feat(mcp): capability-aware tool listing, instructions, openWorldHint, session tenant binding#73
Open
ABB65 wants to merge 1 commit into
Open
feat(mcp): capability-aware tool listing, instructions, openWorldHint, session tenant binding#73ABB65 wants to merge 1 commit into
ABB65 wants to merge 1 commit into
Conversation
…, session tenant binding Make the MCP surface honest per session and harden multi-tenant HTTP: - Capability-aware registration: createServer consults a new declarative TOOL_REQUIREMENTS map (exported with isToolAvailable from @contentrain/mcp/tools/availability, new subpath export) and skips tools the resolved provider + projectRoot pair can never satisfy, via a CapabilityFilteredMcpServer subclass — zero changes to the 8 register functions. Local stdio/CLI flows keep all 19 tools; remote-provider sessions now list only the 9 remote-safe tools instead of advertising 10 that always failed with a capability error. Input-dependent checks (validate --fix, apply reuse) stay as call-time guards. - instructions: CreateServerOptions.instructions threads the MCP instructions string to clients at initialize; defaults to a new DEFAULT_INSTRUCTIONS (<512 chars, describe-format-first + dry-run-first operating rules); '' omits. - openWorldHint: false on all 19 annotations — tools operate on the configured repository only. - sessionFingerprint on multi-tenant HTTP: fingerprint captured at session creation must match every follow-up request with that Mcp-Session-Id; mismatch answers 404 so the client re-initializes against its own provider. Closes cross-tenant session-id replay. Tests: new tests/server/tool-availability.test.ts (15 cases: local vs remote listing, partial capabilities, requirements sanity, instructions default/override/omit, openWorldHint on wire); cross-tenant replay test in http.test.ts; doctor/submit remote tests updated to the new not-advertised behavior. Full suite green in clean runs (667 tests across all 50 files); skills 85/85 + rules 16/16 parity pass; oxlint 0/0; tsc clean; tsdown build includes the new tools/availability entry.
✅ Deploy Preview for contentrain-ai ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
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
Phase 1 of the MCP Cloud hardening roadmap — the upstream half that makes the MCP surface honest per session and closes the cross-tenant session gap. Minor release (1.8.1 → 1.9.0, changeset included). Studio-side quick wins (validate write-set fix, loopback authToken, webhook brain invalidation, quota) are running in parallel in the Studio repo.
Changes
Capability-aware tool listing (directory-submission prerequisite)
createServernow consults a declarative requirement map —TOOL_REQUIREMENTS+isToolAvailable, exported from the new@contentrain/mcp/tools/availabilitysubpath — and skips registering tools the resolved provider +projectRootpair can never satisfy. Implemented as a smallCapabilityFilteredMcpServersubclass that filtersserver.tool(...)by name, so the 8 register functions are untouched.status,describe,describe_format,model_save,model_delete,content_save,content_delete,content_list,validate) — previously all 19 were listed and 10 always failed withcapability_required.validate --fix,applyreuse) remain call-time guards; all existingcapabilityErrorguards stay as defense in depth.instructionssupportCreateServerOptions.instructionsthreads the MCPinstructionsstring to clients atinitialize. Defaults to a new exportedDEFAULT_INSTRUCTIONS(< 512 chars: describe-format-first, dry-run-first, status-first operating rules); pass''to omit.openWorldHint: falseon all 19 annotationsEvery tool operates on the configured repository only — the one annotation OpenAI's scan checks that was missing.
Session tenant binding (multi-tenant HTTP)
New
sessionFingerprint(req)option onstartHttpMcpServerWith({ resolveProvider }): the fingerprint captured on the session-creating request must match every follow-up request carrying thatMcp-Session-Id; a mismatch answers404 Session not found, which per the Streamable HTTP spec makes the client transparently re-initialize against its own provider. Closes cross-tenant session-id replay (B's valid key + A's session id no longer reaches A's provider once Studio passes a fingerprint).Testing
tests/server/tool-availability.test.ts— 15 cases: local vs remote listing (exact set equality), partial-capability providers, requirements-map sanity, instructions default/override/omit,openWorldHintover the wire.http.test.ts(same-tenant replay 200, cross-tenant 404).doctor/submitremote tests updated to the new not-advertised behavior (unknown-tool error instead of capability payload).pnpm installrewriting node_modules mid-run; all four files pass in isolation and in clean batches). skills 85/85 + rules 16/16 parity, oxlint 0/0,tsc --noEmitclean, tsdown build includes the new entry.Notes for Studio integration
sessionFingerprintby deriving it from the samex-cr-*headersresolveProviderreads.TOOL_REQUIREMENTSis importable for proxy-side reasoning (e.g. scope mapping later in the media phase).docs/packages/mcp.md,docs/guides/embedding-mcp.md,docs/guides/http-transport.md.🤖 Generated with Claude Code