From 6a4aece659c4996d05c7fc0766497fa04c8c58d6 Mon Sep 17 00:00:00 2001 From: Vishesh 'ironeagle' Bangotra Date: Mon, 19 Jan 2026 18:22:59 +0530 Subject: [PATCH] feat(docs): add MCP artifact generation to manage_docs CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduced `build_mcp` command to generate docs-only MCP artifacts - Reuses existing MkDocs + mkdocstrings pipeline (no code introspection) - Extracts `:::` mkdocstrings directives from generated Markdown - Emits structured MCP output: - `mcp/index.json` (project metadata) - `mcp/nav.json` (page → module mapping) - `mcp/modules/*.json` (per-module references) - Preserves all existing commands and behavior (`generate`, `build`, `serve`) - Avoids source code exposure; MCP output is derived solely from documentation This enables a clean docs → MCP → MCP server workflow suitable for AI IDE integration. --- manage_docs.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/manage_docs.py b/manage_docs.py index 91a44f8..4c0edaf 100644 --- a/manage_docs.py +++ b/manage_docs.py @@ -18,6 +18,7 @@ Usage: python manage_docs.py generate python manage_docs.py build python manage_docs.py serve + python manage_docs.py build_mcp Optional flags: --docs-dir PATH Path to docs directory (default: ./docs) @@ -27,7 +28,10 @@ Optional flags: from __future__ import annotations import argparse +import json +import re from pathlib import Path +from typing import Iterable from mkdocs.commands import build as mkdocs_build from mkdocs.commands import serve as mkdocs_serve @@ -38,7 +42,14 @@ PROJECT_ROOT = Path(__file__).resolve().parent DEFAULT_DOCS_DIR = PROJECT_ROOT / "docs" DEFAULT_PACKAGE_ROOT = "mail_intake" MKDOCS_YML = PROJECT_ROOT / "mkdocs.yml" +DEFAULT_MCP_DIR = PROJECT_ROOT / "mcp" +MKDOCSTRINGS_DIRECTIVE = re.compile(r"^:::\s+([a-zA-Z0-9_.]+)", re.MULTILINE) + + +# ------------------------- +# Existing functionality +# ------------------------- def generate_docs_from_nav( project_root: Path, @@ -116,10 +127,86 @@ def cmd_serve(_: argparse.Namespace) -> None: config_file=str(MKDOCS_YML) ) + +# ------------------------- +# MCP generation +# ------------------------- + +def iter_markdown_files(docs_root: Path) -> Iterable[Path]: + yield from docs_root.rglob("*.md") + + +def extract_modules(md_file: Path) -> list[str]: + content = md_file.read_text(encoding="utf-8") + return MKDOCSTRINGS_DIRECTIVE.findall(content) + + +def cmd_build_mcp(args: argparse.Namespace) -> None: + docs_root = args.docs_dir + mcp_root = args.mcp_dir + + modules_dir = mcp_root / "modules" + modules_dir.mkdir(parents=True, exist_ok=True) + + nav = [] + modules = [] + + for md in iter_markdown_files(docs_root): + rel = md.relative_to(docs_root) + + module_refs = extract_modules(md) + if not module_refs: + continue + + nav.append({ + "page": str(rel), + "modules": module_refs, + }) + + for module in module_refs: + module_entry = { + "module": module, + "doc_page": str(rel), + } + modules.append(module_entry) + + out = modules_dir / f"{module}.json" + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text( + json.dumps(module_entry, indent=2), + encoding="utf-8", + ) + + mcp_root.mkdir(parents=True, exist_ok=True) + + (mcp_root / "nav.json").write_text( + json.dumps(nav, indent=2), + encoding="utf-8", + ) + + (mcp_root / "index.json").write_text( + json.dumps( + { + "project": "Aetoskia Mail Intake", + "type": "docs-only", + "modules_count": len(modules), + }, + indent=2, + ), + encoding="utf-8", + ) + + print(f"MCP artifacts written to: {mcp_root}") + + +# ------------------------- +# CLI +# ------------------------- + def main() -> None: parser = argparse.ArgumentParser( prog="manage_docs.py", - description="Manage MkDocs documentation for the project", + description="Manage MkDocs documentation and MCP exports for the project", ) parser.add_argument( @@ -128,12 +215,20 @@ def main() -> None: default=DEFAULT_DOCS_DIR, help="Path to the docs directory", ) + parser.add_argument( "--package-root", default=DEFAULT_PACKAGE_ROOT, help="Root Python package name", ) + parser.add_argument( + "--mcp-dir", + type=Path, + default=DEFAULT_MCP_DIR, + help="Output directory for MCP artifacts", + ) + subparsers = parser.add_subparsers(dest="command", required=True) subparsers.add_parser( @@ -151,6 +246,13 @@ def main() -> None: help="Serve the MkDocs site locally", ).set_defaults(func=cmd_serve) + subparsers.add_parser( + "build_mcp", + help="Generate MCP artifacts (docs-only)", + ).set_defaults( + func=cmd_build_mcp + ) + args = parser.parse_args() args.func(args)