Skip to content

feat(mcp): capability-aware tool listing, instructions, openWorldHint, session tenant binding#73

Open
ABB65 wants to merge 1 commit into
mainfrom
feat/mcp-honest-surface
Open

feat(mcp): capability-aware tool listing, instructions, openWorldHint, session tenant binding#73
ABB65 wants to merge 1 commit into
mainfrom
feat/mcp-honest-surface

Conversation

@ABB65

@ABB65 ABB65 commented Jul 12, 2026

Copy link
Copy Markdown
Member

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)

createServer now consults a declarative requirement map — TOOL_REQUIREMENTS + isToolAvailable, exported from the new @contentrain/mcp/tools/availability subpath — and skips registering tools the resolved provider + projectRoot pair can never satisfy. Implemented as a small CapabilityFilteredMcpServer subclass that filters server.tool(...) by name, so the 8 register functions are untouched.

  • Local stdio/CLI flows: all 19 tools, behavior unchanged.
  • Remote-provider sessions (Studio MCP Cloud, GitHub/GitLab): exactly the 9 remote-safe tools (status, describe, describe_format, model_save, model_delete, content_save, content_delete, content_list, validate) — previously all 19 were listed and 10 always failed with capability_required.
  • Input-dependent gates (validate --fix, apply reuse) remain call-time guards; all existing capabilityError guards stay as defense in depth.

instructions support

CreateServerOptions.instructions threads the MCP instructions string to clients at initialize. Defaults to a new exported DEFAULT_INSTRUCTIONS (< 512 chars: describe-format-first, dry-run-first, status-first operating rules); pass '' to omit.

openWorldHint: false on all 19 annotations

Every 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 on startHttpMcpServerWith({ resolveProvider }): the fingerprint captured on the session-creating request must match every follow-up request carrying that Mcp-Session-Id; a mismatch answers 404 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

  • New 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, openWorldHint over the wire.
  • New cross-tenant session-replay test in http.test.ts (same-tenant replay 200, cross-tenant 404).
  • doctor/submit remote tests updated to the new not-advertised behavior (unknown-tool error instead of capability payload).
  • Full suite green in clean runs: 667 tests across all 50 files (an initial run showed 4 failures caused by a concurrent pnpm install rewriting 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 --noEmit clean, tsdown build includes the new entry.

Notes for Studio integration

  • Proxy can adopt sessionFingerprint by deriving it from the same x-cr-* headers resolveProvider reads.
  • TOOL_REQUIREMENTS is importable for proxy-side reasoning (e.g. scope mapping later in the media phase).
  • Docs updated: package README, docs/packages/mcp.md, docs/guides/embedding-mcp.md, docs/guides/http-transport.md.

🤖 Generated with Claude Code

…, 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.
@netlify

netlify Bot commented Jul 12, 2026

Copy link
Copy Markdown

Deploy Preview for contentrain-ai ready!

Name Link
🔨 Latest commit 1387ce1
🔍 Latest deploy log https://app.netlify.com/projects/contentrain-ai/deploys/6a541c85ec4f50000896689c
😎 Deploy Preview https://deploy-preview-73--contentrain-ai.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant