You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(mcp): capability-aware tool listing, server instructions, openWorldHint, session tenant binding
6
+
7
+
**@contentrain/mcp**: the MCP surface now tells the truth about what it can do, per session.
8
+
9
+
-**Capability-aware registration.**`createServer` consults a new declarative requirement map (`TOOL_REQUIREMENTS`, exported from `@contentrain/mcp/tools/availability` together with `isToolAvailable`) and only registers tools the resolved provider + `projectRoot` pair can satisfy. Local stdio/CLI flows keep the full 19-tool surface; remote-provider sessions (Studio MCP Cloud, GitHub/GitLab providers) now list only the remote-safe subset instead of advertising tools that always failed with a capability error. Input-dependent checks (`validate --fix`, `apply` reuse) remain call-time guards.
10
+
-**`instructions` support.**`CreateServerOptions.instructions` threads the MCP `instructions` string to clients at `initialize`. Defaults to a new `DEFAULT_INSTRUCTIONS` (< 512 chars, describes the describe-format-first and dry-run-first operating rules); pass `''` to omit.
11
+
-**`openWorldHint: false`** added to all 19 tool annotations — every tool operates on the configured repository only.
12
+
-**Session tenant binding.** Multi-tenant HTTP mode accepts `sessionFingerprint(req)`: the fingerprint captured at session creation must match on every follow-up request carrying that `Mcp-Session-Id`; a mismatch answers `404 Session not found` so the client re-initializes against its own provider. Closes cross-tenant session-id replay.
The single-provider shape (`{ provider }`) and the resolver shape (`{ resolveProvider }`) are mutually exclusive — pass one or the other.
179
182
183
+
**Session tenant binding.** A session's provider is resolved once, at `initialize`. Without `sessionFingerprint`, any caller that presents a known `Mcp-Session-Id` reaches that session's provider — fine on trusted loopback, not across tenants. Set `sessionFingerprint` to derive a stable tenant identity from each request (e.g. the same headers `resolveProvider` uses); a mismatch answers `404 Session not found`, which per the Streamable HTTP spec makes the client transparently re-initialize its own session.
184
+
180
185
### 4. Programmatic tool calls (no transport at all)
181
186
182
187
If you want to run a Contentrain tool inside your own Node.js process without MCP's JSON-RPC layer:
@@ -234,17 +239,17 @@ This is only needed for remote / reader-based flows. `LocalProvider`'s transacti
234
239
235
240
### `capability_required` is a structured error
236
241
237
-
Tools that need capabilities the active provider doesn't expose return:
242
+
Tools whose requirements can never be met by the session's provider are not registered at all (see [Capability gating](#capability-gating)), so most capability mismatches never reach a handler. The structured error remains for the two input-dependent cases — `validate` with `fix: true` and `apply` in `reuse` mode:
238
243
239
244
```json
240
245
{
241
-
"error": "contentrain_scan requires local filesystem access.",
242
-
"capability_required": "astScan",
246
+
"error": "contentrain_validate requires local filesystem access.",
247
+
"capability_required": "localWorktree",
243
248
"hint": "This tool is unavailable when MCP is driven by a remote provider. Use a LocalProvider or the stdio transport."
244
249
}
245
250
```
246
251
247
-
Treat `capability_required` as a retry signal at the client. Typical fallback: prompt the user to switch to a local checkout, or downgrade the request (e.g. `content_list` with `resolve: true` → `resolve: false`).
252
+
Treat `capability_required` as a retry signal at the client. Typical fallback: prompt the user to switch to a local checkout, or downgrade the request (e.g. `validate` without `fix`).
248
253
249
254
See [Providers & Transports](/guides/providers) for the full capability matrix.
250
255
@@ -258,18 +263,20 @@ Rotate Bearer tokens regularly. MCP does not support per-tool ACLs; a valid toke
258
263
259
264
## Capability gating
260
265
261
-
Each provider advertises a `ProviderCapabilities` manifest. Tools gate on capabilities and reject uniformly when the active provider can't satisfy them.
266
+
Each provider advertises a `ProviderCapabilities` manifest. `createServer` consults it (together with `projectRoot`) at registration time: tools whose requirements can never be met by the session's provider are **not registered**, so `tools/list` only shows what can actually run. The declarative requirement map is exported as `TOOL_REQUIREMENTS` from `@contentrain/mcp/tools/availability`, alongside an `isToolAvailable(name, provider, projectRoot)` helper for embedders that want to reason about the effective surface without spinning up a server.
`init`, `scaffold`, `doctor`, and `bulk` additionally require a local `projectRoot` on disk. Input-dependent checks (`validate --fix`, `apply` reuse) stay as call-time guards and return the structured `capability_required` error above.
279
+
273
280
Read-only tools (`status`, `describe`, `describe_format`, `content_list`, `validate` without `--fix`) work on every provider — they use only the reader surface.
The same pattern works for `createGitLabProvider` with a `GitLabProvider`. Both require their respective optional peers (`@octokit/rest`, `@gitbeaker/rest`).
75
75
76
+
Multi-tenant deployments (`{ resolveProvider }`) should also set `sessionFingerprint` to bind each MCP session to the tenant it was created for — follow-up requests whose fingerprint doesn't match the session's get `404` and the client re-initializes. See the [embedding guide](/guides/embedding-mcp#3a-http--per-request-provider-resolver-multi-tenant) for the full pattern.
77
+
78
+
Note that the tool list is capability-aware: a session backed by a remote provider only advertises the tools it can actually run (no `init`/`scaffold`/`doctor`/`bulk`/`submit`/`merge`/branch lifecycle/normalize tools without a local worktree).
Copy file name to clipboardExpand all lines: docs/packages/mcp.md
+5-1Lines changed: 5 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -55,7 +55,11 @@ Use the local stdio server when the agent should work against a checkout on your
55
55
56
56
## Tool Catalog
57
57
58
-
The MCP server exposes **19 tools** organized by function. Each tool includes [MCP annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) so clients can distinguish safe reads from writes and destructive operations.
58
+
The MCP server exposes **19 tools** organized by function. Each tool includes [MCP annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint: false` — every tool operates on the configured repository only) so clients can distinguish safe reads from writes and destructive operations.
59
+
60
+
::: info Capability-aware listing
61
+
`tools/list` is filtered per session: tools whose requirements (local project root, provider capabilities) cannot be met are not registered at all. A local stdio server lists all 19 tools; a remote-provider session (e.g. Studio MCP Cloud) lists only the remote-safe subset — `status`, `describe`, `describe_format`, `model_save`, `model_delete`, `content_save`, `content_delete`, `content_list`, `validate`. See `TOOL_REQUIREMENTS` in `@contentrain/mcp/tools/availability`.
Copy file name to clipboardExpand all lines: packages/mcp/README.md
+5-1Lines changed: 5 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -71,7 +71,9 @@ All write operations are designed around git-backed safety:
71
71
72
72
## Tool Surface
73
73
74
-
19 MCP tools with [annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) for client safety hints:
74
+
19 MCP tools with [annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint: false` — every tool operates on the configured repository only) for client safety hints.
75
+
76
+
**Tool listing is capability-aware.**`tools/list` only advertises tools the resolved provider + `projectRoot` pair can actually satisfy. A local stdio server lists all 19; a session driven by a remote provider (GitHub/GitLab, no local checkout) lists only the remote-safe subset — `status`, `describe`, `describe_format`, `model_save`, `model_delete`, `content_save`, `content_delete`, `content_list`, `validate`. The requirement map lives in `TOOL_REQUIREMENTS` (`@contentrain/mcp/tools/availability`).
75
77
76
78
| Tool | Purpose | Read-only | Destructive |
77
79
| --- | --- | --- | --- |
@@ -125,6 +127,8 @@ const transport = new StdioServerTransport()
125
127
awaitserver.connect(transport)
126
128
```
127
129
130
+
`createServer` also accepts an options object: `{ provider, projectRoot?, instructions? }`. `instructions` sets the MCP `instructions` string clients receive at `initialize` (defaults to a built-in `DEFAULT_INSTRUCTIONS`, kept under 512 characters; pass `''` to omit).
0 commit comments