@george43g/mcp-kit 1.0.0 → 3.0.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/README.md +189 -2
- package/dist/dispatch.d.ts +10 -2
- package/dist/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +9 -3
- package/dist/dispatch.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +89 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +230 -0
- package/dist/testing.js.map +1 -0
- package/dist/tool-registry.d.ts +111 -7
- package/dist/tool-registry.d.ts.map +1 -1
- package/dist/tool-registry.js +78 -17
- package/dist/tool-registry.js.map +1 -1
- package/package.json +16 -5
- package/src/dispatch.ts +24 -5
- package/src/index.ts +7 -1
- package/src/testing.ts +303 -0
- package/src/tool-registry.ts +177 -25
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
|
package/dist/tool-registry.d.ts
CHANGED
|
@@ -7,10 +7,13 @@
|
|
|
7
7
|
* - the ToolDefinition (registration metadata)
|
|
8
8
|
*
|
|
9
9
|
* The registry collects ToolDefinitions and converts them to the SDK's
|
|
10
|
-
* `Tool[]` shape via `toMcpTools()`.
|
|
10
|
+
* `Tool[]` shape via `toMcpTools()`. Both wire schemas are DERIVED from the one
|
|
11
|
+
* Zod definition per tool by `toMcpSchema()`; there is no hand-written JSON
|
|
12
|
+
* Schema path, so the wire contract cannot drift from the validator.
|
|
11
13
|
*/
|
|
12
|
-
import type {
|
|
13
|
-
import type {
|
|
14
|
+
import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
|
|
15
|
+
import type { RequestInfo, Tool, ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
|
|
16
|
+
import { z } from "zod";
|
|
14
17
|
/**
|
|
15
18
|
* A single MCP content block a tool may emit.
|
|
16
19
|
*
|
|
@@ -33,7 +36,15 @@ export type ContentBlock = {
|
|
|
33
36
|
data: string;
|
|
34
37
|
mimeType: string;
|
|
35
38
|
};
|
|
36
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Any Zod schema, inferring `any` — the default for an unparameterised
|
|
41
|
+
* `ToolDefinition`, so a handler written against it is not forced to narrow
|
|
42
|
+
* `unknown`. This is what `ZodTypeAny` meant under Zod 3; Zod 4's `ZodTypeAny`
|
|
43
|
+
* (a deprecated compat alias) infers `unknown`, which would have made every
|
|
44
|
+
* bare `ToolDefinition` handler a type error on upgrade.
|
|
45
|
+
*/
|
|
46
|
+
export type AnyZodSchema = z.ZodType<any, any>;
|
|
47
|
+
export interface ToolDefinition<TInput extends z.ZodType = AnyZodSchema, TOutput extends z.ZodType = AnyZodSchema> {
|
|
37
48
|
/** Snake_case tool name, e.g. "health_check". */
|
|
38
49
|
name: string;
|
|
39
50
|
/** One-paragraph description shown to the LLM. */
|
|
@@ -68,11 +79,104 @@ export interface ToolDefinition<TInput extends ZodTypeAny = ZodTypeAny, TOutput
|
|
|
68
79
|
toContent?: (result: z.infer<TOutput>) => ContentBlock[];
|
|
69
80
|
}
|
|
70
81
|
export type AnyToolDefinition = ToolDefinition<any, any>;
|
|
82
|
+
/**
|
|
83
|
+
* What a tool filter is told about the request it is answering.
|
|
84
|
+
*
|
|
85
|
+
* A structural subset of the SDK's `RequestHandlerExtra` — the second argument
|
|
86
|
+
* every `server.setRequestHandler` callback receives — so a handler can pass
|
|
87
|
+
* its `extra` straight through: `registry.toMcpTools(dev, extra)` and
|
|
88
|
+
* `dispatch(name, args, extra.signal, extra)`.
|
|
89
|
+
*
|
|
90
|
+
* Every field is optional because most calls carry none of them: stdio has no
|
|
91
|
+
* auth, and an in-process caller (a CLI, a REPL, a test) has no request at all.
|
|
92
|
+
* A filter that gates on scopes therefore sees `authInfo === undefined` there,
|
|
93
|
+
* and should decide deliberately what that means for its tools.
|
|
94
|
+
*/
|
|
95
|
+
export interface ToolFilterContext {
|
|
96
|
+
/** Validated access token, when the transport authenticated the request (HTTP + OAuth). */
|
|
97
|
+
authInfo?: AuthInfo;
|
|
98
|
+
/** Transport session id, when the transport has sessions. */
|
|
99
|
+
sessionId?: string;
|
|
100
|
+
/** The originating HTTP request's headers, when there was one. */
|
|
101
|
+
requestInfo?: RequestInfo;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Per-request tool gate: return `false` to hide a tool from `tools/list` AND
|
|
105
|
+
* refuse calls to it.
|
|
106
|
+
*
|
|
107
|
+
* Synchronous on purpose: it runs inside `toMcpTools()`, which is synchronous,
|
|
108
|
+
* and a scope check is a set lookup. Resolve anything slow (a token
|
|
109
|
+
* introspection) before the request reaches the registry — the HTTP transport's
|
|
110
|
+
* auth layer is where that belongs.
|
|
111
|
+
*
|
|
112
|
+
* A filter that THROWS is treated as `false` (fail closed): a bug in the gate
|
|
113
|
+
* must not expose the tool it was written to protect.
|
|
114
|
+
*/
|
|
115
|
+
export type ToolFilter<TDef extends AnyToolDefinition = AnyToolDefinition> = (tool: TDef, ctx: ToolFilterContext) => boolean;
|
|
116
|
+
/**
|
|
117
|
+
* `TDef` lets a consumer carry its own per-tool metadata into the filter
|
|
118
|
+
* without a cast: declare `interface ScopedTool extends ToolDefinition { scopes:
|
|
119
|
+
* string[] }`, pass `ScopedTool[]`, and the filter receives `ScopedTool`.
|
|
120
|
+
*
|
|
121
|
+
* The filter is called on EVERY `toMcpTools()` / dispatch — never cached — so a
|
|
122
|
+
* predicate that reads live state (scopes granted by a re-auth a minute ago)
|
|
123
|
+
* sees the current value. Read that state inside the predicate.
|
|
124
|
+
*/
|
|
125
|
+
export interface MakeRegistryOptions<TDef extends AnyToolDefinition = AnyToolDefinition> {
|
|
126
|
+
/**
|
|
127
|
+
* Optional per-request gate, applied by BOTH `toMcpTools()` and the
|
|
128
|
+
* dispatcher. It lives on the registry rather than on either consumer so the
|
|
129
|
+
* listing and the call path cannot disagree: a filter that only hid a tool
|
|
130
|
+
* from `tools/list` would leave it callable by name (see `devOnly`).
|
|
131
|
+
*/
|
|
132
|
+
filter?: ToolFilter<TDef>;
|
|
133
|
+
}
|
|
71
134
|
export interface ToolRegistry {
|
|
72
135
|
readonly tools: readonly AnyToolDefinition[];
|
|
73
136
|
get(name: string): AnyToolDefinition | undefined;
|
|
74
|
-
/**
|
|
75
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Whether `def` passes the registry's filter for this request. Always `true`
|
|
139
|
+
* when no filter was configured; `false` when the filter throws.
|
|
140
|
+
*/
|
|
141
|
+
allows(def: AnyToolDefinition, ctx?: ToolFilterContext): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Convert tools to MCP SDK shape: devOnly tools only when `includeDevOnly`,
|
|
144
|
+
* and only tools the filter allows for `ctx`. Schemas are converted once, at
|
|
145
|
+
* `makeRegistry()`, so a call here never throws for a schema problem.
|
|
146
|
+
*/
|
|
147
|
+
toMcpTools(includeDevOnly?: boolean, ctx?: ToolFilterContext): Tool[];
|
|
76
148
|
}
|
|
77
|
-
|
|
149
|
+
/** Which side of a Zod schema to describe: what a caller sends, or what parsing yields. */
|
|
150
|
+
export type McpSchemaIo = "input" | "output";
|
|
151
|
+
/** A JSON Schema object as emitted by `toMcpSchema`: always `type: "object"` at the top. */
|
|
152
|
+
export type McpJsonSchema = {
|
|
153
|
+
type: "object";
|
|
154
|
+
[key: string]: unknown;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Convert a Zod schema to the JSON Schema an MCP client accepts as a tool's
|
|
158
|
+
* `inputSchema` / `outputSchema`.
|
|
159
|
+
*
|
|
160
|
+
* - **Dialect: JSON Schema 2020-12**, the MCP default. Draft-07 output (what
|
|
161
|
+
* `zod-to-json-schema` emitted, and what mcp-kit 2.x shipped) is rejected
|
|
162
|
+
* outright by clients that only load the 2020-12 meta-schema — Claude Code
|
|
163
|
+
* 2.1.292 throws on `"$schema": "http://json-schema.org/draft-07/schema#"`.
|
|
164
|
+
* - **`$schema` is stripped.** 2020-12 is the dialect a schema without a label
|
|
165
|
+
* is read as under MCP, and a schema with no label gives no client a dialect
|
|
166
|
+
* to refuse.
|
|
167
|
+
* - **`io` matters.** `"input"` describes what a caller may send (a field with
|
|
168
|
+
* a `.default()` is optional); `"output"` describes what parsing yields (the
|
|
169
|
+
* same field is required, and objects are closed with
|
|
170
|
+
* `additionalProperties: false`).
|
|
171
|
+
* - **Shared sub-schemas are inlined** (`reused: "inline"`). **Cycles are not
|
|
172
|
+
* inlinable**, so a recursive schema still carries `$defs` / `$ref` (or a
|
|
173
|
+
* root `$ref: "#"`). That is valid 2020-12 and kept as is.
|
|
174
|
+
* - **Unrepresentable types throw**: `z.date()`, `z.bigint()`, a transform on
|
|
175
|
+
* the output side, and so on. The error names the tool, so a registry with a
|
|
176
|
+
* bad schema fails at startup rather than at a client's first `tools/list`.
|
|
177
|
+
* - **The top level must be an object.** MCP requires `type: "object"` for both
|
|
178
|
+
* schemas; anything else throws, naming the tool.
|
|
179
|
+
*/
|
|
180
|
+
export declare function toMcpSchema(schema: z.ZodType, io: McpSchemaIo, toolName?: string): McpJsonSchema;
|
|
181
|
+
export declare function makeRegistry<TDef extends AnyToolDefinition = AnyToolDefinition>(defs: TDef[], opts?: MakeRegistryOptions<TDef>): ToolRegistry;
|
|
78
182
|
//# sourceMappingURL=tool-registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../src/tool-registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../src/tool-registry.ts"],"names":[],"mappings":"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"}
|
package/dist/tool-registry.js
CHANGED
|
@@ -7,31 +7,92 @@
|
|
|
7
7
|
* - the ToolDefinition (registration metadata)
|
|
8
8
|
*
|
|
9
9
|
* The registry collects ToolDefinitions and converts them to the SDK's
|
|
10
|
-
* `Tool[]` shape via `toMcpTools()`.
|
|
10
|
+
* `Tool[]` shape via `toMcpTools()`. Both wire schemas are DERIVED from the one
|
|
11
|
+
* Zod definition per tool by `toMcpSchema()`; there is no hand-written JSON
|
|
12
|
+
* Schema path, so the wire contract cannot drift from the validator.
|
|
11
13
|
*/
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
/**
|
|
16
|
+
* Convert a Zod schema to the JSON Schema an MCP client accepts as a tool's
|
|
17
|
+
* `inputSchema` / `outputSchema`.
|
|
18
|
+
*
|
|
19
|
+
* - **Dialect: JSON Schema 2020-12**, the MCP default. Draft-07 output (what
|
|
20
|
+
* `zod-to-json-schema` emitted, and what mcp-kit 2.x shipped) is rejected
|
|
21
|
+
* outright by clients that only load the 2020-12 meta-schema — Claude Code
|
|
22
|
+
* 2.1.292 throws on `"$schema": "http://json-schema.org/draft-07/schema#"`.
|
|
23
|
+
* - **`$schema` is stripped.** 2020-12 is the dialect a schema without a label
|
|
24
|
+
* is read as under MCP, and a schema with no label gives no client a dialect
|
|
25
|
+
* to refuse.
|
|
26
|
+
* - **`io` matters.** `"input"` describes what a caller may send (a field with
|
|
27
|
+
* a `.default()` is optional); `"output"` describes what parsing yields (the
|
|
28
|
+
* same field is required, and objects are closed with
|
|
29
|
+
* `additionalProperties: false`).
|
|
30
|
+
* - **Shared sub-schemas are inlined** (`reused: "inline"`). **Cycles are not
|
|
31
|
+
* inlinable**, so a recursive schema still carries `$defs` / `$ref` (or a
|
|
32
|
+
* root `$ref: "#"`). That is valid 2020-12 and kept as is.
|
|
33
|
+
* - **Unrepresentable types throw**: `z.date()`, `z.bigint()`, a transform on
|
|
34
|
+
* the output side, and so on. The error names the tool, so a registry with a
|
|
35
|
+
* bad schema fails at startup rather than at a client's first `tools/list`.
|
|
36
|
+
* - **The top level must be an object.** MCP requires `type: "object"` for both
|
|
37
|
+
* schemas; anything else throws, naming the tool.
|
|
38
|
+
*/
|
|
39
|
+
export function toMcpSchema(schema, io, toolName) {
|
|
40
|
+
const where = toolName === undefined ? `${io} schema` : `tool "${toolName}" ${io} schema`;
|
|
41
|
+
let json;
|
|
42
|
+
try {
|
|
43
|
+
json = z.toJSONSchema(schema, { target: "draft-2020-12", io, reused: "inline" });
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
throw new Error(`toMcpSchema: ${where} cannot be represented in JSON Schema: ${err?.message ?? String(err)}. ` +
|
|
47
|
+
"Use a JSON-representable type (an ISO string instead of z.date(), a number or string instead of z.bigint()), " +
|
|
48
|
+
"or move the transform out of the schema.", { cause: err });
|
|
49
|
+
}
|
|
50
|
+
delete json.$schema;
|
|
51
|
+
if (json.type !== "object") {
|
|
52
|
+
throw new Error(`toMcpSchema: ${where} must be a Zod object (JSON Schema type "object"), got ${JSON.stringify(json.type ?? null)}. ` +
|
|
53
|
+
"MCP requires tool input and output schemas to describe an object; wrap the value, e.g. z.object({ result: ... }).");
|
|
54
|
+
}
|
|
55
|
+
return json;
|
|
56
|
+
}
|
|
57
|
+
export function makeRegistry(defs, opts = {}) {
|
|
14
58
|
const byName = new Map(defs.map((d) => [d.name, d]));
|
|
59
|
+
// Converted eagerly: a schema that cannot be represented throws HERE, at
|
|
60
|
+
// startup, naming the tool, instead of on a client's first tools/list.
|
|
61
|
+
// Keyed by definition, not name, so two definitions sharing a name (a
|
|
62
|
+
// mistake, but representable) cannot swap schemas.
|
|
63
|
+
const wire = new Map(defs.map((d) => [
|
|
64
|
+
d,
|
|
65
|
+
{
|
|
66
|
+
name: d.name,
|
|
67
|
+
description: d.description,
|
|
68
|
+
annotations: d.annotations,
|
|
69
|
+
inputSchema: toMcpSchema(d.input, "input", d.name),
|
|
70
|
+
outputSchema: toMcpSchema(d.output, "output", d.name),
|
|
71
|
+
},
|
|
72
|
+
]));
|
|
73
|
+
const { filter } = opts;
|
|
74
|
+
const allows = (def, ctx = {}) => {
|
|
75
|
+
if (!filter)
|
|
76
|
+
return true;
|
|
77
|
+
try {
|
|
78
|
+
// Only definitions from `defs` reach here in practice; the dispatcher
|
|
79
|
+
// looks them up through `get()`.
|
|
80
|
+
return filter(def, ctx) === true;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
15
86
|
return {
|
|
16
87
|
tools: defs,
|
|
17
88
|
get(name) {
|
|
18
89
|
return byName.get(name);
|
|
19
90
|
},
|
|
20
|
-
|
|
91
|
+
allows,
|
|
92
|
+
toMcpTools(includeDevOnly = false, ctx = {}) {
|
|
21
93
|
return defs
|
|
22
|
-
.filter((d) => includeDevOnly || !d.devOnly)
|
|
23
|
-
.map((d) =>
|
|
24
|
-
// The SDK Tool type narrows inputSchema/outputSchema to a JSON-
|
|
25
|
-
// schema with `type: "object"` literal; zodToJsonSchema returns
|
|
26
|
-
// the broader JsonSchema7Type union. Cast is safe because we
|
|
27
|
-
// only ever build Zod object schemas as tool I/O.
|
|
28
|
-
({
|
|
29
|
-
name: d.name,
|
|
30
|
-
description: d.description,
|
|
31
|
-
annotations: d.annotations,
|
|
32
|
-
inputSchema: zodToJsonSchema(d.input),
|
|
33
|
-
outputSchema: zodToJsonSchema(d.output),
|
|
34
|
-
}));
|
|
94
|
+
.filter((d) => (includeDevOnly || !d.devOnly) && allows(d, ctx))
|
|
95
|
+
.map((d) => wire.get(d));
|
|
35
96
|
},
|
|
36
97
|
};
|
|
37
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-registry.js","sourceRoot":"","sources":["../src/tool-registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tool-registry.js","sourceRoot":"","sources":["../src/tool-registry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@george43g/mcp-kit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "MCP server building blocks: tool registry types, dispatcher with timeout/perf/abort/error-wrap baked in, stdio + Streamable HTTP transports, sanitize() for user content, UUID-gated prompt-injection helpers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,10 +33,16 @@
|
|
|
33
33
|
"import": "./dist/transports/stdio.js",
|
|
34
34
|
"default": "./dist/transports/stdio.js"
|
|
35
35
|
},
|
|
36
|
+
"./testing": {
|
|
37
|
+
"types": "./dist/testing.d.ts",
|
|
38
|
+
"import": "./dist/testing.js",
|
|
39
|
+
"default": "./dist/testing.js"
|
|
40
|
+
},
|
|
36
41
|
"./package.json": "./package.json"
|
|
37
42
|
},
|
|
38
43
|
"files": [
|
|
39
44
|
"dist",
|
|
45
|
+
"!dist/tsconfig.tsbuildinfo",
|
|
40
46
|
"src",
|
|
41
47
|
"!src/**/*.test.ts",
|
|
42
48
|
"README.md",
|
|
@@ -51,12 +57,12 @@
|
|
|
51
57
|
"test:coverage": "vitest run --coverage"
|
|
52
58
|
},
|
|
53
59
|
"dependencies": {
|
|
54
|
-
"@george43g/robustness": ">=0.12.0 <1",
|
|
55
60
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
61
|
+
"ajv": "^8.17.1",
|
|
62
|
+
"ajv-formats": "^3.0.1"
|
|
58
63
|
},
|
|
59
64
|
"devDependencies": {
|
|
65
|
+
"@george43g/robustness": "workspace:*",
|
|
60
66
|
"@george43g/tsconfig": "workspace:*",
|
|
61
67
|
"@george43g/vitest-config": "workspace:*",
|
|
62
68
|
"@semantic-release/changelog": "^6.0.3",
|
|
@@ -67,6 +73,11 @@
|
|
|
67
73
|
"semantic-release": "^24.2.0",
|
|
68
74
|
"semantic-release-monorepo": "^8.0.2",
|
|
69
75
|
"typescript": "^5.7.0",
|
|
70
|
-
"vitest": "^3.2.7"
|
|
76
|
+
"vitest": "^3.2.7",
|
|
77
|
+
"zod": "^4.0.0"
|
|
78
|
+
},
|
|
79
|
+
"peerDependencies": {
|
|
80
|
+
"@george43g/robustness": ">=0.11.0 <1",
|
|
81
|
+
"zod": "^4.0.0"
|
|
71
82
|
}
|
|
72
83
|
}
|
package/src/dispatch.ts
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
import type { ZodError } from "zod";
|
|
32
32
|
import { wrapToolError } from "./prompt-injection.js";
|
|
33
33
|
import { sanitize } from "./sanitize.js";
|
|
34
|
-
import type { ContentBlock, ToolRegistry } from "./tool-registry.js";
|
|
34
|
+
import type { ContentBlock, ToolFilterContext, ToolRegistry } from "./tool-registry.js";
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Replace the absolute home-directory prefix with `~` in anything headed for a
|
|
@@ -121,14 +121,29 @@ export interface BuildDispatcherOptions {
|
|
|
121
121
|
devOnlyEnabled?: () => boolean;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Call a tool by name.
|
|
126
|
+
*
|
|
127
|
+
* `ctx` is what the registry's `filter` (see `makeRegistry`) is evaluated
|
|
128
|
+
* against. From an MCP `tools/call` handler, pass the handler's `extra`:
|
|
129
|
+
* `dispatch(name, args, extra.signal, extra)`. An in-process caller omits it,
|
|
130
|
+
* and the filter sees `{}`.
|
|
131
|
+
*/
|
|
132
|
+
export type Dispatch = (
|
|
133
|
+
name: string,
|
|
134
|
+
args: unknown,
|
|
135
|
+
signal?: AbortSignal,
|
|
136
|
+
ctx?: ToolFilterContext,
|
|
137
|
+
) => Promise<ToolResult>;
|
|
125
138
|
|
|
126
139
|
function defaultTimeoutMs(): number {
|
|
127
140
|
return envNum("MCP_TOOL_TIMEOUT_DEFAULT_MS", 30_000);
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
function formatZodError(err: ZodError): string {
|
|
131
|
-
return err.
|
|
144
|
+
return err.issues
|
|
145
|
+
.map((e) => ` - ${e.path.map(String).join(".") || "(root)"}: ${e.message}`)
|
|
146
|
+
.join("\n");
|
|
132
147
|
}
|
|
133
148
|
|
|
134
149
|
export function buildDispatcher(opts: BuildDispatcherOptions): Dispatch {
|
|
@@ -149,7 +164,7 @@ export function buildDispatcher(opts: BuildDispatcherOptions): Dispatch {
|
|
|
149
164
|
}
|
|
150
165
|
|
|
151
166
|
const fallback = defaultTimeoutMs();
|
|
152
|
-
return async (name, args, signal) => {
|
|
167
|
+
return async (name, args, signal, ctx = {}) => {
|
|
153
168
|
noteActivity();
|
|
154
169
|
opts.onCall?.(name);
|
|
155
170
|
const def = opts.registry.get(name);
|
|
@@ -162,8 +177,12 @@ export function buildDispatcher(opts: BuildDispatcherOptions): Dispatch {
|
|
|
162
177
|
// construction, which the readonly type discourages but does not prevent.
|
|
163
178
|
// If that ever happens the tool is gated, not exposed.
|
|
164
179
|
const devGated = def?.devOnly === true && !(opts.devOnlyEnabled?.() ?? false);
|
|
180
|
+
// The registry's per-request filter gates the CALL path with the same
|
|
181
|
+
// predicate that gates the listing. Hiding a tool from tools/list while it
|
|
182
|
+
// still answers by name is the hole `devOnly` already fell into once.
|
|
183
|
+
const filtered = def !== undefined && !opts.registry.allows(def, ctx);
|
|
165
184
|
|
|
166
|
-
if (!def || devGated) {
|
|
185
|
+
if (!def || devGated || filtered) {
|
|
167
186
|
opts.onError?.(name, new Error("unknown_tool"));
|
|
168
187
|
return {
|
|
169
188
|
content: [
|
package/src/index.ts
CHANGED
|
@@ -23,11 +23,17 @@ export { buildResourcesHandler } from "./resources.js";
|
|
|
23
23
|
export { CONTENT_BUDGET, sanitize, sanitizeContent } from "./sanitize.js";
|
|
24
24
|
export type {
|
|
25
25
|
AnyToolDefinition,
|
|
26
|
+
AnyZodSchema,
|
|
26
27
|
ContentBlock,
|
|
28
|
+
MakeRegistryOptions,
|
|
29
|
+
McpJsonSchema,
|
|
30
|
+
McpSchemaIo,
|
|
27
31
|
ToolDefinition,
|
|
32
|
+
ToolFilter,
|
|
33
|
+
ToolFilterContext,
|
|
28
34
|
ToolRegistry,
|
|
29
35
|
} from "./tool-registry.js";
|
|
30
|
-
export { makeRegistry } from "./tool-registry.js";
|
|
36
|
+
export { makeRegistry, toMcpSchema } from "./tool-registry.js";
|
|
31
37
|
export type { HttpServerHandle, HttpServerOptions } from "./transports/http.js";
|
|
32
38
|
export { startHttpServer } from "./transports/http.js";
|
|
33
39
|
export type { StartStdioOptions } from "./transports/stdio.js";
|