feat: read-only MCP server generated from the OpenAPI document - #47
Merged
Conversation
…cument Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
…I verification Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
Rename in the adapter instead of touching src/ (fork kept if FastMCP needs operationId); single PEP 723 script instead of pyproject; one Python test with a method assertion instead of a C# guard; reuse the docs-build job; README as the one doc; client timeout and URL normalisation made explicit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
Also un-ignore /packages/** — the .NET template's NuGet rule was swallowing it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
… server Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
…nges Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Robertzu43 <robertzu43@icloud.com>
There was a problem hiding this comment.
Pull request overview
Adds a locally-run, read-only Model Context Protocol (MCP) server under packages/mcp/ that generates tools from the instance’s /openapi/v1.json, along with documentation/licensing updates and CI coverage to pin the exposed tool surface.
Changes:
- Introduces
packages/mcp/easydocs_mcp.py(PEP 723 script) and a pytest file that asserts the exact tool set and enforces GET-only tools. - Adds end-user setup docs and MIT licensing for
packages/*, and updates repo docs to reflect the newpackages/boundary. - Extends
docs-buildCI to run the MCP package tests and updates.gitignoreto keep/packages/**tracked.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds MCP mention in API section; clarifies AGPL vs MIT boundary for packages/*. |
| packages/mcp/easydocs_mcp.py | New FastMCP server script generated from OpenAPI with allowlisting and tool renaming. |
| packages/mcp/test_easydocs_mcp.py | Pins tool surface to the committed OpenAPI snapshot (exact names + GET-only). |
| packages/mcp/README.md | Installation/config instructions for multiple MCP clients and token handling guidance. |
| packages/mcp/LICENSE | MIT license for the MCP package. |
| docs/superpowers/specs/2026-08-26-mcp-server-design.md | Design spec documenting the approach and constraints. |
| docs/superpowers/plans/2026-08-26-mcp-server.md | Implementation plan describing steps, tests, and CI integration. |
| docs/architecture-decisions.md | Updates ADR-13 to reflect packages/* as the MIT client boundary. |
| docs-site/docs/automation-recipes.md | Links to MCP server as an alternative to raw curl usage. |
| CONTRIBUTING.md | Updates licensing guidance to reflect packages/* MIT boundary. |
| CHANGELOG.md | Adds an unreleased entry for MCP support and packages licensing. |
| .gitignore | Un-ignores repo-root /packages/** while keeping NuGet restore ignores. |
| .github/workflows/ci.yml | Runs MCP pytest in docs-build. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| @@ -0,0 +1,91 @@ | |||
| # /// script | |||
| # requires-python = ">=3.10" | |||
| # dependencies = ["fastmcp>=3.4,<4"] | |||
Comment on lines
177
to
+186
| - name: Install MkDocs Material | ||
| run: pip install mkdocs-material mkdocs-swagger-ui-tag | ||
|
|
||
| # packages/mcp is a Python client of the API, and this job already has Python. Its test pins | ||
| # the read-only tool surface against the committed OpenAPI snapshot (which the .NET job pins | ||
| # against the served document), so a write endpoint cannot leak into the MCP tool set unnoticed. | ||
| - name: Test the MCP server package | ||
| run: | | ||
| pip install "fastmcp>=3.4,<4" pytest | ||
| pytest packages/mcp -q |
Comment on lines
+25
to
+28
| def _tools(): | ||
| spec = json.loads(SNAPSHOT.read_text()) | ||
| server = easydocs_mcp.build(spec, httpx.AsyncClient(base_url="http://example.invalid")) | ||
| return asyncio.run(server.list_tools()) |
Comment on lines
+43
to
+55
| READ_TAGS = ["Documents", "Folders", "Audit", "Members", "Approvals", "Publishing", "Merging", "Copies"] | ||
|
|
||
| # Evaluated in order, first match wins. The trailing catch-all is the point: a new endpoint is | ||
| # excluded until someone adds it here on purpose. | ||
| ROUTE_MAPS = [ | ||
| # Binary docx/pdf — useless to a model and large. Carries the Documents tag, so it must go first. | ||
| RouteMap(methods=["GET"], pattern=r"^/api/v1/versions/\{vid\}/download$", mcp_type=MCPType.EXCLUDE), | ||
| *[RouteMap(methods=["GET"], tags={t}, mcp_type=MCPType.TOOL) for t in READ_TAGS], | ||
| RouteMap(methods=["GET"], pattern=r"^/api/v1/(me|org|orgs)$", mcp_type=MCPType.TOOL), | ||
| # Everything else: all writes, Auth/MFA/SSO/Tokens, Sharing, Editing, the SSE stream, WOPI, | ||
| # WebDAV, /s/, /health, and GET /api/v1/org/members. | ||
| RouteMap(pattern=r".*", mcp_type=MCPType.EXCLUDE), | ||
| ] |
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
packages/mcp/easydocs_mcp.py— a read-only MCP server for Claude Code, Cursor, Codex, Gemini CLI and Claude Desktop. One PEP 723 script: it fetches the install's own/openapi/v1.jsonand, via FastMCP'sfrom_openapi, exposes 17 GET endpoints as named tools (list_documents,list_versions,compare_versions,list_audit_events,list_my_approvals, …). An orderedroute_mapsallowlist with a deny-all catch-all means every write, auth, WOPI, WebDAV, share and SSE route is excluded, and a new endpoint is excluded by default.ed_token, soDocumentAuthorizationapplies untouched. Zero changes tosrc/. Read-only is a property of the tool set, not the token — the README says so plainly.packages/*now exists and is MIT, as README/CONTRIBUTING/ADR-13 always said it would be; their "does not exist yet" wording is flipped. The .NET template's NuGetpackages/ignore rule is negated for/packages/**.GET. Runs in the existingdocs-buildCI job.Design:
docs/superpowers/specs/2026-08-26-mcp-server-design.md· Plan:docs/superpowers/plans/2026-08-26-mcp-server.md. Follow-ups deliberately out of scope (aversions/{vid}/textendpoint, opt-in write tools, a hosted/mcpwith OAuth) are listed in the spec.Test plan
uv run --with "fastmcp>=3.4,<4" --with pytest pytest packages/mcp -q→ 2 passedmkdocs build --strict→ exit 0whoamiandlist_documentsreturn API JSON; a missing document surfaces the API'sproblem+jsondetail as a tool errorKeyError: 'EASYDOCS_URL', exit 1docs-buildnow runs the package test)🤖 Generated with Claude Code