@ttoss/http-server-mcp 0.12.4 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,382 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import { CognitoJwtVerifier } from "@ttoss/auth-core/amazon-cognito";
5
+ import { Router } from "@ttoss/http-server";
6
+ import { z, z as z$1 } from "zod";
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+
9
+ //#region src/index.ts
10
+ const requestContextStore = new AsyncLocalStorage();
11
+ /**
12
+ * Generic HTTP helper for use inside MCP tool handlers.
13
+ *
14
+ * Accepts any full URL (third-party APIs, public APIs, etc.) or a path
15
+ * relative to the `apiBaseUrl` configured in `createMcpRouter`.
16
+ *
17
+ * Headers configured via `getApiHeaders` in `createMcpRouter` are injected
18
+ * automatically into every request, allowing transparent forwarding of auth
19
+ * tokens, API keys, or any other header — without coupling this helper to a
20
+ * specific authentication scheme. Per-call `options.headers` take precedence
21
+ * over context-injected headers.
22
+ *
23
+ * @param method - HTTP method (e.g. `'GET'`, `'POST'`, `'PUT'`, `'DELETE'`)
24
+ * @param url - Full URL **or** a path starting with `/` (appended to `apiBaseUrl`)
25
+ * @param options - Optional body and per-call header overrides
26
+ * @returns Parsed JSON response body
27
+ *
28
+ * @example Bearer token forwarding (configured once in `createMcpRouter`)
29
+ * ```typescript
30
+ * import { apiCall, createMcpRouter, McpServer } from '@ttoss/http-server-mcp';
31
+ *
32
+ * // Tool handler – no manual auth wiring needed
33
+ * mcpServer.registerTool('list-portfolios', { description: '...', inputSchema: {} }, async () => {
34
+ * const data = await apiCall('GET', '/portfolios');
35
+ * return { content: [{ type: 'text', text: JSON.stringify(data) }] };
36
+ * });
37
+ *
38
+ * const mcpRouter = createMcpRouter(mcpServer, {
39
+ * apiBaseUrl: `http://localhost:${process.env.PORT}/api/v1`,
40
+ * // Forward the caller's Bearer token to every apiCall
41
+ * getApiHeaders: (ctx) => ({ Authorization: ctx.headers.authorization ?? '' }),
42
+ * });
43
+ * ```
44
+ *
45
+ * @example x-api-key forwarding
46
+ * ```typescript
47
+ * const mcpRouter = createMcpRouter(mcpServer, {
48
+ * apiBaseUrl: 'https://internal-service/api',
49
+ * getApiHeaders: (ctx) => ({
50
+ * 'x-api-key': ctx.headers['x-api-key'] as string,
51
+ * }),
52
+ * });
53
+ * ```
54
+ *
55
+ * @example Third-party or public API (full URL, no context required)
56
+ * ```typescript
57
+ * const weather = await apiCall('GET', 'https://api.weather.com/current?city=Berlin');
58
+ * const created = await apiCall('POST', 'https://api.example.com/items', {
59
+ * body: { name: 'widget' },
60
+ * headers: { Authorization: 'Bearer fixed-service-token' },
61
+ * });
62
+ * ```
63
+ */
64
+ const apiCall = async (method, url, options) => {
65
+ const context = requestContextStore.getStore();
66
+ let resolvedUrl = url;
67
+ if (url.startsWith("/")) {
68
+ if (!context?.apiBaseUrl) throw new Error(`apiCall received a relative path ("${url}") but no apiBaseUrl is configured. Either pass a full URL or set apiBaseUrl in createMcpRouter options.`);
69
+ resolvedUrl = `${context.apiBaseUrl.replace(/\/$/, "")}${url}`;
70
+ }
71
+ const hasBody = options?.body !== void 0;
72
+ const headers = {
73
+ ...(context !== void 0 ? context.apiHeaders : {}),
74
+ ...(options?.headers ?? {})
75
+ };
76
+ const hasExplicitContentType = Object.keys(headers).some(headerName => {
77
+ return headerName.toLowerCase() === "content-type";
78
+ });
79
+ if (hasBody && !hasExplicitContentType) headers["Content-Type"] = "application/json";
80
+ const response = await fetch(resolvedUrl, {
81
+ method,
82
+ headers,
83
+ body: hasBody ? JSON.stringify(options.body) : void 0
84
+ });
85
+ if (!response.ok) {
86
+ const err = await response.json().catch(() => {
87
+ return {
88
+ error: response.statusText
89
+ };
90
+ });
91
+ throw new Error(err.error || `HTTP ${response.status}`);
92
+ }
93
+ if (response.status === 204 || response.status === 205) return;
94
+ if (response.headers.get("content-type")?.includes("application/json")) return response.json();
95
+ return response.text();
96
+ };
97
+ /**
98
+ * Returns the verified JWT payload for the current MCP request.
99
+ * Only available inside a tool handler when `auth` is configured on the router.
100
+ */
101
+ const getIdentity = () => {
102
+ return requestContextStore.getStore()?.identity;
103
+ };
104
+ /**
105
+ * Asserts that the current request's token contains all required scopes.
106
+ * Throws if any scope is missing — the MCP SDK catches this and returns a
107
+ * tool error to the client. Use inside tool handlers for per-tool authorization.
108
+ *
109
+ * Cognito tokens carry scopes as a space-separated string in `payload.scope`.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * server.tool('delete-user', schema, async (args) => {
114
+ * checkScopes(['admin', 'write:users']);
115
+ * // proceed only if caller has both scopes
116
+ * });
117
+ * ```
118
+ */
119
+ const checkScopes = required => {
120
+ const tokenScopes = (getIdentity()?.scope ?? "").split(" ");
121
+ if (required.filter(s => {
122
+ return !tokenScopes.includes(s);
123
+ }).length > 0) throw new Error(`Insufficient scopes. Required: ${required.join(", ")}`);
124
+ };
125
+ const buildTokenVerifier = auth => {
126
+ if (auth.cognitoUserPool) {
127
+ const v = CognitoJwtVerifier.create({
128
+ tokenUse: "access",
129
+ ...auth.cognitoUserPool
130
+ });
131
+ return t => {
132
+ return v.verify(t);
133
+ };
134
+ }
135
+ if (auth.verifyToken) return auth.verifyToken;
136
+ throw new Error("McpAuthOptions requires either cognitoUserPool or verifyToken");
137
+ };
138
+ const registerAuthRoutes = (router, path, auth, tokenVerifier) => {
139
+ router.use(path, async (ctx, next) => {
140
+ const authHeader = ctx.headers.authorization;
141
+ const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : "";
142
+ let identity;
143
+ try {
144
+ identity = await tokenVerifier(token);
145
+ } catch {
146
+ ctx.status = 401;
147
+ ctx.set("WWW-Authenticate", "Bearer");
148
+ ctx.body = "Unauthorized";
149
+ return;
150
+ }
151
+ if (auth.requiredScopes?.length) {
152
+ const tokenScopes = (identity?.scope ?? "").split(" ");
153
+ if (auth.requiredScopes.filter(s => {
154
+ return !tokenScopes.includes(s);
155
+ }).length > 0) {
156
+ ctx.status = 403;
157
+ ctx.body = "Forbidden";
158
+ return;
159
+ }
160
+ }
161
+ ctx.state.identity = identity;
162
+ await next();
163
+ });
164
+ if (auth.resourceServerUrl && auth.authorizationServerUrl) router.get("/.well-known/oauth-protected-resource", ctx => {
165
+ ctx.body = {
166
+ resource: auth.resourceServerUrl,
167
+ authorization_servers: [auth.authorizationServerUrl]
168
+ };
169
+ });
170
+ };
171
+ /**
172
+ * Creates a Koa router configured to handle MCP protocol requests
173
+ *
174
+ * @param server - The MCP server instance with registered tools and resources
175
+ * @param options - Configuration options for the router
176
+ * @returns A Koa Router instance configured for MCP
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * import { App, bodyParser } from '@ttoss/http-server';
181
+ * import { createMcpRouter, McpServer, z } from '@ttoss/http-server-mcp';
182
+ *
183
+ * const mcpServer = new McpServer({
184
+ * name: 'my-server',
185
+ * version: '1.0.0',
186
+ * });
187
+ *
188
+ * mcpServer.registerTool(
189
+ * 'hello',
190
+ * {
191
+ * description: 'Say hello',
192
+ * inputSchema: { name: z.string() },
193
+ * },
194
+ * async ({ name }) => ({
195
+ * content: [{ type: 'text', text: `Hello, ${name}!` }],
196
+ * })
197
+ * );
198
+ *
199
+ * const app = new App();
200
+ * app.use(bodyParser());
201
+ *
202
+ * const mcpRouter = createMcpRouter(mcpServer);
203
+ * app.use(mcpRouter.routes());
204
+ *
205
+ * app.listen(3000);
206
+ * ```
207
+ */
208
+ const createMcpRouter = (server, options = {}) => {
209
+ const {
210
+ path = "/mcp",
211
+ sessionIdGenerator,
212
+ apiBaseUrl,
213
+ getApiHeaders,
214
+ auth
215
+ } = options;
216
+ const isStateful = sessionIdGenerator !== void 0;
217
+ const needsContext = apiBaseUrl !== void 0 || getApiHeaders !== void 0 || auth !== void 0;
218
+ let sharedTransport;
219
+ if (isStateful) {
220
+ sharedTransport = new StreamableHTTPServerTransport({
221
+ sessionIdGenerator,
222
+ enableJsonResponse: true
223
+ });
224
+ server.connect(sharedTransport);
225
+ }
226
+ let statelessQueue = Promise.resolve();
227
+ const enqueueStateless = work => {
228
+ const result = statelessQueue.then(() => {
229
+ return work();
230
+ });
231
+ statelessQueue = result.catch(() => {});
232
+ return result;
233
+ };
234
+ const router = new Router();
235
+ if (auth) registerAuthRoutes(router, path, auth, buildTokenVerifier(auth));
236
+ const handleWithContext = async (ctx, body) => {
237
+ const apiHeaders = getApiHeaders ? getApiHeaders(ctx) : {};
238
+ const identity = ctx.state.identity;
239
+ const runRequest = async transport => {
240
+ await transport.handleRequest(ctx.req, ctx.res, body);
241
+ ctx.respond = false;
242
+ };
243
+ if (isStateful && sharedTransport) {
244
+ if (needsContext) await requestContextStore.run({
245
+ apiBaseUrl,
246
+ apiHeaders,
247
+ identity
248
+ }, () => {
249
+ return runRequest(sharedTransport);
250
+ });else await runRequest(sharedTransport);
251
+ } else await enqueueStateless(async () => {
252
+ const transport = new StreamableHTTPServerTransport({
253
+ sessionIdGenerator: void 0,
254
+ enableJsonResponse: true
255
+ });
256
+ try {
257
+ await server.connect(transport);
258
+ if (needsContext) await requestContextStore.run({
259
+ apiBaseUrl,
260
+ apiHeaders,
261
+ identity
262
+ }, () => {
263
+ return runRequest(transport);
264
+ });else await runRequest(transport);
265
+ } finally {
266
+ await transport.close();
267
+ }
268
+ });
269
+ };
270
+ router.post(path, async ctx => {
271
+ try {
272
+ await handleWithContext(ctx, ctx.request.body);
273
+ } catch (error) {
274
+ if (!ctx.res.headersSent) {
275
+ ctx.status = 500;
276
+ ctx.body = {
277
+ error: error instanceof Error ? error.message : "Internal server error"
278
+ };
279
+ }
280
+ }
281
+ });
282
+ router.delete(path, async ctx => {
283
+ try {
284
+ await handleWithContext(ctx);
285
+ } catch (error) {
286
+ if (!ctx.res.headersSent) {
287
+ ctx.status = 500;
288
+ ctx.body = {
289
+ error: error instanceof Error ? error.message : "Internal server error"
290
+ };
291
+ }
292
+ }
293
+ });
294
+ return router;
295
+ };
296
+ const rawSchemaRegistryMap = /* @__PURE__ */new WeakMap();
297
+ const patchedServerSet = /* @__PURE__ */new WeakSet();
298
+ /**
299
+ * Registers a tool on an MCP server using a **plain JSON Schema** object for
300
+ * `inputSchema` instead of a Zod shape.
301
+ *
302
+ * This is useful when tool definitions are shared between the MCP server and an
303
+ * AI SDK agent (e.g. Vercel AI SDK's `tool()` helper), because both consume a
304
+ * plain JSON Schema at runtime. Using this helper eliminates the lossy
305
+ * JSON-Schema→Zod conversion that would otherwise be required.
306
+ *
307
+ * Internally the helper:
308
+ * 1. Registers the tool via the standard `McpServer.registerTool` API using a
309
+ * Zod `z.record(z.unknown())` pass-through schema so that the existing MCP
310
+ * `tools/call` handler correctly routes requests and delivers raw args to
311
+ * your handler.
312
+ * 2. Stores the original JSON Schema and patches the `tools/list` response
313
+ * handler so clients receive the verbatim JSON Schema over the wire.
314
+ *
315
+ * @param server - The `McpServer` instance to register the tool on.
316
+ * @param params - Tool configuration including name, description, inputSchema,
317
+ * and handler.
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * import { registerToolFromSchema, McpServer } from '@ttoss/http-server-mcp';
322
+ *
323
+ * const server = new McpServer({ name: 'my-server', version: '1.0.0' });
324
+ *
325
+ * registerToolFromSchema(server, {
326
+ * name: 'get-project',
327
+ * description: 'Get a project by ID',
328
+ * inputSchema: {
329
+ * type: 'object',
330
+ * properties: { id: { type: 'string', description: 'Project public ID' } },
331
+ * required: ['id'],
332
+ * },
333
+ * handler: async ({ id }) => ({
334
+ * content: [{ type: 'text', text: `Project: ${id}` }],
335
+ * }),
336
+ * });
337
+ * ```
338
+ */
339
+ const registerToolFromSchema = (server, params) => {
340
+ const {
341
+ name,
342
+ description,
343
+ inputSchema = {
344
+ type: "object",
345
+ properties: {}
346
+ },
347
+ handler
348
+ } = params;
349
+ if (!rawSchemaRegistryMap.has(server)) rawSchemaRegistryMap.set(server, /* @__PURE__ */new Map());
350
+ rawSchemaRegistryMap.get(server).set(name, inputSchema);
351
+ server.registerTool(name, {
352
+ description,
353
+ inputSchema: z$1.record(z$1.string(), z$1.unknown())
354
+ }, async args => {
355
+ return handler(args);
356
+ });
357
+ if (!patchedServerSet.has(server)) {
358
+ patchedServerSet.add(server);
359
+ const rawServer = server.server;
360
+ const origHandler = rawServer?._requestHandlers?.get("tools/list");
361
+ 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.");
362
+ if (origHandler) rawServer._requestHandlers.set("tools/list", async (rawRequest, extra) => {
363
+ const result = await origHandler(rawRequest, extra);
364
+ const schemas = rawSchemaRegistryMap.get(server);
365
+ if (!schemas) return result;
366
+ return {
367
+ ...result,
368
+ tools: result.tools.map(tool => {
369
+ const raw = schemas.get(tool.name);
370
+ if (raw !== void 0) return {
371
+ ...tool,
372
+ inputSchema: raw
373
+ };
374
+ return tool;
375
+ })
376
+ };
377
+ });
378
+ }
379
+ };
380
+
381
+ //#endregion
382
+ export { McpServer, apiCall, checkScopes, createMcpRouter, getIdentity, registerToolFromSchema, z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp",
3
- "version": "0.12.4",
3
+ "version": "0.13.0",
4
4
  "description": "Model Context Protocol (MCP) server integration for @ttoss/http-server",
5
5
  "keywords": [
6
6
  "ai",
@@ -35,14 +35,15 @@
35
35
  "dependencies": {
36
36
  "@modelcontextprotocol/sdk": "^1.29.0",
37
37
  "zod": "^4.3.6",
38
- "@ttoss/http-server": "^0.5.13"
38
+ "@ttoss/auth-core": "^0.4.13",
39
+ "@ttoss/http-server": "^0.5.14"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@types/koa": "^3.0.2",
42
43
  "jest": "^30.3.0",
43
44
  "supertest": "^7.2.2",
44
- "tsup": "^8.5.1",
45
- "@ttoss/config": "^1.37.12"
45
+ "tsdown": "^0.22.0",
46
+ "@ttoss/config": "^1.37.13"
46
47
  },
47
48
  "peerDependencies": {
48
49
  "@modelcontextprotocol/sdk": "^1.0.0"
@@ -52,7 +53,7 @@
52
53
  "provenance": true
53
54
  },
54
55
  "scripts": {
55
- "build": "tsup",
56
+ "build": "tsdown",
56
57
  "test": "jest --projects tests/unit"
57
58
  }
58
59
  }
package/dist/esm/index.js DELETED
@@ -1,205 +0,0 @@
1
- /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- var __defProp = Object.defineProperty;
3
- var __name = (target, value) => __defProp(target, "name", {
4
- value,
5
- configurable: true
6
- });
7
-
8
- // src/index.ts
9
- import { AsyncLocalStorage } from "async_hooks";
10
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
11
- import { Router } from "@ttoss/http-server";
12
- import { z } from "zod";
13
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
- import { z as z2 } from "zod";
15
- var requestContextStore = new AsyncLocalStorage();
16
- var apiCall = /* @__PURE__ */__name(async (method, url, options) => {
17
- const context = requestContextStore.getStore();
18
- let resolvedUrl = url;
19
- if (url.startsWith("/")) {
20
- if (!context?.apiBaseUrl) {
21
- throw new Error(`apiCall received a relative path ("${url}") but no apiBaseUrl is configured. Either pass a full URL or set apiBaseUrl in createMcpRouter options.`);
22
- }
23
- resolvedUrl = `${context.apiBaseUrl.replace(/\/$/, "")}${url}`;
24
- }
25
- const hasBody = options?.body !== void 0;
26
- const headers = {
27
- ...(context !== void 0 ? context.apiHeaders : {}),
28
- ...(options?.headers ?? {})
29
- };
30
- const hasExplicitContentType = Object.keys(headers).some(headerName => {
31
- return headerName.toLowerCase() === "content-type";
32
- });
33
- if (hasBody && !hasExplicitContentType) {
34
- headers["Content-Type"] = "application/json";
35
- }
36
- const response = await fetch(resolvedUrl, {
37
- method,
38
- headers,
39
- body: hasBody ? JSON.stringify(options.body) : void 0
40
- });
41
- if (!response.ok) {
42
- const err = await response.json().catch(() => {
43
- return {
44
- error: response.statusText
45
- };
46
- });
47
- throw new Error(err.error || `HTTP ${response.status}`);
48
- }
49
- if (response.status === 204 || response.status === 205) {
50
- return void 0;
51
- }
52
- const contentType = response.headers.get("content-type");
53
- if (contentType?.includes("application/json")) {
54
- return response.json();
55
- }
56
- return response.text();
57
- }, "apiCall");
58
- var createMcpRouter = /* @__PURE__ */__name((server, options = {}) => {
59
- const {
60
- path = "/mcp",
61
- sessionIdGenerator,
62
- apiBaseUrl,
63
- getApiHeaders
64
- } = options;
65
- const isStateful = sessionIdGenerator !== void 0;
66
- const needsContext = apiBaseUrl !== void 0 || getApiHeaders !== void 0;
67
- let sharedTransport;
68
- if (isStateful) {
69
- sharedTransport = new StreamableHTTPServerTransport({
70
- sessionIdGenerator,
71
- enableJsonResponse: true
72
- });
73
- server.connect(sharedTransport);
74
- }
75
- let statelessQueue = Promise.resolve();
76
- const enqueueStateless = /* @__PURE__ */__name(work => {
77
- const result = statelessQueue.then(() => {
78
- return work();
79
- });
80
- statelessQueue = result.catch(() => {});
81
- return result;
82
- }, "enqueueStateless");
83
- const router = new Router();
84
- const handleWithContext = /* @__PURE__ */__name(async (ctx, body) => {
85
- const apiHeaders = getApiHeaders ? getApiHeaders(ctx) : {};
86
- const runRequest = /* @__PURE__ */__name(async transport => {
87
- await transport.handleRequest(ctx.req, ctx.res, body);
88
- ctx.respond = false;
89
- }, "runRequest");
90
- if (isStateful && sharedTransport) {
91
- if (needsContext) {
92
- await requestContextStore.run({
93
- apiBaseUrl,
94
- apiHeaders
95
- }, () => {
96
- return runRequest(sharedTransport);
97
- });
98
- } else {
99
- await runRequest(sharedTransport);
100
- }
101
- } else {
102
- await enqueueStateless(async () => {
103
- const transport = new StreamableHTTPServerTransport({
104
- sessionIdGenerator: void 0,
105
- enableJsonResponse: true
106
- });
107
- try {
108
- await server.connect(transport);
109
- if (needsContext) {
110
- await requestContextStore.run({
111
- apiBaseUrl,
112
- apiHeaders
113
- }, () => {
114
- return runRequest(transport);
115
- });
116
- } else {
117
- await runRequest(transport);
118
- }
119
- } finally {
120
- await transport.close();
121
- }
122
- });
123
- }
124
- }, "handleWithContext");
125
- router.post(path, async ctx => {
126
- try {
127
- await handleWithContext(ctx, ctx.request.body);
128
- } catch (error) {
129
- if (!ctx.res.headersSent) {
130
- ctx.status = 500;
131
- ctx.body = {
132
- error: error instanceof Error ? error.message : "Internal server error"
133
- };
134
- }
135
- }
136
- });
137
- router.delete(path, async ctx => {
138
- try {
139
- await handleWithContext(ctx);
140
- } catch (error) {
141
- if (!ctx.res.headersSent) {
142
- ctx.status = 500;
143
- ctx.body = {
144
- error: error instanceof Error ? error.message : "Internal server error"
145
- };
146
- }
147
- }
148
- });
149
- return router;
150
- }, "createMcpRouter");
151
- var rawSchemaRegistryMap = /* @__PURE__ */new WeakMap();
152
- var patchedServerSet = /* @__PURE__ */new WeakSet();
153
- var registerToolFromSchema = /* @__PURE__ */__name((server, params) => {
154
- const {
155
- name,
156
- description,
157
- inputSchema = {
158
- type: "object",
159
- properties: {}
160
- },
161
- handler
162
- } = params;
163
- if (!rawSchemaRegistryMap.has(server)) {
164
- rawSchemaRegistryMap.set(server, /* @__PURE__ */new Map());
165
- }
166
- const registry = rawSchemaRegistryMap.get(server);
167
- registry.set(name, inputSchema);
168
- server.registerTool(name, {
169
- description,
170
- inputSchema: z.record(z.string(), z.unknown())
171
- }, async args => {
172
- return handler(args);
173
- });
174
- if (!patchedServerSet.has(server)) {
175
- patchedServerSet.add(server);
176
- const rawServer = server.server;
177
- const origHandler = rawServer?._requestHandlers?.get("tools/list");
178
- if (!origHandler && process.env.NODE_ENV !== "production") {
179
- console.warn("[registerToolFromSchema] Could not patch tools/list \u2014 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.");
180
- }
181
- if (origHandler) {
182
- rawServer._requestHandlers.set("tools/list", async (rawRequest, extra) => {
183
- const result = await origHandler(rawRequest, extra);
184
- const schemas = rawSchemaRegistryMap.get(server);
185
- if (!schemas) {
186
- return result;
187
- }
188
- return {
189
- ...result,
190
- tools: result.tools.map(tool => {
191
- const raw = schemas.get(tool.name);
192
- if (raw !== void 0) {
193
- return {
194
- ...tool,
195
- inputSchema: raw
196
- };
197
- }
198
- return tool;
199
- })
200
- };
201
- });
202
- }
203
- }
204
- }, "registerToolFromSchema");
205
- export { McpServer, apiCall, createMcpRouter, registerToolFromSchema, z2 as z };