Add plugin-defined MCP tools#988
Conversation
🦋 Changeset detectedLatest commit: c66be2d The changes in this PR will be included in the next version bump. This PR includes changesets to release 15 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Scope checkThis PR changes 683 lines across 26 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
|
/review |
There was a problem hiding this comment.
Solid implementation overall — capability gating, hex-encoded tool names to avoid plugin-id collisions, admin scope + ADMIN role enforced before dispatch, and good test coverage (capability filter, sandbox-not-loaded guard, scope check, ID collision). The delegation to handlePluginApiRoute is a clean reuse strategy.
Findings are mostly DX/footgun concerns at the definePlugin boundary plus a couple of manifest cross-validation gaps. No correctness or auth bugs that block merge.
Notes:
- Trusted (
definePlugin) plugins skip several validations that sandboxed plugins get frompluginManifestSchema— tool-name shape, route existence, and capability declaration. Silent filtering vs. early errors. getPluginRouteMetafalls back to{ public: false }for any route on an existing sandboxed plugin, so MCP tools pointing at nonexistent sandboxed routes register fine and fail at call time. The catch-all route has the same behavior, so this matches existing semantics — flagging only as DX context.- One coverage gap: no test for
requireRole(ADMIN)rejecting a non-admin user holding anadmin-scoped token (the defense-in-depth branch). - Sandboxed plugin MCP tools have no input schema in
ManifestMcpToolEntry, so they all fall back toz.record(z.string(), z.unknown())— MCP clients lose introspection. Future work, but worth tracking.
|
Review submitted successfully (review ID 4270626524) with 6 line-anchored comments and a summary body. Key findings:
No blocking issues — auth/correctness paths check out. |
ascorbic
left a comment
There was a problem hiding this comment.
Excellent work. One thing that would be good would be if there was a way we could provide a schema for tool inputs so we can validate and describe them. While we can't serialise a Zod schema directly, maybe a JSON schema would work?
Can you include docs in the PR too, as it will also make it easier to review.
Agreed on both. I’ll add docs in this PR, and I’ll look at adding a constrained I’ll keep the JSON Schema subset conservative: object root, No |
|
Done. I added docs for plugin MCP tools and added manifest-side |
What does this PR do?
Adds the approved plugin-defined MCP tool surface from Discussion #850:
mcp:toolsas an opt-in plugin capabilitymcpToolsmetadata to plugin manifests, descriptors, bundle extraction, and runtime plugin wiringADMINrole for plugin MCP tool callsRelated discussion: #850
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain.AI-generated code disclosure
Screenshots / test output
pnpm typecheckpnpm lint(exits 0; reports 39 existing warnings, 0 errors)pnpm testgit diff --checkpnpm --filter emdash test -- tests/integration/mcp/plugin-tools.test.ts tests/unit/plugins/adapt-sandbox-entry.test.ts tests/unit/plugins/manifest-schema.test.ts tests/unit/plugins/define-plugin.test.ts tests/unit/cli/bundle-utils.test.tspnpm --filter @emdash-cms/registry-cli test -- bundle-utils.test.tsAdversarial review was run twice with RepoPrompt agent_run. The first pass found two issues around unloaded sandboxed tools and plugin ID tool-name collisions; both were fixed and the second pass found no blocking issues.