mcp-trellis 0.2.1 → 2.1.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 +70 -620
- package/dist/adapters/node-request.d.ts +53 -0
- package/dist/adapters/node-request.d.ts.map +1 -0
- package/dist/adapters/node-request.js +165 -0
- package/dist/adapters/node-request.js.map +1 -0
- package/dist/adapters/node.d.ts +16 -24
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +69 -88
- package/dist/adapters/node.js.map +1 -1
- package/dist/advanced.d.ts +18 -0
- package/dist/advanced.d.ts.map +1 -0
- package/dist/advanced.js +18 -0
- package/dist/advanced.js.map +1 -0
- package/dist/app-options.d.ts +132 -0
- package/dist/app-options.d.ts.map +1 -0
- package/dist/app-options.js +2 -0
- package/dist/app-options.js.map +1 -0
- package/dist/app.d.ts +2 -66
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +150 -57
- package/dist/app.js.map +1 -1
- package/dist/audit.d.ts +5 -5
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +19 -8
- package/dist/audit.js.map +1 -1
- package/dist/auth/bearer.d.ts +4 -1
- package/dist/auth/bearer.d.ts.map +1 -1
- package/dist/auth/bearer.js +25 -5
- package/dist/auth/bearer.js.map +1 -1
- package/dist/clients.d.ts.map +1 -1
- package/dist/clients.js +3 -6
- package/dist/clients.js.map +1 -1
- package/dist/deprecated.d.ts +42 -0
- package/dist/deprecated.d.ts.map +1 -0
- package/dist/deprecated.js +35 -0
- package/dist/deprecated.js.map +1 -0
- package/dist/http/body.d.ts +69 -0
- package/dist/http/body.d.ts.map +1 -0
- package/dist/http/body.js +165 -0
- package/dist/http/body.js.map +1 -0
- package/dist/http/http.d.ts +42 -0
- package/dist/http/http.d.ts.map +1 -0
- package/dist/http/http.js +100 -0
- package/dist/http/http.js.map +1 -0
- package/dist/http/origins.d.ts +37 -0
- package/dist/http/origins.d.ts.map +1 -0
- package/dist/http/origins.js +87 -0
- package/dist/http/origins.js.map +1 -0
- package/dist/mcp/dispatch.d.ts +7 -0
- package/dist/mcp/dispatch.d.ts.map +1 -0
- package/dist/mcp/dispatch.js +99 -0
- package/dist/mcp/dispatch.js.map +1 -0
- package/dist/{jsonrpc.d.ts → mcp/jsonrpc.d.ts} +10 -0
- package/dist/mcp/jsonrpc.d.ts.map +1 -0
- package/dist/mcp/jsonrpc.js +88 -0
- package/dist/mcp/jsonrpc.js.map +1 -0
- package/dist/mcp/methods.d.ts +133 -0
- package/dist/mcp/methods.d.ts.map +1 -0
- package/dist/mcp/methods.js +84 -0
- package/dist/mcp/methods.js.map +1 -0
- package/dist/mcp/protocol.d.ts +16 -0
- package/dist/mcp/protocol.d.ts.map +1 -0
- package/dist/mcp/protocol.js +22 -0
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/registry.d.ts +58 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +81 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/rpc-handlers.d.ts +11 -0
- package/dist/mcp/rpc-handlers.d.ts.map +1 -0
- package/dist/mcp/rpc-handlers.js +133 -0
- package/dist/mcp/rpc-handlers.js.map +1 -0
- package/dist/{tools.d.ts → mcp/tools.d.ts} +30 -2
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +166 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/{validate.d.ts → mcp/validate.d.ts} +24 -12
- package/dist/mcp/validate.d.ts.map +1 -0
- package/dist/mcp/validate.js +186 -0
- package/dist/mcp/validate.js.map +1 -0
- package/dist/oauth/audit.d.ts +20 -0
- package/dist/oauth/audit.d.ts.map +1 -0
- package/dist/oauth/audit.js +29 -0
- package/dist/oauth/audit.js.map +1 -0
- package/dist/oauth/cimd/cimd-parse.d.ts +4 -0
- package/dist/oauth/cimd/cimd-parse.d.ts.map +1 -0
- package/dist/oauth/cimd/cimd-parse.js +70 -0
- package/dist/oauth/cimd/cimd-parse.js.map +1 -0
- package/dist/oauth/cimd/cimd-ssrf.d.ts +8 -0
- package/dist/oauth/cimd/cimd-ssrf.d.ts.map +1 -0
- package/dist/oauth/cimd/cimd-ssrf.js +193 -0
- package/dist/oauth/cimd/cimd-ssrf.js.map +1 -0
- package/dist/oauth/cimd/cimd.d.ts +36 -0
- package/dist/oauth/cimd/cimd.d.ts.map +1 -0
- package/dist/oauth/cimd/cimd.js +132 -0
- package/dist/oauth/cimd/cimd.js.map +1 -0
- package/dist/oauth/cimd/types.d.ts +12 -0
- package/dist/oauth/cimd/types.d.ts.map +1 -0
- package/dist/oauth/cimd/types.js +3 -0
- package/dist/oauth/cimd/types.js.map +1 -0
- package/dist/oauth/config.d.ts +51 -0
- package/dist/oauth/config.d.ts.map +1 -0
- package/dist/oauth/config.js +108 -0
- package/dist/oauth/config.js.map +1 -0
- package/dist/oauth/constants.d.ts +15 -0
- package/dist/oauth/constants.d.ts.map +1 -1
- package/dist/oauth/constants.js +15 -0
- package/dist/oauth/constants.js.map +1 -1
- package/dist/oauth/{base64url.d.ts → crypto/base64url.d.ts} +1 -2
- package/dist/oauth/crypto/base64url.d.ts.map +1 -0
- package/dist/oauth/{base64url.js → crypto/base64url.js} +1 -5
- package/dist/oauth/crypto/base64url.js.map +1 -0
- package/dist/oauth/crypto/clientauth.d.ts +13 -0
- package/dist/oauth/crypto/clientauth.d.ts.map +1 -0
- package/dist/oauth/crypto/clientauth.js +195 -0
- package/dist/oauth/crypto/clientauth.js.map +1 -0
- package/dist/oauth/crypto/codes.d.ts +65 -0
- package/dist/oauth/crypto/codes.d.ts.map +1 -0
- package/dist/oauth/crypto/codes.js +121 -0
- package/dist/oauth/crypto/codes.js.map +1 -0
- package/dist/oauth/crypto/hkdf.d.ts +13 -0
- package/dist/oauth/crypto/hkdf.d.ts.map +1 -0
- package/dist/oauth/crypto/hkdf.js +30 -0
- package/dist/oauth/crypto/hkdf.js.map +1 -0
- package/dist/oauth/crypto/keycache.d.ts +19 -0
- package/dist/oauth/crypto/keycache.d.ts.map +1 -0
- package/dist/oauth/crypto/keycache.js +44 -0
- package/dist/oauth/crypto/keycache.js.map +1 -0
- package/dist/oauth/crypto/pkce.d.ts.map +1 -0
- package/dist/oauth/{pkce.js → crypto/pkce.js} +1 -1
- package/dist/oauth/crypto/pkce.js.map +1 -0
- package/dist/oauth/crypto/sealed.d.ts +26 -0
- package/dist/oauth/crypto/sealed.d.ts.map +1 -0
- package/dist/oauth/crypto/sealed.js +65 -0
- package/dist/oauth/crypto/sealed.js.map +1 -0
- package/dist/oauth/crypto/secrethash.d.ts +58 -0
- package/dist/oauth/crypto/secrethash.d.ts.map +1 -0
- package/dist/oauth/crypto/secrethash.js +82 -0
- package/dist/oauth/crypto/secrethash.js.map +1 -0
- package/dist/oauth/deprecated.d.ts +52 -0
- package/dist/oauth/deprecated.d.ts.map +1 -0
- package/dist/oauth/deprecated.js +49 -0
- package/dist/oauth/deprecated.js.map +1 -0
- package/dist/oauth/endpoints/authorize.d.ts +3 -0
- package/dist/oauth/endpoints/authorize.d.ts.map +1 -0
- package/dist/oauth/endpoints/authorize.js +209 -0
- package/dist/oauth/endpoints/authorize.js.map +1 -0
- package/dist/oauth/endpoints/callback.d.ts +20 -0
- package/dist/oauth/endpoints/callback.d.ts.map +1 -0
- package/dist/oauth/endpoints/callback.js +31 -0
- package/dist/oauth/endpoints/callback.js.map +1 -0
- package/dist/oauth/endpoints/consent-page.d.ts +5 -0
- package/dist/oauth/endpoints/consent-page.d.ts.map +1 -0
- package/dist/oauth/endpoints/consent-page.js +63 -0
- package/dist/oauth/endpoints/consent-page.js.map +1 -0
- package/dist/oauth/endpoints/consent.d.ts +29 -0
- package/dist/oauth/endpoints/consent.d.ts.map +1 -0
- package/dist/oauth/endpoints/consent.js +98 -0
- package/dist/oauth/endpoints/consent.js.map +1 -0
- package/dist/oauth/{metadata.d.ts → endpoints/metadata.d.ts} +14 -8
- package/dist/oauth/endpoints/metadata.d.ts.map +1 -0
- package/dist/oauth/{metadata.js → endpoints/metadata.js} +10 -4
- package/dist/oauth/endpoints/metadata.js.map +1 -0
- package/dist/oauth/endpoints/register.d.ts +10 -0
- package/dist/oauth/endpoints/register.d.ts.map +1 -0
- package/dist/oauth/endpoints/register.js +96 -0
- package/dist/oauth/endpoints/register.js.map +1 -0
- package/dist/oauth/{revoke.d.ts → endpoints/revoke.d.ts} +1 -1
- package/dist/oauth/endpoints/revoke.d.ts.map +1 -0
- package/dist/oauth/{revoke.js → endpoints/revoke.js} +11 -9
- package/dist/oauth/endpoints/revoke.js.map +1 -0
- package/dist/oauth/endpoints/token.d.ts +3 -0
- package/dist/oauth/endpoints/token.d.ts.map +1 -0
- package/dist/oauth/{token.js → endpoints/token.js} +33 -47
- package/dist/oauth/endpoints/token.js.map +1 -0
- package/dist/oauth/{wellknown.d.ts → endpoints/wellknown.d.ts} +1 -1
- package/dist/oauth/endpoints/wellknown.d.ts.map +1 -0
- package/dist/oauth/{wellknown.js → endpoints/wellknown.js} +7 -7
- package/dist/oauth/endpoints/wellknown.js.map +1 -0
- package/dist/oauth/{redirect.d.ts → policy/redirect.d.ts} +6 -1
- package/dist/oauth/policy/redirect.d.ts.map +1 -0
- package/dist/oauth/policy/redirect.js +39 -0
- package/dist/oauth/policy/redirect.js.map +1 -0
- package/dist/oauth/policy/reqbody.d.ts +18 -0
- package/dist/oauth/policy/reqbody.d.ts.map +1 -0
- package/dist/oauth/policy/reqbody.js +68 -0
- package/dist/oauth/policy/reqbody.js.map +1 -0
- package/dist/oauth/policy/resource.d.ts +37 -0
- package/dist/oauth/policy/resource.d.ts.map +1 -0
- package/dist/oauth/policy/resource.js +74 -0
- package/dist/oauth/policy/resource.js.map +1 -0
- package/dist/oauth/policy/scope.d.ts +20 -0
- package/dist/oauth/policy/scope.d.ts.map +1 -0
- package/dist/oauth/policy/scope.js +35 -0
- package/dist/oauth/policy/scope.js.map +1 -0
- package/dist/oauth/router.d.ts +12 -12
- package/dist/oauth/router.d.ts.map +1 -1
- package/dist/oauth/router.js +105 -87
- package/dist/oauth/router.js.map +1 -1
- package/dist/oauth/types.d.ts +177 -26
- package/dist/oauth/types.d.ts.map +1 -1
- package/dist/oauth/types.js +1 -27
- package/dist/oauth/types.js.map +1 -1
- package/dist/server.d.ts +14 -13
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -9
- package/dist/server.js.map +1 -1
- package/dist/util/defined.d.ts +11 -0
- package/dist/util/defined.d.ts.map +1 -0
- package/dist/util/defined.js +15 -0
- package/dist/util/defined.js.map +1 -0
- package/dist/util/json.d.ts +3 -0
- package/dist/util/json.d.ts.map +1 -0
- package/dist/util/json.js +3 -0
- package/dist/util/json.js.map +1 -0
- package/docs/ROADMAP.md +283 -0
- package/docs/compatibility.md +84 -0
- package/docs/diagrams/mcp-trellis-architecture.html +305 -0
- package/docs/guide.md +441 -0
- package/docs/reference.md +210 -0
- package/docs/security.md +112 -0
- package/docs/troubleshooting.md +19 -0
- package/package.json +24 -8
- package/dist/adapters/origins.d.ts +0 -19
- package/dist/adapters/origins.d.ts.map +0 -1
- package/dist/adapters/origins.js +0 -55
- package/dist/adapters/origins.js.map +0 -1
- package/dist/dispatch.d.ts +0 -7
- package/dist/dispatch.d.ts.map +0 -1
- package/dist/dispatch.js +0 -79
- package/dist/dispatch.js.map +0 -1
- package/dist/http.d.ts +0 -17
- package/dist/http.d.ts.map +0 -1
- package/dist/http.js +0 -38
- package/dist/http.js.map +0 -1
- package/dist/jsonrpc.d.ts.map +0 -1
- package/dist/jsonrpc.js +0 -17
- package/dist/jsonrpc.js.map +0 -1
- package/dist/methods.d.ts +0 -61
- package/dist/methods.d.ts.map +0 -1
- package/dist/methods.js +0 -114
- package/dist/methods.js.map +0 -1
- package/dist/oauth/authorize.d.ts +0 -3
- package/dist/oauth/authorize.d.ts.map +0 -1
- package/dist/oauth/authorize.js +0 -109
- package/dist/oauth/authorize.js.map +0 -1
- package/dist/oauth/base64url.d.ts.map +0 -1
- package/dist/oauth/base64url.js.map +0 -1
- package/dist/oauth/clientauth.d.ts +0 -19
- package/dist/oauth/clientauth.d.ts.map +0 -1
- package/dist/oauth/clientauth.js +0 -76
- package/dist/oauth/clientauth.js.map +0 -1
- package/dist/oauth/codes.d.ts +0 -30
- package/dist/oauth/codes.d.ts.map +0 -1
- package/dist/oauth/codes.js +0 -93
- package/dist/oauth/codes.js.map +0 -1
- package/dist/oauth/metadata.d.ts.map +0 -1
- package/dist/oauth/metadata.js.map +0 -1
- package/dist/oauth/pkce.d.ts.map +0 -1
- package/dist/oauth/pkce.js.map +0 -1
- package/dist/oauth/redirect.d.ts.map +0 -1
- package/dist/oauth/redirect.js +0 -26
- package/dist/oauth/redirect.js.map +0 -1
- package/dist/oauth/resource.d.ts +0 -7
- package/dist/oauth/resource.d.ts.map +0 -1
- package/dist/oauth/resource.js +0 -44
- package/dist/oauth/resource.js.map +0 -1
- package/dist/oauth/revoke.d.ts.map +0 -1
- package/dist/oauth/revoke.js.map +0 -1
- package/dist/oauth/scope.d.ts +0 -11
- package/dist/oauth/scope.d.ts.map +0 -1
- package/dist/oauth/scope.js +0 -24
- package/dist/oauth/scope.js.map +0 -1
- package/dist/oauth/token.d.ts +0 -3
- package/dist/oauth/token.d.ts.map +0 -1
- package/dist/oauth/token.js.map +0 -1
- package/dist/oauth/wellknown.d.ts.map +0 -1
- package/dist/oauth/wellknown.js.map +0 -1
- package/dist/protocol.d.ts +0 -4
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js +0 -14
- package/dist/protocol.js.map +0 -1
- package/dist/registry.d.ts +0 -37
- package/dist/registry.d.ts.map +0 -1
- package/dist/registry.js +0 -69
- package/dist/registry.js.map +0 -1
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js +0 -97
- package/dist/tools.js.map +0 -1
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -130
- package/dist/validate.js.map +0 -1
- /package/dist/oauth/{pkce.d.ts → crypto/pkce.d.ts} +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const PROTOCOL_VERSIONS = new Set(["2024-11-05", "2025-03-26", "2025-06-18"]);
|
|
2
|
+
/**
|
|
3
|
+
* Answered on `initialize` when the client's requested version is missing
|
|
4
|
+
* or unrecognized: per the spec, the latest version this server supports.
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_PROTOCOL_VERSION = "2025-06-18";
|
|
7
|
+
/**
|
|
8
|
+
* The assumed protocol version for a request that omits the
|
|
9
|
+
* `MCP-Protocol-Version` header — distinct from `DEFAULT_PROTOCOL_VERSION`
|
|
10
|
+
* above. This is the 2025-06-18 spec's own backwards-compatibility rule
|
|
11
|
+
* for the header specifically (introduced in that revision, so a header-less
|
|
12
|
+
* request predates it), not a "pick the newest" preference.
|
|
13
|
+
*/
|
|
14
|
+
export const ASSUMED_HEADER_PROTOCOL_VERSION = "2025-03-26";
|
|
15
|
+
export const pickProtocolVersion = (params) => {
|
|
16
|
+
const requested = params?.protocolVersion;
|
|
17
|
+
if (typeof requested === "string" && PROTOCOL_VERSIONS.has(requested)) {
|
|
18
|
+
return requested;
|
|
19
|
+
}
|
|
20
|
+
return DEFAULT_PROTOCOL_VERSION;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/mcp/protocol.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;AAErF;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,YAAY,CAAC;AAE5D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAAgC,EAAU,EAAE;IAC9E,MAAM,SAAS,GAAG,MAAM,EAAE,eAAe,CAAC;IAC1C,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACtE,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,wBAAwB,CAAC;AAClC,CAAC,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { JsonSchema } from "./validate.js";
|
|
2
|
+
export type ToolResult = {
|
|
3
|
+
content: Array<{
|
|
4
|
+
type: "text";
|
|
5
|
+
text: string;
|
|
6
|
+
}>;
|
|
7
|
+
isError?: boolean | undefined;
|
|
8
|
+
};
|
|
9
|
+
export type ToolHandler<TCtx> = (ctx: TCtx, args: Record<string, unknown>) => Promise<ToolResult | string> | ToolResult | string;
|
|
10
|
+
export type ToolDef<TCtx> = {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
inputSchema: JsonSchema;
|
|
14
|
+
/**
|
|
15
|
+
* Required scope, or `undefined`/omitted for "any authenticated
|
|
16
|
+
* principal, whatever its scopes." On a `createMcpApp` server advertising
|
|
17
|
+
* more than one scope, an omitted `scope` is a construction-time error —
|
|
18
|
+
* see `assertToolScopesConfigured` — precisely because "any authenticated
|
|
19
|
+
* principal" silently includes a principal with zero scopes, which is
|
|
20
|
+
* rarely the intent on a multi-scope server. Pass `scope: null` to state
|
|
21
|
+
* that intentionally instead of by omission.
|
|
22
|
+
*/
|
|
23
|
+
scope?: string | null | undefined;
|
|
24
|
+
handler: ToolHandler<TCtx>;
|
|
25
|
+
};
|
|
26
|
+
export type ToolListEntry = {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
inputSchema: JsonSchema;
|
|
30
|
+
};
|
|
31
|
+
export type ToolRegistry<TCtx> = {
|
|
32
|
+
/**
|
|
33
|
+
* `allowScope`, when passed, is consulted per tool with that tool's
|
|
34
|
+
* `scope` — omit a tool by returning `false`. Lets a caller (see
|
|
35
|
+
* `McpHandlerOptions.hideToolsOutsideScope`) filter `tools/list` by a
|
|
36
|
+
* principal's granted scopes without the registry itself knowing what a
|
|
37
|
+
* "principal" or "scope check" is — it only ever sees the raw `scope`
|
|
38
|
+
* value already on each `ToolDef`.
|
|
39
|
+
*/
|
|
40
|
+
list: (allowScope?: (scope: string | null | undefined) => boolean) => ToolListEntry[];
|
|
41
|
+
get: (name: string) => ToolDef<TCtx> | undefined;
|
|
42
|
+
call: (name: string, ctx: TCtx, args: Record<string, unknown>) => Promise<ToolResult>;
|
|
43
|
+
};
|
|
44
|
+
export type RegistryOptions = {
|
|
45
|
+
/**
|
|
46
|
+
* Validate tools/call args against inputSchema. Default **true** since 2.0 —
|
|
47
|
+
* forgetting this was a silent injection path into handlers. Set `false`
|
|
48
|
+
* only when you intentionally skip schema checks.
|
|
49
|
+
*/
|
|
50
|
+
validateArgs?: boolean | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Map tool exceptions to client-visible text.
|
|
53
|
+
* Default: `"Tool execution failed"` (no exception leakage).
|
|
54
|
+
*/
|
|
55
|
+
onToolError?: ((error: unknown) => string) | undefined;
|
|
56
|
+
};
|
|
57
|
+
export declare const createToolRegistry: <TCtx>(tools: ToolDef<TCtx>[], options?: RegistryOptions) => ToolRegistry<TCtx>;
|
|
58
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,IAAI,IAAI,CAC9B,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC1B,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,UAAU,GAAG,MAAM,CAAC;AAExD,MAAM,MAAM,OAAO,CAAC,IAAI,IAAI;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,IAAI,IAAI;IAC/B;;;;;;;OAOG;IACH,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,OAAO,KAAK,aAAa,EAAE,CAAC;IACtF,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IACjD,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACvF,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CACxD,CAAC;AA8DF,eAAO,MAAM,kBAAkB,GAAI,IAAI,EACrC,OAAO,OAAO,CAAC,IAAI,CAAC,EAAE,EACtB,UAAS,eAAoB,KAC5B,YAAY,CAAC,IAAI,CAqCnB,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { missingObjectType, unsupportedKeywords, validateAgainstSchema } from "./validate.js";
|
|
2
|
+
const DEFAULT_TOOL_ERROR = "Tool execution failed";
|
|
3
|
+
/**
|
|
4
|
+
* Map a tool exception to client-visible text.
|
|
5
|
+
* A throwing or non-string `onToolError` falls back to the redacted default —
|
|
6
|
+
* a mapper must never turn a tool failure into a transport failure.
|
|
7
|
+
*/
|
|
8
|
+
const resolveToolError = (caught, onToolError) => {
|
|
9
|
+
if (!onToolError)
|
|
10
|
+
return DEFAULT_TOOL_ERROR;
|
|
11
|
+
try {
|
|
12
|
+
const mapped = onToolError(caught);
|
|
13
|
+
return typeof mapped === "string" && mapped.length > 0 ? mapped : DEFAULT_TOOL_ERROR;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return DEFAULT_TOOL_ERROR;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const asToolResult = (out) => {
|
|
20
|
+
if (typeof out === "string") {
|
|
21
|
+
return { content: [{ type: "text", text: out }], isError: false };
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
};
|
|
25
|
+
const errorResult = (message) => ({
|
|
26
|
+
content: [{ type: "text", text: message }],
|
|
27
|
+
isError: true,
|
|
28
|
+
});
|
|
29
|
+
/** Throws with every violation listed at once, rather than failing on the first tool found. */
|
|
30
|
+
const assertToolSchemasValid = (tools) => {
|
|
31
|
+
const keywordViolations = tools.flatMap((tool) => unsupportedKeywords(tool.inputSchema).map((path) => `${tool.name}: unsupported JSON Schema keyword at ${path}`));
|
|
32
|
+
if (keywordViolations.length > 0) {
|
|
33
|
+
throw new Error(`validateArgs: true but inputSchema uses unsupported keywords:\n` +
|
|
34
|
+
keywordViolations.join("\n") +
|
|
35
|
+
"\nRemove the keyword, enforce it in the handler, or set validateArgs: false");
|
|
36
|
+
}
|
|
37
|
+
// `properties`/`required` without `type: "object"` validates nothing at
|
|
38
|
+
// that node, and passes the keyword check above. See `missingObjectType`.
|
|
39
|
+
const typeViolations = tools.flatMap((tool) => missingObjectType(tool.inputSchema).map((path) => `${tool.name}: ${path} uses properties/required without type: "object"`));
|
|
40
|
+
if (typeViolations.length > 0) {
|
|
41
|
+
throw new Error(`validateArgs: true but inputSchema implies an object shape without declaring it:\n` +
|
|
42
|
+
typeViolations.join("\n") +
|
|
43
|
+
'\nAdd type: "object" (or include it in a union), or set validateArgs: false');
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
export const createToolRegistry = (tools, options = {}) => {
|
|
47
|
+
const byName = new Map(tools.map((t) => [t.name, t]));
|
|
48
|
+
if (byName.size !== tools.length) {
|
|
49
|
+
throw new Error("duplicate tool names in registry");
|
|
50
|
+
}
|
|
51
|
+
const validateArgs = options.validateArgs !== false;
|
|
52
|
+
if (validateArgs)
|
|
53
|
+
assertToolSchemasValid(tools);
|
|
54
|
+
return {
|
|
55
|
+
list: (allowScope) => tools
|
|
56
|
+
.filter((tool) => !allowScope || allowScope(tool.scope))
|
|
57
|
+
.map(({ name, description, inputSchema }) => ({
|
|
58
|
+
name,
|
|
59
|
+
description,
|
|
60
|
+
inputSchema,
|
|
61
|
+
})),
|
|
62
|
+
get: (name) => byName.get(name),
|
|
63
|
+
call: async (name, ctx, args) => {
|
|
64
|
+
const tool = byName.get(name);
|
|
65
|
+
if (!tool)
|
|
66
|
+
return errorResult(`Unknown tool: ${name}`);
|
|
67
|
+
if (validateArgs) {
|
|
68
|
+
const errors = validateAgainstSchema(args, tool.inputSchema);
|
|
69
|
+
if (errors.length > 0)
|
|
70
|
+
return errorResult(errors.join("; "));
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return asToolResult(await tool.handler(ctx, args));
|
|
74
|
+
}
|
|
75
|
+
catch (caught) {
|
|
76
|
+
return errorResult(resolveToolError(caught, options.onToolError));
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** JSON-RPC method handlers and authenticated dispatch. */
|
|
2
|
+
import { type JsonRpcRequest } from "./jsonrpc.js";
|
|
3
|
+
import { type ResolvedMcpHandlerOptions } from "./methods.js";
|
|
4
|
+
export declare const dispatchRpc: <TCtx>(input: {
|
|
5
|
+
req: Request;
|
|
6
|
+
body: JsonRpcRequest;
|
|
7
|
+
options: ResolvedMcpHandlerOptions<TCtx>;
|
|
8
|
+
/** Request start (captured in `createMcpHandler.fetch`), for denial-path audit timing. */
|
|
9
|
+
startedAt: number;
|
|
10
|
+
}) => Promise<Response>;
|
|
11
|
+
//# sourceMappingURL=rpc-handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-handlers.d.ts","sourceRoot":"","sources":["../../src/mcp/rpc-handlers.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAI3D,OAAO,EAIL,KAAK,cAAc,EAGpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAOL,KAAK,yBAAyB,EAI/B,MAAM,cAAc,CAAC;AA8ItB,eAAO,MAAM,WAAW,GAAU,IAAI,EAAE,OAAO;IAC7C,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,yBAAyB,CAAC,IAAI,CAAC,CAAC;IACzC,0FAA0F;IAC1F,SAAS,EAAE,MAAM,CAAC;CACnB,KAAG,OAAO,CAAC,QAAQ,CAkCnB,CAAC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/** JSON-RPC method handlers and authenticated dispatch. */
|
|
2
|
+
import { jsonResponse } from "../http/http.js";
|
|
3
|
+
import { isJsonObject } from "../util/json.js";
|
|
4
|
+
import { JSONRPC_INVALID_PARAMS, JSONRPC_METHOD_NOT_FOUND, rpcError, rpcResult, } from "./jsonrpc.js";
|
|
5
|
+
import { DENIAL_REASONS, hasScope, insufficientScope, resolveWwwAuthenticate, safeAudit, unauthorized, } from "./methods.js";
|
|
6
|
+
import { pickProtocolVersion } from "./protocol.js";
|
|
7
|
+
/** The one shape every "tools/call" outcome — unknown tool, missing scope, or a real call — audits. */
|
|
8
|
+
const auditToolCall = (options, input) => safeAudit(options, {
|
|
9
|
+
method: "tools/call",
|
|
10
|
+
tool: input.tool,
|
|
11
|
+
principalId: input.principal?.id,
|
|
12
|
+
ok: input.ok,
|
|
13
|
+
error: input.error,
|
|
14
|
+
durationMs: Date.now() - input.startedAt,
|
|
15
|
+
});
|
|
16
|
+
const parseToolCallArgs = (body) => {
|
|
17
|
+
const params = body.params ?? {};
|
|
18
|
+
const name = String(params.name ?? "");
|
|
19
|
+
const args = isJsonObject(params.arguments) ? params.arguments : {};
|
|
20
|
+
return { name, args };
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* A name that doesn't refer to any registered tool is a malformed request,
|
|
24
|
+
* not a tool execution outcome — MCP distinguishes protocol errors (a
|
|
25
|
+
* standard JSON-RPC error response) from a tool's own isError: true result,
|
|
26
|
+
* and "no such tool" belongs to the former. `ToolRegistry.call`'s own
|
|
27
|
+
* "Unknown tool: …" text-result fallback stays as is for direct callers of
|
|
28
|
+
* that API outside this dispatch.
|
|
29
|
+
*/
|
|
30
|
+
const unknownToolResponse = async (options, input) => {
|
|
31
|
+
await auditToolCall(options, {
|
|
32
|
+
...input,
|
|
33
|
+
tool: input.name,
|
|
34
|
+
ok: false,
|
|
35
|
+
error: DENIAL_REASONS.unknownTool,
|
|
36
|
+
});
|
|
37
|
+
return jsonResponse({
|
|
38
|
+
data: rpcError(input.id, JSONRPC_INVALID_PARAMS, `Unknown tool: ${input.name}`),
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
const missingScopeResponse = async (req, options, input) => {
|
|
42
|
+
await auditToolCall(options, {
|
|
43
|
+
...input,
|
|
44
|
+
tool: input.name,
|
|
45
|
+
ok: false,
|
|
46
|
+
error: DENIAL_REASONS.missingScope,
|
|
47
|
+
});
|
|
48
|
+
const wwwAuthenticate = resolveWwwAuthenticate(options, req);
|
|
49
|
+
// No principal at all (only reachable when a host adds "tools/call" to
|
|
50
|
+
// `publicMethods`) → 401, nothing was presented to authenticate with.
|
|
51
|
+
// A principal that authenticated but lacks the tool's scope → 403
|
|
52
|
+
// insufficient_scope (RFC 6750 §3.1) — see `insufficientScope`'s doc.
|
|
53
|
+
return input.principal
|
|
54
|
+
? insufficientScope(wwwAuthenticate, input.scope, input.id)
|
|
55
|
+
: unauthorized(wwwAuthenticate, `Missing scope: ${input.scope}`, input.id);
|
|
56
|
+
};
|
|
57
|
+
const METHODS = {
|
|
58
|
+
initialize: async ({ id, body, options }) => jsonResponse({
|
|
59
|
+
data: rpcResult(id, {
|
|
60
|
+
protocolVersion: pickProtocolVersion(body.params),
|
|
61
|
+
capabilities: { tools: {} },
|
|
62
|
+
serverInfo: options.serverInfo,
|
|
63
|
+
instructions: options.instructions ?? "",
|
|
64
|
+
}),
|
|
65
|
+
}),
|
|
66
|
+
ping: async ({ id }) => jsonResponse({ data: rpcResult(id, {}) }),
|
|
67
|
+
"tools/list": async ({ id, options, principal }) => {
|
|
68
|
+
const allowScope = options.hideToolsOutsideScope
|
|
69
|
+
? (scope) => !scope || (principal ? hasScope(principal, scope) : false)
|
|
70
|
+
: undefined;
|
|
71
|
+
return jsonResponse({ data: rpcResult(id, { tools: options.registry.list(allowScope) }) });
|
|
72
|
+
},
|
|
73
|
+
"tools/call": async ({ req, body, id, principal, options, startedAt }) => {
|
|
74
|
+
const { name, args } = parseToolCallArgs(body);
|
|
75
|
+
const tool = options.registry.get(name);
|
|
76
|
+
if (!tool)
|
|
77
|
+
return unknownToolResponse(options, { name, principal, id, startedAt });
|
|
78
|
+
if (tool.scope && (!principal || !hasScope(principal, tool.scope))) {
|
|
79
|
+
return missingScopeResponse(req, options, {
|
|
80
|
+
name,
|
|
81
|
+
principal,
|
|
82
|
+
id,
|
|
83
|
+
startedAt,
|
|
84
|
+
scope: tool.scope,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// Built only for a call that will actually run: `initialize`, `ping`,
|
|
88
|
+
// `tools/list` and denied calls never reach the host's `context` port.
|
|
89
|
+
const ctx = await options.ports.context(req, principal);
|
|
90
|
+
const toolStartedAt = Date.now();
|
|
91
|
+
const result = await options.registry.call(name, ctx, args);
|
|
92
|
+
await auditToolCall(options, {
|
|
93
|
+
tool: name,
|
|
94
|
+
principal,
|
|
95
|
+
ok: !result.isError,
|
|
96
|
+
error: result.isError ? result.content[0]?.text : undefined,
|
|
97
|
+
startedAt: toolStartedAt,
|
|
98
|
+
});
|
|
99
|
+
return jsonResponse({ data: rpcResult(id, result) });
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
export const dispatchRpc = async (input) => {
|
|
103
|
+
const { req, body, options, startedAt } = input;
|
|
104
|
+
// Shape-validated in `handlePost` before routing — method is a non-empty string.
|
|
105
|
+
const method = typeof body.method === "string" ? body.method : "";
|
|
106
|
+
// Notifications omit `id`; explicit null is a valid request id (JSON-RPC).
|
|
107
|
+
const id = body.id === undefined ? null : body.id;
|
|
108
|
+
const toolName = method === "tools/call" ? String(body.params?.name ?? "") : undefined;
|
|
109
|
+
// Notifications (including every `notifications/*`) already got 202 in `handlePost`.
|
|
110
|
+
const isPublic = options.publicMethods.has(method);
|
|
111
|
+
let principal = null;
|
|
112
|
+
if (!isPublic) {
|
|
113
|
+
principal = await options.ports.authenticate(req, method, toolName);
|
|
114
|
+
if (!principal) {
|
|
115
|
+
await safeAudit(options, {
|
|
116
|
+
method,
|
|
117
|
+
tool: toolName,
|
|
118
|
+
ok: false,
|
|
119
|
+
error: DENIAL_REASONS.unauthorized,
|
|
120
|
+
durationMs: Date.now() - startedAt,
|
|
121
|
+
});
|
|
122
|
+
return unauthorized(resolveWwwAuthenticate(options, req), undefined, id);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const handler = METHODS[method];
|
|
126
|
+
if (!handler) {
|
|
127
|
+
return jsonResponse({
|
|
128
|
+
data: rpcError(id, JSONRPC_METHOD_NOT_FOUND, `Method not found: ${method}`),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return handler({ req, body, id, principal, options, startedAt });
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=rpc-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-handlers.js","sourceRoot":"","sources":["../../src/mcp/rpc-handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* an arbitrary Standard Schema validator. `input`, when supplied, is what
|
|
8
8
|
* actually parses and types `args` at call time — keep the two in sync.
|
|
9
9
|
*/
|
|
10
|
-
import type { JsonSchema } from "./validate.js";
|
|
11
10
|
import type { ToolDef, ToolResult } from "./registry.js";
|
|
11
|
+
import type { JsonSchema } from "./validate.js";
|
|
12
12
|
/**
|
|
13
13
|
* Minimal Standard Schema v1 surface (https://standardschema.dev).
|
|
14
14
|
* Any compliant validator works here with zero adapter code. This is a
|
|
@@ -42,7 +42,8 @@ type ToolCore = {
|
|
|
42
42
|
description: string;
|
|
43
43
|
/** Advertised via tools/list. Required — see module doc for why. */
|
|
44
44
|
inputSchema: JsonSchema;
|
|
45
|
-
scope
|
|
45
|
+
/** See `ToolDef.scope` — pass `null` to explicitly opt out of a scope check. */
|
|
46
|
+
scope?: string | null | undefined;
|
|
46
47
|
};
|
|
47
48
|
type ToolHandler<TCtx, Args> = (ctx: TCtx, args: Args) => Promise<ToolResult | string> | ToolResult | string;
|
|
48
49
|
type ValidatedInput<Input> = {
|
|
@@ -66,7 +67,34 @@ export type ApiRequest = string | URL | Request;
|
|
|
66
67
|
type ApiExtra<TCtx, Args> = {
|
|
67
68
|
request: (ctx: TCtx, args: Args) => ApiRequest | Promise<ApiRequest>;
|
|
68
69
|
respond?: (res: Response) => Promise<ToolResult | string> | ToolResult | string;
|
|
70
|
+
/**
|
|
71
|
+
* Shape a non-2xx response yourself — you get the raw `Response`, so read
|
|
72
|
+
* `res.text()`/`res.json()` if you want the body. Omit for the default:
|
|
73
|
+
* status only, upstream body never forwarded. A returned bare `string` is
|
|
74
|
+
* **not** automatically marked as an error (same as any other tool
|
|
75
|
+
* handler) — return `{ content: [...], isError: true }` explicitly if
|
|
76
|
+
* that's what you want the model to see.
|
|
77
|
+
*/
|
|
78
|
+
onError?: (res: Response) => Promise<ToolResult | string> | ToolResult | string;
|
|
69
79
|
fetch?: typeof fetch;
|
|
80
|
+
/**
|
|
81
|
+
* Abort the upstream request after this many ms. Default 30000. An
|
|
82
|
+
* upstream that never responds otherwise hangs the tool call (and the
|
|
83
|
+
* MCP request behind it) indefinitely. Pass `false` to disable — the
|
|
84
|
+
* request then relies entirely on whatever signal (if any) is already on
|
|
85
|
+
* the `Request` your `request` callback returns; a timeout firing surfaces
|
|
86
|
+
* as `isError: true`, not a thrown exception `onToolError` would redact.
|
|
87
|
+
*/
|
|
88
|
+
timeoutMs?: number | false;
|
|
89
|
+
/**
|
|
90
|
+
* Cap the upstream response body at this many bytes before it ever
|
|
91
|
+
* reaches `respond`/`onError`/the default error path — an unbounded
|
|
92
|
+
* `res.text()` on an attacker-influenced or merely oversized upstream
|
|
93
|
+
* response is the same memory-exhaustion shape an unbounded *incoming*
|
|
94
|
+
* request body is (see `body.ts`). Default 1 MiB. Exceeding it surfaces
|
|
95
|
+
* as `isError: true`, not a thrown exception `onToolError` would redact.
|
|
96
|
+
*/
|
|
97
|
+
maxResponseBytes?: number;
|
|
70
98
|
};
|
|
71
99
|
export type ApiToolOptions<TCtx, Input = Record<string, unknown>> = (ToolCore & ValidatedInput<Input> & ApiExtra<TCtx, Input>) | (ToolCore & RawInput & ApiExtra<TCtx, Record<string, unknown>>);
|
|
72
100
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ergonomic tool authoring on top of `ToolDef` — turning "I have an API" into
|
|
3
|
+
* "I have an MCP tool" without hand-rolling validation or fetch plumbing.
|
|
4
|
+
*
|
|
5
|
+
* `inputSchema` (JSON Schema) stays required: it's what `tools/list` actually
|
|
6
|
+
* advertises to clients, and no library-agnostic way exists to derive it from
|
|
7
|
+
* an arbitrary Standard Schema validator. `input`, when supplied, is what
|
|
8
|
+
* actually parses and types `args` at call time — keep the two in sync.
|
|
9
|
+
*/
|
|
10
|
+
import { BodyTooLargeError, DEFAULT_MCP_BODY_LIMIT, readBoundedBytes } from "../http/body.js";
|
|
11
|
+
import { pickDefined } from "../util/defined.js";
|
|
12
|
+
const pathToString = (path) => (path ?? [])
|
|
13
|
+
.map((segment) => segment && typeof segment === "object" && "key" in segment
|
|
14
|
+
? String(segment.key)
|
|
15
|
+
: String(segment))
|
|
16
|
+
.join(".");
|
|
17
|
+
const parseWithSchema = async (schema, raw) => {
|
|
18
|
+
const result = await schema["~standard"].validate(raw);
|
|
19
|
+
const issues = result.issues;
|
|
20
|
+
if (issues?.length) {
|
|
21
|
+
return {
|
|
22
|
+
issues: issues.map((issue) => {
|
|
23
|
+
const path = pathToString(issue.path);
|
|
24
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return { value: result.value };
|
|
29
|
+
};
|
|
30
|
+
const issuesResult = (issues) => ({
|
|
31
|
+
content: [{ type: "text", text: issues.join("; ") }],
|
|
32
|
+
isError: true,
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* A `ToolDef` with typed, validated `args` — drop straight into
|
|
36
|
+
* `createToolRegistry` / `createMcpApp`'s `tools` array like any other tool.
|
|
37
|
+
*/
|
|
38
|
+
export const defineTool = (options) => ({
|
|
39
|
+
name: options.name,
|
|
40
|
+
description: options.description,
|
|
41
|
+
inputSchema: options.inputSchema,
|
|
42
|
+
...pickDefined(options, ["scope"]),
|
|
43
|
+
handler: async (ctx, rawArgs) => {
|
|
44
|
+
if (!options.input)
|
|
45
|
+
return options.handler(ctx, rawArgs);
|
|
46
|
+
const parsed = await parseWithSchema(options.input, rawArgs);
|
|
47
|
+
if ("issues" in parsed)
|
|
48
|
+
return issuesResult(parsed.issues);
|
|
49
|
+
return options.handler(ctx, parsed.value);
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const defaultRespond = (res) => res.text();
|
|
53
|
+
/**
|
|
54
|
+
* Status only — the upstream body is never forwarded by default. This is a
|
|
55
|
+
* return value, not a thrown exception, so `onToolError` redaction never
|
|
56
|
+
* sees it; an upstream error page can echo internal detail, tokens or SQL
|
|
57
|
+
* into the tool result and audit log. Use `onError` to forward (a redacted
|
|
58
|
+
* version of) the body on purpose.
|
|
59
|
+
*/
|
|
60
|
+
const defaultErrorResult = (res) => {
|
|
61
|
+
const status = [res.status, res.statusText].filter(Boolean).join(" ");
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: `Request failed: ${status}` }],
|
|
64
|
+
isError: true,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
const DEFAULT_API_TOOL_TIMEOUT_MS = 30_000;
|
|
68
|
+
const isTimeoutError = (caught) => {
|
|
69
|
+
if (!(caught instanceof Error))
|
|
70
|
+
return false;
|
|
71
|
+
return (caught.name === "TimeoutError" ||
|
|
72
|
+
caught.name === "AbortError" ||
|
|
73
|
+
caught.message === "body read aborted");
|
|
74
|
+
};
|
|
75
|
+
const timedOutResult = (timeoutMs) => ({
|
|
76
|
+
content: [{ type: "text", text: `Request timed out after ${timeoutMs}ms` }],
|
|
77
|
+
isError: true,
|
|
78
|
+
});
|
|
79
|
+
/** A timed-out fetch becomes a `ToolResult`; every other throw still propagates. */
|
|
80
|
+
const fetchWithTimeout = async (fetchImpl, input, timeoutMs) => {
|
|
81
|
+
if (timeoutMs === false)
|
|
82
|
+
return { response: await fetchImpl(input) };
|
|
83
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
84
|
+
try {
|
|
85
|
+
return { response: await fetchImpl(input, { signal }), signal };
|
|
86
|
+
}
|
|
87
|
+
catch (caught) {
|
|
88
|
+
if (isTimeoutError(caught))
|
|
89
|
+
return timedOutResult(timeoutMs);
|
|
90
|
+
throw caught;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Capped before `respond`/`onError` ever see it — an unbounded res.text()
|
|
95
|
+
* on the upstream body is the same memory-exhaustion shape an unbounded
|
|
96
|
+
* *incoming* body is (see body.ts). Rebuilt as a fresh Response from the
|
|
97
|
+
* raw bytes — not decoded text — so `respond`/`onError` can still call
|
|
98
|
+
* res.arrayBuffer()/res.blob() on binary bodies as well as res.text()/
|
|
99
|
+
* res.json(), exactly as if they'd read the original response themselves.
|
|
100
|
+
* An oversized body, or the timeout signal firing mid-body, becomes a
|
|
101
|
+
* `ToolResult`; every other throw still propagates.
|
|
102
|
+
*/
|
|
103
|
+
const boundResponse = async (res, maxResponseBytes, timeoutMs, signal) => {
|
|
104
|
+
let bytes;
|
|
105
|
+
try {
|
|
106
|
+
bytes = (await readBoundedBytes(res, maxResponseBytes, signal));
|
|
107
|
+
}
|
|
108
|
+
catch (caught) {
|
|
109
|
+
if (caught instanceof BodyTooLargeError) {
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: "text", text: `Response exceeded ${maxResponseBytes} bytes` }],
|
|
112
|
+
isError: true,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (isTimeoutError(caught))
|
|
116
|
+
return timedOutResult(timeoutMs);
|
|
117
|
+
throw caught;
|
|
118
|
+
}
|
|
119
|
+
// The buffered body is already decoded and re-framed — the upstream
|
|
120
|
+
// encoding/length headers no longer describe it.
|
|
121
|
+
const headers = new Headers(res.headers);
|
|
122
|
+
headers.delete("content-encoding");
|
|
123
|
+
headers.delete("content-length");
|
|
124
|
+
return new Response(bytes, { status: res.status, statusText: res.statusText, headers });
|
|
125
|
+
};
|
|
126
|
+
const runApi = async (options, ctx, args) => {
|
|
127
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
128
|
+
const input = await options.request(ctx, args);
|
|
129
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_API_TOOL_TIMEOUT_MS;
|
|
130
|
+
const fetched = await fetchWithTimeout(fetchImpl, input, timeoutMs);
|
|
131
|
+
if (!("response" in fetched))
|
|
132
|
+
return fetched;
|
|
133
|
+
const maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MCP_BODY_LIMIT;
|
|
134
|
+
const bounded = await boundResponse(fetched.response, maxResponseBytes, timeoutMs, fetched.signal);
|
|
135
|
+
if (!(bounded instanceof Response))
|
|
136
|
+
return bounded;
|
|
137
|
+
if (!bounded.ok)
|
|
138
|
+
return options.onError ? options.onError(bounded) : defaultErrorResult(bounded);
|
|
139
|
+
return (options.respond ?? defaultRespond)(bounded);
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Wrap a single REST call as an MCP tool in one call: build the request from
|
|
143
|
+
* typed args, run it, and shape the response — no hand-rolled fetch/error
|
|
144
|
+
* plumbing per tool. Built on `defineTool`, so `input` gets the same
|
|
145
|
+
* validation-before-call treatment.
|
|
146
|
+
*/
|
|
147
|
+
export const apiTool = (options) => {
|
|
148
|
+
const core = {
|
|
149
|
+
name: options.name,
|
|
150
|
+
description: options.description,
|
|
151
|
+
inputSchema: options.inputSchema,
|
|
152
|
+
...pickDefined(options, ["scope"]),
|
|
153
|
+
};
|
|
154
|
+
if (options.input) {
|
|
155
|
+
return defineTool({
|
|
156
|
+
...core,
|
|
157
|
+
input: options.input,
|
|
158
|
+
handler: (ctx, args) => runApi(options, ctx, args),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return defineTool({
|
|
162
|
+
...core,
|
|
163
|
+
handler: (ctx, args) => runApi(options, ctx, args),
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
export type JsonSchema = {
|
|
2
|
-
type
|
|
2
|
+
/** A single type, or a union (`["string", "null"]`) — both are evaluated. */
|
|
3
|
+
type?: string | string[];
|
|
3
4
|
properties?: Record<string, JsonSchema>;
|
|
4
5
|
required?: string[];
|
|
5
6
|
enum?: unknown[];
|
|
6
7
|
items?: JsonSchema;
|
|
7
8
|
minimum?: number;
|
|
8
9
|
maximum?: number;
|
|
10
|
+
/** Only the boolean form is evaluated; a schema-valued form is unsupported. */
|
|
11
|
+
additionalProperties?: boolean | JsonSchema;
|
|
9
12
|
description?: string;
|
|
10
13
|
title?: string;
|
|
11
14
|
[key: string]: unknown;
|
|
12
15
|
};
|
|
16
|
+
export declare const JSON_SCHEMA_TYPES: {
|
|
17
|
+
readonly string: "string";
|
|
18
|
+
readonly number: "number";
|
|
19
|
+
readonly integer: "integer";
|
|
20
|
+
readonly boolean: "boolean";
|
|
21
|
+
readonly object: "object";
|
|
22
|
+
readonly array: "array";
|
|
23
|
+
readonly null: "null";
|
|
24
|
+
};
|
|
13
25
|
/** Keywords `validateAgainstSchema` actually evaluates. */
|
|
14
26
|
export declare const SUPPORTED_SCHEMA_KEYWORDS: ReadonlySet<string>;
|
|
15
27
|
/**
|
|
16
28
|
* Allowed on inputSchema but never evaluated (tools/list / generator metadata).
|
|
17
|
-
* Semantically-enforcing keywords (`pattern`, `
|
|
18
|
-
*
|
|
29
|
+
* Semantically-enforcing keywords (`pattern`, `oneOf`, …) are not ignored —
|
|
30
|
+
* with `validateArgs: true` they throw at construction.
|
|
19
31
|
*/
|
|
20
32
|
export declare const IGNORED_SCHEMA_KEYWORDS: ReadonlySet<string>;
|
|
21
33
|
/**
|
|
@@ -23,15 +35,15 @@ export declare const IGNORED_SCHEMA_KEYWORDS: ReadonlySet<string>;
|
|
|
23
35
|
* Walks nested `properties` / `items`.
|
|
24
36
|
*/
|
|
25
37
|
export declare const unsupportedKeywords: (schema: JsonSchema, path?: string) => string[];
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Paths where `properties`/`required` implies an object shape but `type`
|
|
40
|
+
* doesn't say so — absent, or a type/union without `"object"`. Such a
|
|
41
|
+
* schema would otherwise accept any input, `{}` included. Under
|
|
42
|
+
* `validateArgs: true` this throws at construction; `validateNode`'s
|
|
43
|
+
* dispatch on the value's runtime type is the backstop for schemas that
|
|
44
|
+
* reach validation unchecked.
|
|
45
|
+
*/
|
|
46
|
+
export declare const missingObjectType: (schema: JsonSchema, path?: string) => string[];
|
|
35
47
|
/** Minimal JSON Schema subset used by MCP tool inputSchema. Empty = valid. */
|
|
36
48
|
export declare const validateAgainstSchema: (value: unknown, schema: JsonSchema) => string[];
|
|
37
49
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/mcp/validate.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,oBAAoB,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;;;CAQpB,CAAC;AAkBX,2DAA2D;AAC3D,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,MAAM,CASxD,CAAC;AAUH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAYtD,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,UAAU,EAAE,aAAa,KAAG,MAAM,EAU7E,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,UAAU,EAAE,aAAa,KAAG,MAAM,EAS3E,CAAC;AAiHF,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,GAAI,OAAO,OAAO,EAAE,QAAQ,UAAU,KAAG,MAAM,EAC5C,CAAC"}
|