@ttoss/http-server-mcp 0.22.0 → 0.23.1
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 +36 -0
- package/dist/index.cjs +119 -96
- package/dist/index.d.cts +96 -78
- package/dist/index.d.mts +97 -79
- package/dist/index.mjs +119 -96
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -266,6 +266,41 @@ mcpServer.registerTool(
|
|
|
266
266
|
|
|
267
267
|
Cognito encodes scopes as a space-separated string in `payload.scope` (e.g. `"openid mcp:access admin"`).
|
|
268
268
|
|
|
269
|
+
### Resource indicator validation (RFC 8707)
|
|
270
|
+
|
|
271
|
+
`requiredScopes` checks _what_ a token can do; `resourceIndicator` checks that the token was minted _for this server_ in the first place. Without it, a token issued by your authorization server for a different resource (another API, another MCP server) would still pass verification here as long as the signature checks out — the classic confused-deputy risk RFC 8707 exists to close.
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
createMcpRouter(mcpServer, {
|
|
275
|
+
auth: {
|
|
276
|
+
cognitoUserPool: { userPoolId: '...', clientId: '...' },
|
|
277
|
+
resourceIndicator: 'https://mcp.example.com',
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The verified token's `aud` claim must include at least one of the configured values (a single string or an array of strings, for servers reachable under multiple hostnames), or the request receives `401 Unauthorized`. This applies uniformly regardless of the verification method — `cognitoUserPool`, a custom `verifyToken`, or `@ttoss/auth-core/oidc`'s `createOidcVerifier` below.
|
|
283
|
+
|
|
284
|
+
### OIDC providers (Entra ID, Okta, Auth0, …)
|
|
285
|
+
|
|
286
|
+
For any standards-compliant OIDC provider beyond Cognito, use `createOidcVerifier` from `@ttoss/auth-core/oidc`. It discovers the provider's signing keys from its `/.well-known/openid-configuration` document — no manual JWKS URL, no hand-rolled discovery:
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { createOidcVerifier } from '@ttoss/auth-core/oidc';
|
|
290
|
+
import { createMcpRouter } from '@ttoss/http-server-mcp';
|
|
291
|
+
|
|
292
|
+
const mcpRouter = createMcpRouter(mcpServer, {
|
|
293
|
+
auth: {
|
|
294
|
+
verifyToken: createOidcVerifier({
|
|
295
|
+
issuer: 'https://login.microsoftonline.com/<tenant>/v2.0',
|
|
296
|
+
}),
|
|
297
|
+
resourceIndicator: 'https://mcp.example.com',
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
`createOidcVerifier` deliberately does not validate `aud` itself — pass `resourceIndicator` alongside it, as shown, so audience validation stays consistent across every auth method this router supports. See the [`@ttoss/auth-core` README](https://ttoss.dev/docs/modules/packages/auth-core) for details on key caching and rotation.
|
|
303
|
+
|
|
269
304
|
### OAuth Protected Resource Metadata
|
|
270
305
|
|
|
271
306
|
MCP clients (Claude, Cursor, etc.) fetch `/.well-known/oauth-protected-resource` to discover which authorization server issues tokens for your MCP server. The endpoint must be **unauthenticated** — MCP clients call it before they have a token.
|
|
@@ -460,6 +495,7 @@ Creates a Koa router configured to handle MCP protocol requests.
|
|
|
460
495
|
- `auth.resourceServerUrl` + `auth.authorizationServerUrl` — Enable `/.well-known/oauth-protected-resource`; the metadata `resource` is set to `resourceServerUrl + path` so clients following `resource` land on the actual MCP endpoint
|
|
461
496
|
- `auth.publicMethods` — JSON-RPC methods that bypass verification (default `['initialize', 'tools/list']`)
|
|
462
497
|
- `auth.resourceMetadataUrl` — Emit RFC 9728 `WWW-Authenticate: Bearer resource_metadata="…"` on 401
|
|
498
|
+
- `auth.resourceIndicator` — Expected `aud` value(s) (RFC 8707); rejects tokens minted for a different resource. See [Resource indicator validation](#resource-indicator-validation-rfc-8707)
|
|
463
499
|
|
|
464
500
|
**Returns:** `Router` — Koa router instance
|
|
465
501
|
|
package/dist/index.cjs
CHANGED
|
@@ -6,8 +6,8 @@ let _modelcontextprotocol_sdk_server_streamableHttp_js = require("@modelcontextp
|
|
|
6
6
|
let _ttoss_auth_core_amazon_cognito = require("@ttoss/auth-core/amazon-cognito");
|
|
7
7
|
let _ttoss_http_server = require("@ttoss/http-server");
|
|
8
8
|
let _ttoss_http_server_auth = require("@ttoss/http-server-auth");
|
|
9
|
-
let zod = require("zod");
|
|
10
9
|
let node_async_hooks = require("node:async_hooks");
|
|
10
|
+
let zod = require("zod");
|
|
11
11
|
let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
12
12
|
|
|
13
13
|
//#region src/context.ts
|
|
@@ -24,6 +24,93 @@ var getIdentity = () => {
|
|
|
24
24
|
return requestContextStore.getStore()?.identity;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/registerToolFromSchema.ts
|
|
29
|
+
var rawSchemaRegistryMap = /* @__PURE__ */new WeakMap();
|
|
30
|
+
var patchedServerSet = /* @__PURE__ */new WeakSet();
|
|
31
|
+
/**
|
|
32
|
+
* Registers a tool on an MCP server using a **plain JSON Schema** object for
|
|
33
|
+
* `inputSchema` instead of a Zod shape.
|
|
34
|
+
*
|
|
35
|
+
* This is useful when tool definitions are shared between the MCP server and an
|
|
36
|
+
* AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
|
|
37
|
+
* plain JSON Schema at runtime. Using this helper eliminates the lossy
|
|
38
|
+
* JSON-Schema→Zod conversion that would otherwise be required.
|
|
39
|
+
*
|
|
40
|
+
* Internally the helper:
|
|
41
|
+
* 1. Registers the tool via the standard `McpServer.registerTool` API using a
|
|
42
|
+
* Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
|
|
43
|
+
* `tools/call` handler correctly routes requests and delivers raw args to
|
|
44
|
+
* your handler.
|
|
45
|
+
* 2. Stores the original JSON Schema and patches the `tools/list` response
|
|
46
|
+
* handler so clients receive the verbatim JSON Schema over the wire.
|
|
47
|
+
*
|
|
48
|
+
* @param server - The `McpServer` instance to register the tool on.
|
|
49
|
+
* @param params - Tool configuration including name, description, inputSchema,
|
|
50
|
+
* and handler.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
|
|
55
|
+
*
|
|
56
|
+
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
57
|
+
*
|
|
58
|
+
* registerToolFromSchema(server, {
|
|
59
|
+
* name: 'get-project',
|
|
60
|
+
* description: 'Get a project by ID',
|
|
61
|
+
* inputSchema: {
|
|
62
|
+
* type: 'object',
|
|
63
|
+
* properties: { id: { type: 'string', description: 'Project public ID' } },
|
|
64
|
+
* required: ['id'],
|
|
65
|
+
* },
|
|
66
|
+
* handler: async ({ id }) => ({
|
|
67
|
+
* content: [{ type: 'text', text: `Project: ${id}` }],
|
|
68
|
+
* }),
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
var registerToolFromSchema = (server, params) => {
|
|
73
|
+
const {
|
|
74
|
+
name,
|
|
75
|
+
description,
|
|
76
|
+
inputSchema = {
|
|
77
|
+
type: "object",
|
|
78
|
+
properties: {}
|
|
79
|
+
},
|
|
80
|
+
handler
|
|
81
|
+
} = params;
|
|
82
|
+
if (!rawSchemaRegistryMap.has(server)) rawSchemaRegistryMap.set(server, /* @__PURE__ */new Map());
|
|
83
|
+
rawSchemaRegistryMap.get(server).set(name, inputSchema);
|
|
84
|
+
server.registerTool(name, {
|
|
85
|
+
description,
|
|
86
|
+
inputSchema: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
87
|
+
}, async args => {
|
|
88
|
+
return handler(args);
|
|
89
|
+
});
|
|
90
|
+
if (!patchedServerSet.has(server)) {
|
|
91
|
+
patchedServerSet.add(server);
|
|
92
|
+
const rawServer = server.server;
|
|
93
|
+
const origHandler = rawServer?._requestHandlers?.get("tools/list");
|
|
94
|
+
if (!origHandler && process.env.NODE_ENV !== "production") console.warn("[registerToolFromSchema] Could not patch tools/list — internal MCP SDK structure may have changed. The tool will still be callable, but tools/list may return a Zod-derived schema instead of the verbatim JSON Schema.");
|
|
95
|
+
if (origHandler) rawServer._requestHandlers.set("tools/list", async (rawRequest, extra) => {
|
|
96
|
+
const result = await origHandler(rawRequest, extra);
|
|
97
|
+
const schemas = rawSchemaRegistryMap.get(server);
|
|
98
|
+
if (!schemas) return result;
|
|
99
|
+
return {
|
|
100
|
+
...result,
|
|
101
|
+
tools: result.tools.map(tool => {
|
|
102
|
+
const raw = schemas.get(tool.name);
|
|
103
|
+
if (raw !== void 0) return {
|
|
104
|
+
...tool,
|
|
105
|
+
inputSchema: raw
|
|
106
|
+
};
|
|
107
|
+
return tool;
|
|
108
|
+
})
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
27
114
|
//#endregion
|
|
28
115
|
//#region src/createGatedToolRegistrar.ts
|
|
29
116
|
var toolError = message => {
|
|
@@ -145,19 +232,39 @@ var createGatedToolRegistrar = ({
|
|
|
145
232
|
//#region src/index.ts
|
|
146
233
|
/** MCP lifecycle/discovery methods reachable before a client authenticates. */
|
|
147
234
|
var DEFAULT_PUBLIC_METHODS = ["initialize", "tools/list"];
|
|
235
|
+
/**
|
|
236
|
+
* Asserts that a verified token's `aud` claim includes at least one of the
|
|
237
|
+
* expected resource indicator values. `aud` may be a single string or an
|
|
238
|
+
* array of strings per the JWT spec (RFC 7519); both forms are checked.
|
|
239
|
+
*/
|
|
240
|
+
var assertResourceIndicator = (payload, resourceIndicator) => {
|
|
241
|
+
const expected = Array.isArray(resourceIndicator) ? resourceIndicator : [resourceIndicator];
|
|
242
|
+
const aud = payload?.aud;
|
|
243
|
+
if (!(typeof aud === "string" ? [aud] : Array.isArray(aud) ? aud : []).some(audience => {
|
|
244
|
+
return typeof audience === "string" && expected.includes(audience);
|
|
245
|
+
})) throw new Error(`Token audience does not include the expected resource indicator (expected one of: ${expected.join(", ")}).`);
|
|
246
|
+
};
|
|
148
247
|
/** Builds the token verifier from the MCP auth options. */
|
|
149
248
|
var buildVerifyToken = auth => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
249
|
+
const verify = (() => {
|
|
250
|
+
if (auth.cognitoUserPool) {
|
|
251
|
+
const verifier = _ttoss_auth_core_amazon_cognito.CognitoJwtVerifier.create({
|
|
252
|
+
tokenUse: "access",
|
|
253
|
+
...auth.cognitoUserPool
|
|
254
|
+
});
|
|
255
|
+
return token => {
|
|
256
|
+
return verifier.verify(token);
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
if (auth.verifyToken) return auth.verifyToken;
|
|
260
|
+
throw new Error("McpAuthOptions requires either cognitoUserPool or verifyToken");
|
|
261
|
+
})();
|
|
262
|
+
if (!auth.resourceIndicator) return verify;
|
|
263
|
+
return async token => {
|
|
264
|
+
const payload = await verify(token);
|
|
265
|
+
assertResourceIndicator(payload, auth.resourceIndicator);
|
|
266
|
+
return payload;
|
|
267
|
+
};
|
|
161
268
|
};
|
|
162
269
|
/**
|
|
163
270
|
* Generic HTTP helper for use inside MCP tool handlers.
|
|
@@ -440,90 +547,6 @@ var createMcpRouter = (server, options = {}) => {
|
|
|
440
547
|
}
|
|
441
548
|
return router;
|
|
442
549
|
};
|
|
443
|
-
var rawSchemaRegistryMap = /* @__PURE__ */new WeakMap();
|
|
444
|
-
var patchedServerSet = /* @__PURE__ */new WeakSet();
|
|
445
|
-
/**
|
|
446
|
-
* Registers a tool on an MCP server using a **plain JSON Schema** object for
|
|
447
|
-
* `inputSchema` instead of a Zod shape.
|
|
448
|
-
*
|
|
449
|
-
* This is useful when tool definitions are shared between the MCP server and an
|
|
450
|
-
* AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
|
|
451
|
-
* plain JSON Schema at runtime. Using this helper eliminates the lossy
|
|
452
|
-
* JSON-Schema→Zod conversion that would otherwise be required.
|
|
453
|
-
*
|
|
454
|
-
* Internally the helper:
|
|
455
|
-
* 1. Registers the tool via the standard `McpServer.registerTool` API using a
|
|
456
|
-
* Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
|
|
457
|
-
* `tools/call` handler correctly routes requests and delivers raw args to
|
|
458
|
-
* your handler.
|
|
459
|
-
* 2. Stores the original JSON Schema and patches the `tools/list` response
|
|
460
|
-
* handler so clients receive the verbatim JSON Schema over the wire.
|
|
461
|
-
*
|
|
462
|
-
* @param server - The `McpServer` instance to register the tool on.
|
|
463
|
-
* @param params - Tool configuration including name, description, inputSchema,
|
|
464
|
-
* and handler.
|
|
465
|
-
*
|
|
466
|
-
* @example
|
|
467
|
-
* ```typescript
|
|
468
|
-
* import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
|
|
469
|
-
*
|
|
470
|
-
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
471
|
-
*
|
|
472
|
-
* registerToolFromSchema(server, {
|
|
473
|
-
* name: 'get-project',
|
|
474
|
-
* description: 'Get a project by ID',
|
|
475
|
-
* inputSchema: {
|
|
476
|
-
* type: 'object',
|
|
477
|
-
* properties: { id: { type: 'string', description: 'Project public ID' } },
|
|
478
|
-
* required: ['id'],
|
|
479
|
-
* },
|
|
480
|
-
* handler: async ({ id }) => ({
|
|
481
|
-
* content: [{ type: 'text', text: `Project: ${id}` }],
|
|
482
|
-
* }),
|
|
483
|
-
* });
|
|
484
|
-
* ```
|
|
485
|
-
*/
|
|
486
|
-
var registerToolFromSchema = (server, params) => {
|
|
487
|
-
const {
|
|
488
|
-
name,
|
|
489
|
-
description,
|
|
490
|
-
inputSchema = {
|
|
491
|
-
type: "object",
|
|
492
|
-
properties: {}
|
|
493
|
-
},
|
|
494
|
-
handler
|
|
495
|
-
} = params;
|
|
496
|
-
if (!rawSchemaRegistryMap.has(server)) rawSchemaRegistryMap.set(server, /* @__PURE__ */new Map());
|
|
497
|
-
rawSchemaRegistryMap.get(server).set(name, inputSchema);
|
|
498
|
-
server.registerTool(name, {
|
|
499
|
-
description,
|
|
500
|
-
inputSchema: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
501
|
-
}, async args => {
|
|
502
|
-
return handler(args);
|
|
503
|
-
});
|
|
504
|
-
if (!patchedServerSet.has(server)) {
|
|
505
|
-
patchedServerSet.add(server);
|
|
506
|
-
const rawServer = server.server;
|
|
507
|
-
const origHandler = rawServer?._requestHandlers?.get("tools/list");
|
|
508
|
-
if (!origHandler && process.env.NODE_ENV !== "production") console.warn("[registerToolFromSchema] Could not patch tools/list — internal MCP SDK structure may have changed. The tool will still be callable, but tools/list may return a Zod-derived schema instead of the verbatim JSON Schema.");
|
|
509
|
-
if (origHandler) rawServer._requestHandlers.set("tools/list", async (rawRequest, extra) => {
|
|
510
|
-
const result = await origHandler(rawRequest, extra);
|
|
511
|
-
const schemas = rawSchemaRegistryMap.get(server);
|
|
512
|
-
if (!schemas) return result;
|
|
513
|
-
return {
|
|
514
|
-
...result,
|
|
515
|
-
tools: result.tools.map(tool => {
|
|
516
|
-
const raw = schemas.get(tool.name);
|
|
517
|
-
if (raw !== void 0) return {
|
|
518
|
-
...tool,
|
|
519
|
-
inputSchema: raw
|
|
520
|
-
};
|
|
521
|
-
return tool;
|
|
522
|
-
})
|
|
523
|
-
};
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
};
|
|
527
550
|
|
|
528
551
|
//#endregion
|
|
529
552
|
Object.defineProperty(exports, 'McpServer', {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { McpServer, McpServer as McpServer$1 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
-
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
5
4
|
import { Router } from "@ttoss/http-server";
|
|
6
5
|
import accepts from "accepts";
|
|
7
6
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -17,6 +16,7 @@ import compose from "koa-compose";
|
|
|
17
16
|
import { ListenOptions, Socket } from "net";
|
|
18
17
|
import { ParsedUrlQuery } from "querystring";
|
|
19
18
|
import * as url from "url";
|
|
19
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
20
20
|
import { z } from "zod";
|
|
21
21
|
|
|
22
22
|
//#region ../../node_modules/.pnpm/@types+koa@3.0.3/node_modules/@types/koa/index.d.ts
|
|
@@ -676,6 +676,84 @@ declare namespace Application {
|
|
|
676
676
|
*/
|
|
677
677
|
declare const getIdentity: <T = unknown>() => T | undefined;
|
|
678
678
|
//#endregion
|
|
679
|
+
//#region src/registerToolFromSchema.d.ts
|
|
680
|
+
/**
|
|
681
|
+
* A plain JSON Schema object (draft-07 compatible) describing the shape of a
|
|
682
|
+
* tool's input. Used with {@link registerToolFromSchema} as an alternative to
|
|
683
|
+
* providing a Zod shape, enabling lossless round-trips for schemas that contain
|
|
684
|
+
* features not expressible in Zod v3 (`anyOf`, `$ref`, `pattern`, `allOf`, …).
|
|
685
|
+
*/
|
|
686
|
+
interface JsonObjectSchema {
|
|
687
|
+
type: 'object';
|
|
688
|
+
properties?: Record<string, unknown>;
|
|
689
|
+
required?: string[];
|
|
690
|
+
[key: string]: unknown;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Parameters accepted by {@link registerToolFromSchema}.
|
|
694
|
+
*/
|
|
695
|
+
interface RegisterToolFromSchemaParams {
|
|
696
|
+
/** Unique tool name. */
|
|
697
|
+
name: string;
|
|
698
|
+
/** Human-readable description shown to the AI client. */
|
|
699
|
+
description?: string;
|
|
700
|
+
/**
|
|
701
|
+
* Plain JSON Schema that describes the tool's input object.
|
|
702
|
+
* This schema is forwarded verbatim over the MCP wire protocol, so any
|
|
703
|
+
* JSON Schema feature (`anyOf`, `$ref`, `pattern`, …) is preserved without
|
|
704
|
+
* loss. Defaults to `{ type: 'object', properties: {} }` when omitted.
|
|
705
|
+
*/
|
|
706
|
+
inputSchema?: JsonObjectSchema;
|
|
707
|
+
/**
|
|
708
|
+
* Tool handler invoked when the AI client calls the tool.
|
|
709
|
+
* Receives the raw request arguments as a plain object (no Zod validation is
|
|
710
|
+
* applied, so the shape matches whatever the client sends).
|
|
711
|
+
*/
|
|
712
|
+
handler: (args: Record<string, unknown>) => CallToolResult | Promise<CallToolResult>;
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Registers a tool on an MCP server using a **plain JSON Schema** object for
|
|
716
|
+
* `inputSchema` instead of a Zod shape.
|
|
717
|
+
*
|
|
718
|
+
* This is useful when tool definitions are shared between the MCP server and an
|
|
719
|
+
* AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
|
|
720
|
+
* plain JSON Schema at runtime. Using this helper eliminates the lossy
|
|
721
|
+
* JSON-Schema→Zod conversion that would otherwise be required.
|
|
722
|
+
*
|
|
723
|
+
* Internally the helper:
|
|
724
|
+
* 1. Registers the tool via the standard `McpServer.registerTool` API using a
|
|
725
|
+
* Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
|
|
726
|
+
* `tools/call` handler correctly routes requests and delivers raw args to
|
|
727
|
+
* your handler.
|
|
728
|
+
* 2. Stores the original JSON Schema and patches the `tools/list` response
|
|
729
|
+
* handler so clients receive the verbatim JSON Schema over the wire.
|
|
730
|
+
*
|
|
731
|
+
* @param server - The `McpServer` instance to register the tool on.
|
|
732
|
+
* @param params - Tool configuration including name, description, inputSchema,
|
|
733
|
+
* and handler.
|
|
734
|
+
*
|
|
735
|
+
* @example
|
|
736
|
+
* ```typescript
|
|
737
|
+
* import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
|
|
738
|
+
*
|
|
739
|
+
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
740
|
+
*
|
|
741
|
+
* registerToolFromSchema(server, {
|
|
742
|
+
* name: 'get-project',
|
|
743
|
+
* description: 'Get a project by ID',
|
|
744
|
+
* inputSchema: {
|
|
745
|
+
* type: 'object',
|
|
746
|
+
* properties: { id: { type: 'string', description: 'Project public ID' } },
|
|
747
|
+
* required: ['id'],
|
|
748
|
+
* },
|
|
749
|
+
* handler: async ({ id }) => ({
|
|
750
|
+
* content: [{ type: 'text', text: `Project: ${id}` }],
|
|
751
|
+
* }),
|
|
752
|
+
* });
|
|
753
|
+
* ```
|
|
754
|
+
*/
|
|
755
|
+
declare const registerToolFromSchema: (server: McpServer$1, params: RegisterToolFromSchemaParams) => void;
|
|
756
|
+
//#endregion
|
|
679
757
|
//#region src/createGatedToolRegistrar.d.ts
|
|
680
758
|
/** Resolved identity for a gated tool call. */
|
|
681
759
|
type ToolIdentity = {
|
|
@@ -816,6 +894,22 @@ interface McpAuthOptions {
|
|
|
816
894
|
resourceServerUrl?: string;
|
|
817
895
|
/** URL of the OAuth Authorization Server that issues tokens for this resource. */
|
|
818
896
|
authorizationServerUrl?: string;
|
|
897
|
+
/**
|
|
898
|
+
* Expected audience — the resource indicator (RFC 8707) this MCP server
|
|
899
|
+
* identifies as. When set, the verified token's `aud` claim must include at
|
|
900
|
+
* least one of these values, or the request is rejected with `401`. Without
|
|
901
|
+
* this check, a token minted for a *different* resource but signed by the
|
|
902
|
+
* same authorization server would still be accepted here — the classic
|
|
903
|
+
* confused-deputy risk RFC 8707 exists to close.
|
|
904
|
+
*
|
|
905
|
+
* Applies uniformly regardless of whether verification is done via
|
|
906
|
+
* `cognitoUserPool`, a custom `verifyToken`, or `@ttoss/auth-core/oidc`'s
|
|
907
|
+
* `createOidcVerifier` (which intentionally leaves audience validation to
|
|
908
|
+
* the caller for this reason).
|
|
909
|
+
*
|
|
910
|
+
* @example 'https://mcp.example.com'
|
|
911
|
+
*/
|
|
912
|
+
resourceIndicator?: string | string[];
|
|
819
913
|
}
|
|
820
914
|
/**
|
|
821
915
|
* Options for a single `apiCall` request.
|
|
@@ -1039,81 +1133,5 @@ interface McpRouterOptions {
|
|
|
1039
1133
|
* ```
|
|
1040
1134
|
*/
|
|
1041
1135
|
declare const createMcpRouter: (server: McpServer$1, options?: McpRouterOptions) => Router<Application.DefaultState, Application.DefaultContext>;
|
|
1042
|
-
/**
|
|
1043
|
-
* A plain JSON Schema object (draft-07 compatible) describing the shape of a
|
|
1044
|
-
* tool's input. Used with {@link registerToolFromSchema} as an alternative to
|
|
1045
|
-
* providing a Zod shape, enabling lossless round-trips for schemas that contain
|
|
1046
|
-
* features not expressible in Zod v3 (`anyOf`, `$ref`, `pattern`, `allOf`, …).
|
|
1047
|
-
*/
|
|
1048
|
-
interface JsonObjectSchema {
|
|
1049
|
-
type: 'object';
|
|
1050
|
-
properties?: Record<string, unknown>;
|
|
1051
|
-
required?: string[];
|
|
1052
|
-
[key: string]: unknown;
|
|
1053
|
-
}
|
|
1054
|
-
/**
|
|
1055
|
-
* Parameters accepted by {@link registerToolFromSchema}.
|
|
1056
|
-
*/
|
|
1057
|
-
interface RegisterToolFromSchemaParams {
|
|
1058
|
-
/** Unique tool name. */
|
|
1059
|
-
name: string;
|
|
1060
|
-
/** Human-readable description shown to the AI client. */
|
|
1061
|
-
description?: string;
|
|
1062
|
-
/**
|
|
1063
|
-
* Plain JSON Schema that describes the tool's input object.
|
|
1064
|
-
* This schema is forwarded verbatim over the MCP wire protocol, so any
|
|
1065
|
-
* JSON Schema feature (`anyOf`, `$ref`, `pattern`, …) is preserved without
|
|
1066
|
-
* loss. Defaults to `{ type: 'object', properties: {} }` when omitted.
|
|
1067
|
-
*/
|
|
1068
|
-
inputSchema?: JsonObjectSchema;
|
|
1069
|
-
/**
|
|
1070
|
-
* Tool handler invoked when the AI client calls the tool.
|
|
1071
|
-
* Receives the raw request arguments as a plain object (no Zod validation is
|
|
1072
|
-
* applied, so the shape matches whatever the client sends).
|
|
1073
|
-
*/
|
|
1074
|
-
handler: (args: Record<string, unknown>) => CallToolResult | Promise<CallToolResult>;
|
|
1075
|
-
}
|
|
1076
|
-
/**
|
|
1077
|
-
* Registers a tool on an MCP server using a **plain JSON Schema** object for
|
|
1078
|
-
* `inputSchema` instead of a Zod shape.
|
|
1079
|
-
*
|
|
1080
|
-
* This is useful when tool definitions are shared between the MCP server and an
|
|
1081
|
-
* AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
|
|
1082
|
-
* plain JSON Schema at runtime. Using this helper eliminates the lossy
|
|
1083
|
-
* JSON-Schema→Zod conversion that would otherwise be required.
|
|
1084
|
-
*
|
|
1085
|
-
* Internally the helper:
|
|
1086
|
-
* 1. Registers the tool via the standard `McpServer.registerTool` API using a
|
|
1087
|
-
* Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
|
|
1088
|
-
* `tools/call` handler correctly routes requests and delivers raw args to
|
|
1089
|
-
* your handler.
|
|
1090
|
-
* 2. Stores the original JSON Schema and patches the `tools/list` response
|
|
1091
|
-
* handler so clients receive the verbatim JSON Schema over the wire.
|
|
1092
|
-
*
|
|
1093
|
-
* @param server - The `McpServer` instance to register the tool on.
|
|
1094
|
-
* @param params - Tool configuration including name, description, inputSchema,
|
|
1095
|
-
* and handler.
|
|
1096
|
-
*
|
|
1097
|
-
* @example
|
|
1098
|
-
* ```typescript
|
|
1099
|
-
* import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
|
|
1100
|
-
*
|
|
1101
|
-
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
1102
|
-
*
|
|
1103
|
-
* registerToolFromSchema(server, {
|
|
1104
|
-
* name: 'get-project',
|
|
1105
|
-
* description: 'Get a project by ID',
|
|
1106
|
-
* inputSchema: {
|
|
1107
|
-
* type: 'object',
|
|
1108
|
-
* properties: { id: { type: 'string', description: 'Project public ID' } },
|
|
1109
|
-
* required: ['id'],
|
|
1110
|
-
* },
|
|
1111
|
-
* handler: async ({ id }) => ({
|
|
1112
|
-
* content: [{ type: 'text', text: `Project: ${id}` }],
|
|
1113
|
-
* }),
|
|
1114
|
-
* });
|
|
1115
|
-
* ```
|
|
1116
|
-
*/
|
|
1117
|
-
declare const registerToolFromSchema: (server: McpServer$1, params: RegisterToolFromSchemaParams) => void;
|
|
1118
1136
|
//#endregion
|
|
1119
|
-
export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, RegisterToolFromSchemaParams, type ToolCallContext, type ToolIdentity, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerToolFromSchema, z };
|
|
1137
|
+
export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, type JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, type RegisterToolFromSchemaParams, type ToolCallContext, type ToolIdentity, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerToolFromSchema, z };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { Router } from "@ttoss/http-server";
|
|
4
|
-
import { z } from "zod";
|
|
5
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
import { z } from "zod";
|
|
6
6
|
import { McpServer, McpServer as McpServer$1 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
-
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
8
7
|
import accepts from "accepts";
|
|
9
8
|
import { AsyncLocalStorage as AsyncLocalStorage$1 } from "async_hooks";
|
|
10
9
|
import Cookies from "cookies";
|
|
@@ -19,6 +18,7 @@ import compose from "koa-compose";
|
|
|
19
18
|
import { ListenOptions, Socket } from "net";
|
|
20
19
|
import { ParsedUrlQuery } from "querystring";
|
|
21
20
|
import * as url from "url";
|
|
21
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
22
22
|
|
|
23
23
|
//#region ../../node_modules/.pnpm/@types+koa@3.0.3/node_modules/@types/koa/index.d.ts
|
|
24
24
|
declare interface ContextDelegatedRequest {
|
|
@@ -677,6 +677,84 @@ declare namespace Application {
|
|
|
677
677
|
*/
|
|
678
678
|
declare const getIdentity: <T = unknown>() => T | undefined;
|
|
679
679
|
//#endregion
|
|
680
|
+
//#region src/registerToolFromSchema.d.ts
|
|
681
|
+
/**
|
|
682
|
+
* A plain JSON Schema object (draft-07 compatible) describing the shape of a
|
|
683
|
+
* tool's input. Used with {@link registerToolFromSchema} as an alternative to
|
|
684
|
+
* providing a Zod shape, enabling lossless round-trips for schemas that contain
|
|
685
|
+
* features not expressible in Zod v3 (`anyOf`, `$ref`, `pattern`, `allOf`, …).
|
|
686
|
+
*/
|
|
687
|
+
interface JsonObjectSchema {
|
|
688
|
+
type: 'object';
|
|
689
|
+
properties?: Record<string, unknown>;
|
|
690
|
+
required?: string[];
|
|
691
|
+
[key: string]: unknown;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Parameters accepted by {@link registerToolFromSchema}.
|
|
695
|
+
*/
|
|
696
|
+
interface RegisterToolFromSchemaParams {
|
|
697
|
+
/** Unique tool name. */
|
|
698
|
+
name: string;
|
|
699
|
+
/** Human-readable description shown to the AI client. */
|
|
700
|
+
description?: string;
|
|
701
|
+
/**
|
|
702
|
+
* Plain JSON Schema that describes the tool's input object.
|
|
703
|
+
* This schema is forwarded verbatim over the MCP wire protocol, so any
|
|
704
|
+
* JSON Schema feature (`anyOf`, `$ref`, `pattern`, …) is preserved without
|
|
705
|
+
* loss. Defaults to `{ type: 'object', properties: {} }` when omitted.
|
|
706
|
+
*/
|
|
707
|
+
inputSchema?: JsonObjectSchema;
|
|
708
|
+
/**
|
|
709
|
+
* Tool handler invoked when the AI client calls the tool.
|
|
710
|
+
* Receives the raw request arguments as a plain object (no Zod validation is
|
|
711
|
+
* applied, so the shape matches whatever the client sends).
|
|
712
|
+
*/
|
|
713
|
+
handler: (args: Record<string, unknown>) => CallToolResult | Promise<CallToolResult>;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Registers a tool on an MCP server using a **plain JSON Schema** object for
|
|
717
|
+
* `inputSchema` instead of a Zod shape.
|
|
718
|
+
*
|
|
719
|
+
* This is useful when tool definitions are shared between the MCP server and an
|
|
720
|
+
* AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
|
|
721
|
+
* plain JSON Schema at runtime. Using this helper eliminates the lossy
|
|
722
|
+
* JSON-Schema→Zod conversion that would otherwise be required.
|
|
723
|
+
*
|
|
724
|
+
* Internally the helper:
|
|
725
|
+
* 1. Registers the tool via the standard `McpServer.registerTool` API using a
|
|
726
|
+
* Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
|
|
727
|
+
* `tools/call` handler correctly routes requests and delivers raw args to
|
|
728
|
+
* your handler.
|
|
729
|
+
* 2. Stores the original JSON Schema and patches the `tools/list` response
|
|
730
|
+
* handler so clients receive the verbatim JSON Schema over the wire.
|
|
731
|
+
*
|
|
732
|
+
* @param server - The `McpServer` instance to register the tool on.
|
|
733
|
+
* @param params - Tool configuration including name, description, inputSchema,
|
|
734
|
+
* and handler.
|
|
735
|
+
*
|
|
736
|
+
* @example
|
|
737
|
+
* ```typescript
|
|
738
|
+
* import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
|
|
739
|
+
*
|
|
740
|
+
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
741
|
+
*
|
|
742
|
+
* registerToolFromSchema(server, {
|
|
743
|
+
* name: 'get-project',
|
|
744
|
+
* description: 'Get a project by ID',
|
|
745
|
+
* inputSchema: {
|
|
746
|
+
* type: 'object',
|
|
747
|
+
* properties: { id: { type: 'string', description: 'Project public ID' } },
|
|
748
|
+
* required: ['id'],
|
|
749
|
+
* },
|
|
750
|
+
* handler: async ({ id }) => ({
|
|
751
|
+
* content: [{ type: 'text', text: `Project: ${id}` }],
|
|
752
|
+
* }),
|
|
753
|
+
* });
|
|
754
|
+
* ```
|
|
755
|
+
*/
|
|
756
|
+
declare const registerToolFromSchema: (server: McpServer$1, params: RegisterToolFromSchemaParams) => void;
|
|
757
|
+
//#endregion
|
|
680
758
|
//#region src/createGatedToolRegistrar.d.ts
|
|
681
759
|
/** Resolved identity for a gated tool call. */
|
|
682
760
|
type ToolIdentity = {
|
|
@@ -817,6 +895,22 @@ interface McpAuthOptions {
|
|
|
817
895
|
resourceServerUrl?: string;
|
|
818
896
|
/** URL of the OAuth Authorization Server that issues tokens for this resource. */
|
|
819
897
|
authorizationServerUrl?: string;
|
|
898
|
+
/**
|
|
899
|
+
* Expected audience — the resource indicator (RFC 8707) this MCP server
|
|
900
|
+
* identifies as. When set, the verified token's `aud` claim must include at
|
|
901
|
+
* least one of these values, or the request is rejected with `401`. Without
|
|
902
|
+
* this check, a token minted for a *different* resource but signed by the
|
|
903
|
+
* same authorization server would still be accepted here — the classic
|
|
904
|
+
* confused-deputy risk RFC 8707 exists to close.
|
|
905
|
+
*
|
|
906
|
+
* Applies uniformly regardless of whether verification is done via
|
|
907
|
+
* `cognitoUserPool`, a custom `verifyToken`, or `@ttoss/auth-core/oidc`'s
|
|
908
|
+
* `createOidcVerifier` (which intentionally leaves audience validation to
|
|
909
|
+
* the caller for this reason).
|
|
910
|
+
*
|
|
911
|
+
* @example 'https://mcp.example.com'
|
|
912
|
+
*/
|
|
913
|
+
resourceIndicator?: string | string[];
|
|
820
914
|
}
|
|
821
915
|
/**
|
|
822
916
|
* Options for a single `apiCall` request.
|
|
@@ -1040,81 +1134,5 @@ interface McpRouterOptions {
|
|
|
1040
1134
|
* ```
|
|
1041
1135
|
*/
|
|
1042
1136
|
declare const createMcpRouter: (server: McpServer$1, options?: McpRouterOptions) => Router<Application.DefaultState, Application.DefaultContext>;
|
|
1043
|
-
/**
|
|
1044
|
-
* A plain JSON Schema object (draft-07 compatible) describing the shape of a
|
|
1045
|
-
* tool's input. Used with {@link registerToolFromSchema} as an alternative to
|
|
1046
|
-
* providing a Zod shape, enabling lossless round-trips for schemas that contain
|
|
1047
|
-
* features not expressible in Zod v3 (`anyOf`, `$ref`, `pattern`, `allOf`, …).
|
|
1048
|
-
*/
|
|
1049
|
-
interface JsonObjectSchema {
|
|
1050
|
-
type: 'object';
|
|
1051
|
-
properties?: Record<string, unknown>;
|
|
1052
|
-
required?: string[];
|
|
1053
|
-
[key: string]: unknown;
|
|
1054
|
-
}
|
|
1055
|
-
/**
|
|
1056
|
-
* Parameters accepted by {@link registerToolFromSchema}.
|
|
1057
|
-
*/
|
|
1058
|
-
interface RegisterToolFromSchemaParams {
|
|
1059
|
-
/** Unique tool name. */
|
|
1060
|
-
name: string;
|
|
1061
|
-
/** Human-readable description shown to the AI client. */
|
|
1062
|
-
description?: string;
|
|
1063
|
-
/**
|
|
1064
|
-
* Plain JSON Schema that describes the tool's input object.
|
|
1065
|
-
* This schema is forwarded verbatim over the MCP wire protocol, so any
|
|
1066
|
-
* JSON Schema feature (`anyOf`, `$ref`, `pattern`, …) is preserved without
|
|
1067
|
-
* loss. Defaults to `{ type: 'object', properties: {} }` when omitted.
|
|
1068
|
-
*/
|
|
1069
|
-
inputSchema?: JsonObjectSchema;
|
|
1070
|
-
/**
|
|
1071
|
-
* Tool handler invoked when the AI client calls the tool.
|
|
1072
|
-
* Receives the raw request arguments as a plain object (no Zod validation is
|
|
1073
|
-
* applied, so the shape matches whatever the client sends).
|
|
1074
|
-
*/
|
|
1075
|
-
handler: (args: Record<string, unknown>) => CallToolResult | Promise<CallToolResult>;
|
|
1076
|
-
}
|
|
1077
|
-
/**
|
|
1078
|
-
* Registers a tool on an MCP server using a **plain JSON Schema** object for
|
|
1079
|
-
* `inputSchema` instead of a Zod shape.
|
|
1080
|
-
*
|
|
1081
|
-
* This is useful when tool definitions are shared between the MCP server and an
|
|
1082
|
-
* AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
|
|
1083
|
-
* plain JSON Schema at runtime. Using this helper eliminates the lossy
|
|
1084
|
-
* JSON-Schema→Zod conversion that would otherwise be required.
|
|
1085
|
-
*
|
|
1086
|
-
* Internally the helper:
|
|
1087
|
-
* 1. Registers the tool via the standard `McpServer.registerTool` API using a
|
|
1088
|
-
* Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
|
|
1089
|
-
* `tools/call` handler correctly routes requests and delivers raw args to
|
|
1090
|
-
* your handler.
|
|
1091
|
-
* 2. Stores the original JSON Schema and patches the `tools/list` response
|
|
1092
|
-
* handler so clients receive the verbatim JSON Schema over the wire.
|
|
1093
|
-
*
|
|
1094
|
-
* @param server - The `McpServer` instance to register the tool on.
|
|
1095
|
-
* @param params - Tool configuration including name, description, inputSchema,
|
|
1096
|
-
* and handler.
|
|
1097
|
-
*
|
|
1098
|
-
* @example
|
|
1099
|
-
* ```typescript
|
|
1100
|
-
* import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
|
|
1101
|
-
*
|
|
1102
|
-
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
1103
|
-
*
|
|
1104
|
-
* registerToolFromSchema(server, {
|
|
1105
|
-
* name: 'get-project',
|
|
1106
|
-
* description: 'Get a project by ID',
|
|
1107
|
-
* inputSchema: {
|
|
1108
|
-
* type: 'object',
|
|
1109
|
-
* properties: { id: { type: 'string', description: 'Project public ID' } },
|
|
1110
|
-
* required: ['id'],
|
|
1111
|
-
* },
|
|
1112
|
-
* handler: async ({ id }) => ({
|
|
1113
|
-
* content: [{ type: 'text', text: `Project: ${id}` }],
|
|
1114
|
-
* }),
|
|
1115
|
-
* });
|
|
1116
|
-
* ```
|
|
1117
|
-
*/
|
|
1118
|
-
declare const registerToolFromSchema: (server: McpServer$1, params: RegisterToolFromSchemaParams) => void;
|
|
1119
1137
|
//#endregion
|
|
1120
|
-
export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, RegisterToolFromSchemaParams, type ToolCallContext, type ToolIdentity, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerToolFromSchema, z };
|
|
1138
|
+
export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, type JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, type RegisterToolFromSchemaParams, type ToolCallContext, type ToolIdentity, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerToolFromSchema, z };
|
package/dist/index.mjs
CHANGED
|
@@ -3,8 +3,8 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
|
|
|
3
3
|
import { CognitoJwtVerifier } from "@ttoss/auth-core/amazon-cognito";
|
|
4
4
|
import { Router } from "@ttoss/http-server";
|
|
5
5
|
import { authMiddleware } from "@ttoss/http-server-auth";
|
|
6
|
-
import { z, z as z$1 } from "zod";
|
|
7
6
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
|
+
import { z, z as z$1 } from "zod";
|
|
8
8
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
9
|
|
|
10
10
|
//#region src/context.ts
|
|
@@ -21,6 +21,93 @@ var getIdentity = () => {
|
|
|
21
21
|
return requestContextStore.getStore()?.identity;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/registerToolFromSchema.ts
|
|
26
|
+
var rawSchemaRegistryMap = /* @__PURE__ */new WeakMap();
|
|
27
|
+
var patchedServerSet = /* @__PURE__ */new WeakSet();
|
|
28
|
+
/**
|
|
29
|
+
* Registers a tool on an MCP server using a **plain JSON Schema** object for
|
|
30
|
+
* `inputSchema` instead of a Zod shape.
|
|
31
|
+
*
|
|
32
|
+
* This is useful when tool definitions are shared between the MCP server and an
|
|
33
|
+
* AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
|
|
34
|
+
* plain JSON Schema at runtime. Using this helper eliminates the lossy
|
|
35
|
+
* JSON-Schema→Zod conversion that would otherwise be required.
|
|
36
|
+
*
|
|
37
|
+
* Internally the helper:
|
|
38
|
+
* 1. Registers the tool via the standard `McpServer.registerTool` API using a
|
|
39
|
+
* Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
|
|
40
|
+
* `tools/call` handler correctly routes requests and delivers raw args to
|
|
41
|
+
* your handler.
|
|
42
|
+
* 2. Stores the original JSON Schema and patches the `tools/list` response
|
|
43
|
+
* handler so clients receive the verbatim JSON Schema over the wire.
|
|
44
|
+
*
|
|
45
|
+
* @param server - The `McpServer` instance to register the tool on.
|
|
46
|
+
* @param params - Tool configuration including name, description, inputSchema,
|
|
47
|
+
* and handler.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
|
|
52
|
+
*
|
|
53
|
+
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
54
|
+
*
|
|
55
|
+
* registerToolFromSchema(server, {
|
|
56
|
+
* name: 'get-project',
|
|
57
|
+
* description: 'Get a project by ID',
|
|
58
|
+
* inputSchema: {
|
|
59
|
+
* type: 'object',
|
|
60
|
+
* properties: { id: { type: 'string', description: 'Project public ID' } },
|
|
61
|
+
* required: ['id'],
|
|
62
|
+
* },
|
|
63
|
+
* handler: async ({ id }) => ({
|
|
64
|
+
* content: [{ type: 'text', text: `Project: ${id}` }],
|
|
65
|
+
* }),
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
var registerToolFromSchema = (server, params) => {
|
|
70
|
+
const {
|
|
71
|
+
name,
|
|
72
|
+
description,
|
|
73
|
+
inputSchema = {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: {}
|
|
76
|
+
},
|
|
77
|
+
handler
|
|
78
|
+
} = params;
|
|
79
|
+
if (!rawSchemaRegistryMap.has(server)) rawSchemaRegistryMap.set(server, /* @__PURE__ */new Map());
|
|
80
|
+
rawSchemaRegistryMap.get(server).set(name, inputSchema);
|
|
81
|
+
server.registerTool(name, {
|
|
82
|
+
description,
|
|
83
|
+
inputSchema: z$1.record(z$1.string(), z$1.unknown())
|
|
84
|
+
}, async args => {
|
|
85
|
+
return handler(args);
|
|
86
|
+
});
|
|
87
|
+
if (!patchedServerSet.has(server)) {
|
|
88
|
+
patchedServerSet.add(server);
|
|
89
|
+
const rawServer = server.server;
|
|
90
|
+
const origHandler = rawServer?._requestHandlers?.get("tools/list");
|
|
91
|
+
if (!origHandler && process.env.NODE_ENV !== "production") console.warn("[registerToolFromSchema] Could not patch tools/list — internal MCP SDK structure may have changed. The tool will still be callable, but tools/list may return a Zod-derived schema instead of the verbatim JSON Schema.");
|
|
92
|
+
if (origHandler) rawServer._requestHandlers.set("tools/list", async (rawRequest, extra) => {
|
|
93
|
+
const result = await origHandler(rawRequest, extra);
|
|
94
|
+
const schemas = rawSchemaRegistryMap.get(server);
|
|
95
|
+
if (!schemas) return result;
|
|
96
|
+
return {
|
|
97
|
+
...result,
|
|
98
|
+
tools: result.tools.map(tool => {
|
|
99
|
+
const raw = schemas.get(tool.name);
|
|
100
|
+
if (raw !== void 0) return {
|
|
101
|
+
...tool,
|
|
102
|
+
inputSchema: raw
|
|
103
|
+
};
|
|
104
|
+
return tool;
|
|
105
|
+
})
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
24
111
|
//#endregion
|
|
25
112
|
//#region src/createGatedToolRegistrar.ts
|
|
26
113
|
var toolError = message => {
|
|
@@ -142,19 +229,39 @@ var createGatedToolRegistrar = ({
|
|
|
142
229
|
//#region src/index.ts
|
|
143
230
|
/** MCP lifecycle/discovery methods reachable before a client authenticates. */
|
|
144
231
|
var DEFAULT_PUBLIC_METHODS = ["initialize", "tools/list"];
|
|
232
|
+
/**
|
|
233
|
+
* Asserts that a verified token's `aud` claim includes at least one of the
|
|
234
|
+
* expected resource indicator values. `aud` may be a single string or an
|
|
235
|
+
* array of strings per the JWT spec (RFC 7519); both forms are checked.
|
|
236
|
+
*/
|
|
237
|
+
var assertResourceIndicator = (payload, resourceIndicator) => {
|
|
238
|
+
const expected = Array.isArray(resourceIndicator) ? resourceIndicator : [resourceIndicator];
|
|
239
|
+
const aud = payload?.aud;
|
|
240
|
+
if (!(typeof aud === "string" ? [aud] : Array.isArray(aud) ? aud : []).some(audience => {
|
|
241
|
+
return typeof audience === "string" && expected.includes(audience);
|
|
242
|
+
})) throw new Error(`Token audience does not include the expected resource indicator (expected one of: ${expected.join(", ")}).`);
|
|
243
|
+
};
|
|
145
244
|
/** Builds the token verifier from the MCP auth options. */
|
|
146
245
|
var buildVerifyToken = auth => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
246
|
+
const verify = (() => {
|
|
247
|
+
if (auth.cognitoUserPool) {
|
|
248
|
+
const verifier = CognitoJwtVerifier.create({
|
|
249
|
+
tokenUse: "access",
|
|
250
|
+
...auth.cognitoUserPool
|
|
251
|
+
});
|
|
252
|
+
return token => {
|
|
253
|
+
return verifier.verify(token);
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (auth.verifyToken) return auth.verifyToken;
|
|
257
|
+
throw new Error("McpAuthOptions requires either cognitoUserPool or verifyToken");
|
|
258
|
+
})();
|
|
259
|
+
if (!auth.resourceIndicator) return verify;
|
|
260
|
+
return async token => {
|
|
261
|
+
const payload = await verify(token);
|
|
262
|
+
assertResourceIndicator(payload, auth.resourceIndicator);
|
|
263
|
+
return payload;
|
|
264
|
+
};
|
|
158
265
|
};
|
|
159
266
|
/**
|
|
160
267
|
* Generic HTTP helper for use inside MCP tool handlers.
|
|
@@ -437,90 +544,6 @@ var createMcpRouter = (server, options = {}) => {
|
|
|
437
544
|
}
|
|
438
545
|
return router;
|
|
439
546
|
};
|
|
440
|
-
var rawSchemaRegistryMap = /* @__PURE__ */new WeakMap();
|
|
441
|
-
var patchedServerSet = /* @__PURE__ */new WeakSet();
|
|
442
|
-
/**
|
|
443
|
-
* Registers a tool on an MCP server using a **plain JSON Schema** object for
|
|
444
|
-
* `inputSchema` instead of a Zod shape.
|
|
445
|
-
*
|
|
446
|
-
* This is useful when tool definitions are shared between the MCP server and an
|
|
447
|
-
* AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
|
|
448
|
-
* plain JSON Schema at runtime. Using this helper eliminates the lossy
|
|
449
|
-
* JSON-Schema→Zod conversion that would otherwise be required.
|
|
450
|
-
*
|
|
451
|
-
* Internally the helper:
|
|
452
|
-
* 1. Registers the tool via the standard `McpServer.registerTool` API using a
|
|
453
|
-
* Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
|
|
454
|
-
* `tools/call` handler correctly routes requests and delivers raw args to
|
|
455
|
-
* your handler.
|
|
456
|
-
* 2. Stores the original JSON Schema and patches the `tools/list` response
|
|
457
|
-
* handler so clients receive the verbatim JSON Schema over the wire.
|
|
458
|
-
*
|
|
459
|
-
* @param server - The `McpServer` instance to register the tool on.
|
|
460
|
-
* @param params - Tool configuration including name, description, inputSchema,
|
|
461
|
-
* and handler.
|
|
462
|
-
*
|
|
463
|
-
* @example
|
|
464
|
-
* ```typescript
|
|
465
|
-
* import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
|
|
466
|
-
*
|
|
467
|
-
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
468
|
-
*
|
|
469
|
-
* registerToolFromSchema(server, {
|
|
470
|
-
* name: 'get-project',
|
|
471
|
-
* description: 'Get a project by ID',
|
|
472
|
-
* inputSchema: {
|
|
473
|
-
* type: 'object',
|
|
474
|
-
* properties: { id: { type: 'string', description: 'Project public ID' } },
|
|
475
|
-
* required: ['id'],
|
|
476
|
-
* },
|
|
477
|
-
* handler: async ({ id }) => ({
|
|
478
|
-
* content: [{ type: 'text', text: `Project: ${id}` }],
|
|
479
|
-
* }),
|
|
480
|
-
* });
|
|
481
|
-
* ```
|
|
482
|
-
*/
|
|
483
|
-
var registerToolFromSchema = (server, params) => {
|
|
484
|
-
const {
|
|
485
|
-
name,
|
|
486
|
-
description,
|
|
487
|
-
inputSchema = {
|
|
488
|
-
type: "object",
|
|
489
|
-
properties: {}
|
|
490
|
-
},
|
|
491
|
-
handler
|
|
492
|
-
} = params;
|
|
493
|
-
if (!rawSchemaRegistryMap.has(server)) rawSchemaRegistryMap.set(server, /* @__PURE__ */new Map());
|
|
494
|
-
rawSchemaRegistryMap.get(server).set(name, inputSchema);
|
|
495
|
-
server.registerTool(name, {
|
|
496
|
-
description,
|
|
497
|
-
inputSchema: z$1.record(z$1.string(), z$1.unknown())
|
|
498
|
-
}, async args => {
|
|
499
|
-
return handler(args);
|
|
500
|
-
});
|
|
501
|
-
if (!patchedServerSet.has(server)) {
|
|
502
|
-
patchedServerSet.add(server);
|
|
503
|
-
const rawServer = server.server;
|
|
504
|
-
const origHandler = rawServer?._requestHandlers?.get("tools/list");
|
|
505
|
-
if (!origHandler && process.env.NODE_ENV !== "production") console.warn("[registerToolFromSchema] Could not patch tools/list — internal MCP SDK structure may have changed. The tool will still be callable, but tools/list may return a Zod-derived schema instead of the verbatim JSON Schema.");
|
|
506
|
-
if (origHandler) rawServer._requestHandlers.set("tools/list", async (rawRequest, extra) => {
|
|
507
|
-
const result = await origHandler(rawRequest, extra);
|
|
508
|
-
const schemas = rawSchemaRegistryMap.get(server);
|
|
509
|
-
if (!schemas) return result;
|
|
510
|
-
return {
|
|
511
|
-
...result,
|
|
512
|
-
tools: result.tools.map(tool => {
|
|
513
|
-
const raw = schemas.get(tool.name);
|
|
514
|
-
if (raw !== void 0) return {
|
|
515
|
-
...tool,
|
|
516
|
-
inputSchema: raw
|
|
517
|
-
};
|
|
518
|
-
return tool;
|
|
519
|
-
})
|
|
520
|
-
};
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
};
|
|
524
547
|
|
|
525
548
|
//#endregion
|
|
526
549
|
export { McpServer, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerToolFromSchema, z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/http-server-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server integration for @ttoss/http-server",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37
37
|
"zod": "^4.4.3",
|
|
38
|
-
"@ttoss/auth-core": "^0.
|
|
39
|
-
"@ttoss/http-server
|
|
40
|
-
"@ttoss/http-server": "^0.
|
|
38
|
+
"@ttoss/auth-core": "^0.12.0",
|
|
39
|
+
"@ttoss/http-server": "^0.7.1",
|
|
40
|
+
"@ttoss/http-server-auth": "^0.5.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/koa": "^3.0.3",
|