docs-index
Read-only MCP server exposing generated docs reports (docs/public/generated-reports/*.json) and content page metadata
MCP
FastMCP
2 deps
mcp/docs-index/server.py
Read-only MCP server exposing generated docs reports (docs/public/generated-reports/*.json) and content page metadata
| Field | Value |
|---|---|
| Name | mcp-docs-index |
| Version | 0.1.0 |
| Python | >=3.13 |
fastmcp>=2wagents
{ "$schema": "https://gofastmcp.com/public/schemas/fastmcp.json/v1.json", "source": { "path": "server.py", "entrypoint": "mcp" }, "environment": { "type": "uv" }}Server Source
Section titled “Server Source”"""MCP server: docs-index.
Read-only access to `wagents docs generate`'s generated maintainer reports(`docs/public/generated-reports/*.json`, mirrored from`docs/src/content/docs/reports/*.mdx`) and lightweight content-pagemetadata. No tool in this server mutates the repository."""
from __future__ import annotations
import jsonfrom typing import Any
from fastmcp import FastMCP
from wagents.docs_reports import REPORT_SPECS, REPORTS_JSON_DIR, iter_content_pages, read_page_frontmatterfrom wagents.mcp_shared.read_only_paths import PathNotAllowedError, read_text_within_allowlist
mcp = FastMCP("Docs Index")
_READ_ONLY = { "readOnlyHint": True, "destructiveHint": False, "idempotentHint": True, "openWorldHint": False,}
_REPORT_SLUGS = {spec.slug for spec in REPORT_SPECS}
@mcp.tool(annotations=_READ_ONLY)def list_reports() -> list[dict[str, str]]: """List every registered maintainer report (slug, title, description).
Reports are regenerated by `wagents docs generate` and are available as both a browsable MDX page (`/reports/<slug>/`) and machine-readable JSON via `get_report`. Use this to discover available slugs before calling `get_report`. """ return [{"slug": spec.slug, "title": spec.title, "description": spec.description} for spec in REPORT_SPECS]
@mcp.tool(annotations=_READ_ONLY)def get_report(slug: str) -> dict[str, Any]: """Return the generated JSON payload for one report.
*slug* must be one of the values returned by `list_reports` (e.g. "docs-dependency-drift", "llms-txt-coverage", "site-graph-insights", "docs-link-check", "docs-graph-snapshot"). Raises if the slug is unknown or the report has not been generated yet — run `uv run wagents docs generate` in the repo if the file is missing. """ if slug not in _REPORT_SLUGS: raise ValueError(f"Unknown report slug={slug!r}. Call list_reports() for valid slugs.") path = REPORTS_JSON_DIR / f"{slug}.json" if not path.exists(): raise FileNotFoundError( f"Report {slug!r} has not been generated yet. Run `uv run wagents docs generate` in the repo." ) return json.loads(path.read_text(encoding="utf-8"))
@mcp.tool(annotations=_READ_ONLY)def list_content_pages(query: str = "") -> list[dict[str, str]]: """List generated docs site content pages (title, description, relative path).
Pass *query* (case-insensitive substring) to filter by relative path, title, or description; leave empty to list every page under `docs/src/content/docs/`. Complements `skill-catalog` / `agent-catalog` for pages outside those two catalogs (reports, harness support, CLI, contributing, etc.). """ needle = query.strip().lower() from wagents import CONTENT_DIR
results = [] for page in iter_content_pages(): fm = read_page_frontmatter(page) rel = str(page.relative_to(CONTENT_DIR)) title = str(fm.get("title", "")) description = str(fm.get("description", "")) haystack = f"{rel} {title} {description}".lower() if needle and needle not in haystack: continue results.append({"path": rel, "title": title, "description": description}) return sorted(results, key=lambda r: r["path"])
@mcp.tool(annotations=_READ_ONLY)def read_content_page(relative_path: str, max_bytes: int = 200_000) -> str: """Return the raw MDX source of a docs content page.
*relative_path* is repo-root-relative, e.g. "docs/src/content/docs/reports/site-graph-insights.mdx". Enforced against the shared MCP read-only allowlist (`wagents.mcp_shared.read_only_paths`); raises `PathNotAllowedError` for anything outside `docs/src/content/docs/` and the other allowlisted repo surfaces. """ try: return read_text_within_allowlist(relative_path, max_bytes=max_bytes) except PathNotAllowedError as exc: raise ValueError(str(exc)) from exc
if __name__ == "__main__": mcp.run()Resources
Section titled “Resources”MCP OverviewBrowse all MCP documentation in this site.
CLI ReferenceScaffold new MCP servers with wagents.
