@ts-pf/mcp 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -51,7 +51,16 @@ export type McpToolResult = {
51
51
  };
52
52
  /** A bound toolset: list and call tools without a transport (tests, agent frameworks, `./sdk`). */
53
53
  export interface McpTools {
54
+ /** The tools this caller may see (`.visible()` filters per caller). */
54
55
  list(info?: McpCallInfo): Promise<McpToolDefinition[]>;
56
+ /** A tool hidden from this caller answers like an unknown tool. */
55
57
  call(name: string, args: unknown, info?: McpCallInfo): Promise<McpToolResult>;
58
+ /**
59
+ * OAuth scopes a call to `name` with `args` needs (`.scopes()`; for a host's
60
+ * `call_*`, the named inner tool's). Empty for a tool or inner tool hidden
61
+ * from this caller. With `./sdk` and a verified token, a missing one is a
62
+ * `403 insufficient_scope` step-up over HTTP. Optional for hand-written tools.
63
+ */
64
+ scopesFor?(name: string, args: unknown, info?: McpCallInfo): Promise<readonly string[]>;
56
65
  }
57
66
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAEvC,iEAAiE;AACjE,MAAM,MAAM,WAAW,GAAG;IACxB,iFAAiF;IACjF,QAAQ,CAAC,EAAE;QACT,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,EAAE,CAAA;QAChB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,QAAQ,CAAC,EAAE,GAAG,CAAA;QACd,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAChC,CAAA;IACD,sFAAsF;IACtF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACxC,+DAA+D;IAC/D,GAAG,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACzB;;;;OAIG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACtC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,UAAU,CAAA;IACvB,oFAAoF;IACpF,YAAY,CAAC,EAAE,UAAU,CAAA;IACzB,WAAW,EAAE,kBAAkB,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,IAAI,CAAA;CACf,CAAA;AAED,mGAAmG;AACnG,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAA;IACtD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;CAC9E"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAEvC,iEAAiE;AACjE,MAAM,MAAM,WAAW,GAAG;IACxB,iFAAiF;IACjF,QAAQ,CAAC,EAAE;QACT,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,EAAE,CAAA;QAChB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,QAAQ,CAAC,EAAE,GAAG,CAAA;QACd,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAChC,CAAA;IACD,sFAAsF;IACtF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACxC,+DAA+D;IAC/D,GAAG,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACzB;;;;OAIG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACtC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,UAAU,CAAA;IACvB,oFAAoF;IACpF,YAAY,CAAC,EAAE,UAAU,CAAA;IACzB,WAAW,EAAE,kBAAkB,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,IAAI,CAAA;CACf,CAAA;AAED,mGAAmG;AACnG,MAAM,WAAW,QAAQ;IACvB,uEAAuE;IACvE,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAA;IACtD,mEAAmE;IACnE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;IAC7E;;;;;OAKG;IACH,SAAS,CAAC,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;CAC9B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ts-pf/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Opt-in typed projection of a ts-pf contract into MCP tools",
5
5
  "keywords": [
6
6
  "ts-pf",
@@ -61,12 +61,12 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@ts-pf/contract": "0.2.1",
64
- "@ts-pf/docs": "0.1.8",
64
+ "@ts-pf/docs": "0.1.9",
65
65
  "@ts-pf/protocol": "0.2.0",
66
66
  "@ts-pf/server": "0.4.1"
67
67
  },
68
68
  "peerDependencies": {
69
- "@modelcontextprotocol/server": ">=2.4.0 <3"
69
+ "@modelcontextprotocol/server": ">=2.3.0 <3"
70
70
  },
71
71
  "peerDependenciesMeta": {
72
72
  "@modelcontextprotocol/server": {
@@ -74,9 +74,11 @@
74
74
  }
75
75
  },
76
76
  "devDependencies": {
77
- "@modelcontextprotocol/client": "^2.4.0",
78
- "@modelcontextprotocol/server": "^2.4.0",
77
+ "@modelcontextprotocol/client": "^2.3.0",
78
+ "@modelcontextprotocol/server": "^2.3.0",
79
79
  "@ts-pf/client": "0.2.1",
80
+ "@ts-pf/client-http": "0.2.1",
81
+ "@ts-pf/server-http": "0.3.1",
80
82
  "zod": "^4.0.0"
81
83
  }
82
84
  }
@@ -7,7 +7,7 @@ description: Use when exposing a ts-pf contract as MCP tools for LLM clients —
7
7
 
8
8
  A typed projection of a ts-pf contract into MCP tools. The contract defines the tools; an executor (`{ app, context }` in-process through `runProcedure`, or `{ client }`) runs them; `@modelcontextprotocol/server` v2 serves them.
9
9
 
10
- Install: `npm i @ts-pf/mcp @modelcontextprotocol/server` (peer **>=2.4.0 <3**, needed for `./sdk` only). The app already has `@ts-pf/contract` and `@ts-pf/server`; add `@ts-pf/docs` to import `docs()` in contract files.
10
+ Install: `npm i @ts-pf/mcp @modelcontextprotocol/server` (peer **>=2.3.0 <3**, needed for `./sdk` only; keep a single copy in the app). The app already has `@ts-pf/contract` and `@ts-pf/server`; add `@ts-pf/docs` to import `docs()` in contract files.
11
11
 
12
12
  Link for agents: `npx skills experimental_sync -y`
13
13
 
@@ -60,12 +60,15 @@ export const factory = createMcpFactory(tools, { name: 'planets', version: '1.0.
60
60
  - `.inject({ tenantId: ({ context }) => context.tenantId })` removes the key from the model's schema and fills it per call (also forced safe defaults: `.inject({ includePii: () => false })`). Injected values win over anything the model sends. `all(node, { inject })` applies a key only where the input has it; a typo or a conflicting field type is a compile error naming the path.
61
61
  - `.input(schema, map)` replaces the model input; it is exclusive with `.inject` (inject inside the map).
62
62
  - `.output(map)` reshapes; `.output(schema, map)` also advertises `outputSchema`, returns `structuredContent`, and checks the result (a mismatch is `INTERNAL`). Mapper `call` is a typed client on the same executor, for joins. Literal unions in a mapper return need `as const`.
63
+ - `all(node, { tags: ['billing'] })` and `docs({ hidden: true })` filter in the types when the contract writes them as literals; a widened `string[]` keeps the tool in the type (runtime `$coverage` still checks).
63
64
  - `.errors({ CODE: ({ data }) => 'next step' })` for declared codes only. `VALIDATION` returns the issues plus the model-facing schema. Unknown throws are `INTERNAL: Internal server error` (via `toWireError`) and logged with `console.error` unless `onError` is set.
64
65
  - More than about 15 tools in a group: `tk.$host({ description, tools: all(tk.admin) })`. `split: 'effect'` (default) gives `get_admin_query_capabilities` / `call_admin_query_capability` (read) and `get_admin_operations_capabilities` / `call_admin_operations_capability` (write + destructive); `split: false` gives `get_admin_capabilities` / `call_admin_capability`. Pin hot tools flat beside the host. Whole-server discovery is one host over `all(tk)`.
65
- - `tk.$coverage({ toolsets, exclude })` is a compile error (and a runtime throw) naming every procedure no toolset exposes and no `exclude` names. Hosts count; `$tool` composites do not; `docs({ hidden: true })` counts as decided at runtime.
66
+ - `tk.$coverage({ toolsets, exclude })` is a compile error (and a runtime throw) naming every procedure no toolset exposes and no `exclude` names. Hosts count; `$tool` composites do not; `docs({ hidden: true })` counts as decided at runtime (and in types when written literally).
66
67
  - `audit(toolsets)` in CI: missing descriptions (error), unclassified tools, schema roots (unions, recursion, non-object), more than 15 tools, names over 60 characters.
67
68
  - Identity comes from `info.authInfo` (HTTP: your verified token passed to `createMcpHandler(factory).fetch(req, { authInfo })`). stdio never sets it: `serveStdio((ctx) => factory({ ...ctx, authInfo }))`, with `serveStdio` from `@modelcontextprotocol/server/stdio`. Enforce roles in procedure middleware; annotations and `docs({ hidden: true })` are hints, not security.
68
- - OAuth over HTTP: check the token in the SDK at the HTTP edge, so a missing or bad token is a `401` challenge and the client can start sign-in. Map claims to the app's context in `context`. A gateway calling upstream as the user uses `client: (info) => createClient(…)`. Full verifier and metadata setup: the package README, "OAuth".
69
+ - OAuth over HTTP: check the token in the SDK at the HTTP edge, so a missing or bad token is a `401` challenge and the client can start sign-in. Map claims to the app's context in `context`. A gateway calling upstream as the user uses `client: (info) => createClient(…)` (built once per tool call, shared with mapper `call`). Full verifier and metadata setup: the package README, "OAuth".
70
+ - Per-caller lists: `.visible((info) => boolean)` on a tool, `all(node, { visible })`, `$tool({ visible })`, `$host({ visible })`. The predicate gets `McpCallInfo` (not `context`); a hidden tool is left out of `tools/list` and a call to it answers like an unknown tool; host discovery, the `get_*` description, the `call_*` enum and annotations follow the caller's visible set.
71
+ - Scope step-up: `.scopes(['admin'])` (also `all` / `$tool`). Over HTTP a token missing one gets `403 insufficient_scope` (granted ∪ required scopes) before the call runs, and the client re-consents; a host's `call_*` challenges per inner tool (never one hidden from the caller). Toolkit only: `createMcpFactory(app, …)` declares no scopes. A non-OAuth scope string throws a `TypeError` at build time. No token, stdio, and `tools.call()` never challenge, so middleware still enforces. Hide a tool or step up into it, not both.
69
72
 
70
73
  ```ts
71
74
  import { createMcpHandler, getOAuthProtectedResourceMetadataUrl, type OAuthMetadata, type OAuthTokenVerifier, oauthMetadataResponse, requireBearerAuth } from '@modelcontextprotocol/server'
@@ -111,7 +114,7 @@ export async function fetchHandler(request: Request): Promise<Response> {
111
114
  - `bindTools` — `{ app, context, interceptors?, onError?, maxResultChars? }` or `{ client, context?, onError?, maxResultChars? }` (`context` required when the toolkit's context type has required keys)
112
115
  - `audit` — `(toolsets, { maxTools? = 15, maxNameLength? = 60, missingDescription? = 'error' })` → `{ level, tool, message }[]`
113
116
  - `createMcpFactory` (`@ts-pf/mcp/sdk`) — `(app, { name, version, instructions?, listTtlMs?, context, interceptors?, onError?, maxResultChars? })` (`context` optional for an unbranded app) or `(tools, { name, version, instructions?, listTtlMs? })`
114
- - `McpTools`
117
+ - `McpTools` — `{ list(info?), call(name, args, info?), scopesFor?(name, args, info?) }` (`scopesFor` async)
115
118
  - `McpCallInfo` — `{ authInfo?, requestInfo?, signal?, inputResponses?, era?, tool? }`; `tool` is `{ name, path }` of the tool being called (the inner tool for a host call)
116
119
  - `McpToolDefinition`
117
120
  - `McpToolResult`
@@ -131,4 +134,5 @@ export async function fetchHandler(request: Request): Promise<Response> {
131
134
  - Name contract keys starting with `$` (reserved for toolkit root members).
132
135
  - Forward `Authorization` / `Cookie` headers into context; use `info.authInfo`.
133
136
  - Expect interceptors to see the tool name; they see the procedure path. Copy `info.tool` into your context type in `context: (info) => …` if you trace tools.
134
- - Switch to hosts automatically by tool count, or add resources / prompts, `.visible()`, `confirm`, `.title()`, `.text()`, or custom host name templates (later versions).
137
+ - Treat `.visible()` or `.scopes()` as access control; procedure middleware is the boundary.
138
+ - Switch to hosts automatically by tool count, or add resources / prompts, `confirm`, `.title()`, `.text()`, or custom host name templates (later versions).