mcp-use 2.0.0-beta.4 → 2.0.0-beta.6
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/.tsbuildinfo +1 -1
- package/dist/{chunk-AQ2ZZM2P.js → chunk-DQ7LE4ZA.js} +57 -13
- package/dist/chunk-DQ7LE4ZA.js.map +1 -0
- package/dist/{chunk-SFI2T6TE.js → chunk-PMPGMSYA.js} +8 -1
- package/dist/chunk-PMPGMSYA.js.map +1 -0
- package/dist/cli/build.d.ts.map +1 -1
- package/dist/cli/dev.d.ts.map +1 -1
- package/dist/cli/tools-declaration.d.ts +22 -0
- package/dist/cli/tools-declaration.d.ts.map +1 -0
- package/dist/commands/build.js +5 -1
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/dev.js +5 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/config.d.ts +41 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/fetch-app.d.ts +17 -0
- package/dist/fetch-app.d.ts.map +1 -1
- package/dist/index.d.ts +14 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +451 -57
- package/dist/index.js.map +1 -1
- package/dist/inspector-shell.d.ts +6 -0
- package/dist/inspector-shell.d.ts.map +1 -1
- package/dist/middleware/cors.d.ts +11 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/mcp-middleware.d.ts +135 -0
- package/dist/middleware/mcp-middleware.d.ts.map +1 -0
- package/dist/mount-mcp.d.ts +0 -4
- package/dist/mount-mcp.d.ts.map +1 -1
- package/dist/oauth/index.js +1 -1
- package/dist/{public-route-7IK5D7V7.js → public-route-26FUVRO5.js} +5 -3
- package/dist/public-route-26FUVRO5.js.map +1 -0
- package/dist/react/hooks/use-files.d.ts +25 -0
- package/dist/react/hooks/use-files.d.ts.map +1 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +66 -2
- package/dist/react/index.js.map +1 -1
- package/dist/react/runtime/view-runtime.d.ts +23 -0
- package/dist/react/runtime/view-runtime.d.ts.map +1 -1
- package/dist/react/types/file-types.d.ts +16 -0
- package/dist/react/types/file-types.d.ts.map +1 -0
- package/dist/react/types/register.d.ts +1 -1
- package/dist/react/types/register.d.ts.map +1 -1
- package/dist/resources.d.ts +22 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/server.d.ts +49 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/tools.d.ts +12 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/views/public-route.d.ts +7 -3
- package/dist/views/public-route.d.ts.map +1 -1
- package/dist/views/routes.d.ts +2 -0
- package/dist/views/routes.d.ts.map +1 -1
- package/dist/views/wire.d.ts +7 -3
- package/dist/views/wire.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-AQ2ZZM2P.js.map +0 -1
- package/dist/chunk-SFI2T6TE.js.map +0 -1
- package/dist/public-route-7IK5D7V7.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -18,8 +18,9 @@ import {
|
|
|
18
18
|
originValidationMiddleware,
|
|
19
19
|
pathnameOf,
|
|
20
20
|
requireBearerAuth,
|
|
21
|
-
routeFetch
|
|
22
|
-
|
|
21
|
+
routeFetch,
|
|
22
|
+
toFrameworkHandler
|
|
23
|
+
} from "./chunk-PMPGMSYA.js";
|
|
23
24
|
import {
|
|
24
25
|
getOAuthProviderOptions,
|
|
25
26
|
resolveConfiguredOAuthResource,
|
|
@@ -229,12 +230,198 @@ function toAuthenticatedRequestContext(ctx) {
|
|
|
229
230
|
};
|
|
230
231
|
}
|
|
231
232
|
|
|
233
|
+
// src/middleware/cors.ts
|
|
234
|
+
var DEFAULT_METHODS = ["GET", "HEAD", "POST", "OPTIONS"];
|
|
235
|
+
var DEFAULT_ALLOWED_HEADERS = [
|
|
236
|
+
"Content-Type",
|
|
237
|
+
"Authorization",
|
|
238
|
+
"mcp-protocol-version",
|
|
239
|
+
"mcp-method",
|
|
240
|
+
"mcp-name"
|
|
241
|
+
];
|
|
242
|
+
function resolveAllowedOrigin(origin, requestOrigin) {
|
|
243
|
+
if (origin === void 0) {
|
|
244
|
+
return requestOrigin;
|
|
245
|
+
}
|
|
246
|
+
if (typeof origin === "function") {
|
|
247
|
+
return origin(requestOrigin);
|
|
248
|
+
}
|
|
249
|
+
if (origin === "*") {
|
|
250
|
+
return "*";
|
|
251
|
+
}
|
|
252
|
+
if (Array.isArray(origin)) {
|
|
253
|
+
if (requestOrigin !== null && origin.includes(requestOrigin)) {
|
|
254
|
+
return requestOrigin;
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
return origin;
|
|
259
|
+
}
|
|
260
|
+
function corsHeaders(options, request) {
|
|
261
|
+
if (request.headers.has("Access-Control-Allow-Origin")) {
|
|
262
|
+
return void 0;
|
|
263
|
+
}
|
|
264
|
+
const requestOrigin = request.headers.get("Origin");
|
|
265
|
+
const allowedOrigin = resolveAllowedOrigin(options.origin, requestOrigin);
|
|
266
|
+
if (allowedOrigin === null) {
|
|
267
|
+
return void 0;
|
|
268
|
+
}
|
|
269
|
+
const headers = {
|
|
270
|
+
"Access-Control-Allow-Origin": allowedOrigin,
|
|
271
|
+
"Access-Control-Allow-Methods": options.methods.join(", "),
|
|
272
|
+
"Access-Control-Allow-Headers": options.allowedHeaders.join(", ")
|
|
273
|
+
};
|
|
274
|
+
if (options.credentials) {
|
|
275
|
+
headers["Access-Control-Allow-Credentials"] = "true";
|
|
276
|
+
}
|
|
277
|
+
if (allowedOrigin !== "*") {
|
|
278
|
+
headers.Vary = "Origin";
|
|
279
|
+
}
|
|
280
|
+
return headers;
|
|
281
|
+
}
|
|
282
|
+
function mergeCorsHeaders(response, headers) {
|
|
283
|
+
if (response.headers.has("Access-Control-Allow-Origin")) {
|
|
284
|
+
return response;
|
|
285
|
+
}
|
|
286
|
+
const merged = new Headers(response.headers);
|
|
287
|
+
const corsHeaders2 = new Headers(headers);
|
|
288
|
+
corsHeaders2.forEach((value, key) => {
|
|
289
|
+
merged.set(key, value);
|
|
290
|
+
});
|
|
291
|
+
return new Response(response.body, {
|
|
292
|
+
status: response.status,
|
|
293
|
+
statusText: response.statusText,
|
|
294
|
+
headers: merged
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
function corsFetchMiddleware(options) {
|
|
298
|
+
const enabled = options.enabled !== false;
|
|
299
|
+
if (!enabled) {
|
|
300
|
+
return async (_request, next) => next();
|
|
301
|
+
}
|
|
302
|
+
const resolved = {
|
|
303
|
+
...options.origin !== void 0 && { origin: options.origin },
|
|
304
|
+
methods: options.methods ?? DEFAULT_METHODS,
|
|
305
|
+
allowedHeaders: options.allowedHeaders ?? DEFAULT_ALLOWED_HEADERS,
|
|
306
|
+
credentials: options.credentials ?? false
|
|
307
|
+
};
|
|
308
|
+
return async (request, next) => {
|
|
309
|
+
const headers = corsHeaders(resolved, request);
|
|
310
|
+
if (headers === void 0) {
|
|
311
|
+
return next();
|
|
312
|
+
}
|
|
313
|
+
if (request.method === "OPTIONS") {
|
|
314
|
+
return new Response(null, { status: 204, headers });
|
|
315
|
+
}
|
|
316
|
+
const response = await next();
|
|
317
|
+
return mergeCorsHeaders(response, headers);
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function isGlobalCorsEnabled(cors) {
|
|
321
|
+
return cors !== void 0 && cors.enabled !== false;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/middleware/mcp-middleware.ts
|
|
325
|
+
function matchesPattern(pattern, method) {
|
|
326
|
+
if (pattern === "*") return true;
|
|
327
|
+
if (pattern.endsWith("/*")) {
|
|
328
|
+
const prefix = pattern.slice(0, -1);
|
|
329
|
+
return method.startsWith(prefix);
|
|
330
|
+
}
|
|
331
|
+
return pattern === method;
|
|
332
|
+
}
|
|
333
|
+
function composeMiddleware(entries, method, innerFn) {
|
|
334
|
+
const matching = entries.filter((e) => matchesPattern(e.pattern, method));
|
|
335
|
+
if (matching.length === 0) {
|
|
336
|
+
return (_ctx) => innerFn();
|
|
337
|
+
}
|
|
338
|
+
return (ctx) => {
|
|
339
|
+
let index = -1;
|
|
340
|
+
const dispatch = (i) => {
|
|
341
|
+
if (i <= index) {
|
|
342
|
+
return Promise.reject(new Error("next() called multiple times"));
|
|
343
|
+
}
|
|
344
|
+
index = i;
|
|
345
|
+
if (i === matching.length) {
|
|
346
|
+
return innerFn();
|
|
347
|
+
}
|
|
348
|
+
const entry = matching[i];
|
|
349
|
+
return entry.handler(ctx, () => dispatch(i + 1));
|
|
350
|
+
};
|
|
351
|
+
return dispatch(0);
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function freezeMiddlewareContext(ctx) {
|
|
355
|
+
return Object.freeze({
|
|
356
|
+
method: ctx.method,
|
|
357
|
+
params: Object.freeze({ ...ctx.params }),
|
|
358
|
+
...ctx.auth !== void 0 && { auth: ctx.auth },
|
|
359
|
+
state: ctx.state
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
async function runMcpOperation(middlewares, events, method, ctx, innerFn) {
|
|
363
|
+
dispatchMcpEvents(events, method, "before", ctx);
|
|
364
|
+
const chained = composeMiddleware(middlewares, method, innerFn);
|
|
365
|
+
const result = await chained(ctx);
|
|
366
|
+
dispatchMcpEvents(events, method, "complete", ctx, result);
|
|
367
|
+
return result;
|
|
368
|
+
}
|
|
369
|
+
function dispatchMcpEvents(events, method, phase, ctx, result) {
|
|
370
|
+
const frozen = freezeMiddlewareContext(ctx);
|
|
371
|
+
for (const entry of events) {
|
|
372
|
+
if (entry.phase !== phase || !matchesPattern(entry.pattern, method)) {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
if (phase === "before") {
|
|
377
|
+
entry.handler(frozen);
|
|
378
|
+
} else {
|
|
379
|
+
entry.handler(frozen, result);
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.error(
|
|
383
|
+
`[mcp-use] MCP event listener for "${entry.pattern}" (${phase}) threw:`,
|
|
384
|
+
error
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function parseMcpPattern(raw) {
|
|
390
|
+
const pattern = raw.startsWith("mcp:") ? raw.slice(4) : raw;
|
|
391
|
+
if (pattern.endsWith(":complete")) {
|
|
392
|
+
return {
|
|
393
|
+
pattern: pattern.slice(0, -":complete".length),
|
|
394
|
+
phase: "complete"
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
return { pattern, phase: "before" };
|
|
398
|
+
}
|
|
399
|
+
function normalizeMcpMiddlewarePattern(raw) {
|
|
400
|
+
return raw.startsWith("mcp:") ? raw.slice(4) : raw;
|
|
401
|
+
}
|
|
402
|
+
|
|
232
403
|
// src/inspector-shell.ts
|
|
233
404
|
var INSPECTOR_TAG = "beta";
|
|
234
405
|
var DEFAULT_INSPECTOR_ASSETS_URL = `https://cdn.jsdelivr.net/npm/@mcp-use/inspector@${INSPECTOR_TAG}/dist/cdn/inspector.js`;
|
|
235
406
|
function inspectorStylesUrl(assetsUrl) {
|
|
236
407
|
return assetsUrl.replace(/\.js(?=$|[?#])/, ".css");
|
|
237
408
|
}
|
|
409
|
+
function isDefaultJsdelivrInspectorUrl(url) {
|
|
410
|
+
return url.startsWith("https://cdn.jsdelivr.net/npm/@mcp-use/inspector@");
|
|
411
|
+
}
|
|
412
|
+
function withInspectorCacheBust(assetsUrl) {
|
|
413
|
+
if (!isDefaultJsdelivrInspectorUrl(assetsUrl)) return assetsUrl;
|
|
414
|
+
const sep = assetsUrl.includes("?") ? "&" : "?";
|
|
415
|
+
return `${assetsUrl}${sep}cb=${crypto.randomUUID()}`;
|
|
416
|
+
}
|
|
417
|
+
function matchesInspectorShellPath(pathname, basePath) {
|
|
418
|
+
const prefix = `${basePath}/inspector`;
|
|
419
|
+
if (pathname !== prefix && !pathname.startsWith(`${prefix}/`)) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
const suffix = pathname.slice(prefix.length);
|
|
423
|
+
return suffix !== "/api" && !suffix.startsWith("/api/");
|
|
424
|
+
}
|
|
238
425
|
function escapeHtml(value) {
|
|
239
426
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
240
427
|
}
|
|
@@ -245,7 +432,8 @@ function renderInspectorShell(options) {
|
|
|
245
432
|
const { serverName, basePath, assetsUrl, manufactChatUrl } = options;
|
|
246
433
|
const serializedBasePath = serializeForInlineScript(basePath);
|
|
247
434
|
const serializedManufactChatUrl = manufactChatUrl ? serializeForInlineScript(manufactChatUrl) : null;
|
|
248
|
-
const
|
|
435
|
+
const rawUrl = assetsUrl ?? DEFAULT_INSPECTOR_ASSETS_URL;
|
|
436
|
+
const bundleUrl = withInspectorCacheBust(rawUrl);
|
|
249
437
|
const scriptSrc = escapeHtml(bundleUrl);
|
|
250
438
|
const stylesHref = escapeHtml(inspectorStylesUrl(bundleUrl));
|
|
251
439
|
return `<!doctype html>
|
|
@@ -311,22 +499,21 @@ function createInspectorHandler(inspector, options) {
|
|
|
311
499
|
const { assetsUrl: configAssetsUrl, manufactChatUrl: configManufactChatUrl } = inspector ?? {};
|
|
312
500
|
const assetsUrl = configAssetsUrl ?? process.env["MCP_USE_INSPECTOR_ASSETS_URL"] ?? void 0;
|
|
313
501
|
const manufactChatUrl = configManufactChatUrl ?? process.env["MANUFACT_CHAT_URL"] ?? void 0;
|
|
314
|
-
const
|
|
502
|
+
const shellOptions = {
|
|
315
503
|
serverName: options.serverName,
|
|
316
504
|
basePath: options.basePath,
|
|
317
505
|
assetsUrl,
|
|
318
506
|
manufactChatUrl
|
|
319
|
-
}
|
|
320
|
-
const path = `${options.basePath}/inspector`;
|
|
321
|
-
const slashPath = `${path}/`;
|
|
507
|
+
};
|
|
322
508
|
return async (request) => {
|
|
323
509
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
324
510
|
return new Response("Method Not Allowed", { status: 405 });
|
|
325
511
|
}
|
|
326
512
|
const pathname = new URL(request.url).pathname;
|
|
327
|
-
if (pathname
|
|
513
|
+
if (!matchesInspectorShellPath(pathname, options.basePath)) {
|
|
328
514
|
return new Response("Not Found", { status: 404 });
|
|
329
515
|
}
|
|
516
|
+
const html = renderInspectorShell(shellOptions);
|
|
330
517
|
return new Response(request.method === "HEAD" ? null : html, {
|
|
331
518
|
status: 200,
|
|
332
519
|
headers: { "content-type": "text/html; charset=utf-8" }
|
|
@@ -716,9 +903,6 @@ function createMcpMount(factory, options = {}) {
|
|
|
716
903
|
};
|
|
717
904
|
return { handler, fetch };
|
|
718
905
|
}
|
|
719
|
-
function mountMcp(factory, options = {}) {
|
|
720
|
-
return createMcpMount(factory, options);
|
|
721
|
-
}
|
|
722
906
|
|
|
723
907
|
// src/tools.ts
|
|
724
908
|
function resolveToolInputSchema(definition) {
|
|
@@ -853,13 +1037,16 @@ function createViewAssetsHandler(basePath, views, options) {
|
|
|
853
1037
|
if (entry === void 0 || entry.kind !== "external") {
|
|
854
1038
|
return new Response("Not Found", { status: 404 });
|
|
855
1039
|
}
|
|
856
|
-
const [{ join }, { resolvePublicFilePath, servePublicFile }] = await Promise.all([import("path"), import("./public-route-
|
|
1040
|
+
const [{ join }, { resolvePublicFilePath, servePublicFile }] = await Promise.all([import("path"), import("./public-route-26FUVRO5.js")]);
|
|
857
1041
|
const viewRoot = join(projectRoot, VIEW_ASSETS_BUILD_ROOT, viewName);
|
|
858
1042
|
const diskPath = await resolvePublicFilePath(viewRoot, subpath);
|
|
859
1043
|
if (diskPath === null) {
|
|
860
1044
|
return new Response("Not Found", { status: 404 });
|
|
861
1045
|
}
|
|
862
|
-
return await servePublicFile(
|
|
1046
|
+
return await servePublicFile(
|
|
1047
|
+
diskPath,
|
|
1048
|
+
options?.deferCors === true ? { deferCors: true } : {}
|
|
1049
|
+
);
|
|
863
1050
|
};
|
|
864
1051
|
}
|
|
865
1052
|
function createViewPublicHandler(basePath, views, options) {
|
|
@@ -881,30 +1068,43 @@ function createViewPublicHandler(basePath, views, options) {
|
|
|
881
1068
|
if (subpath.length === 0) {
|
|
882
1069
|
return new Response("Not Found", { status: 404 });
|
|
883
1070
|
}
|
|
884
|
-
const [{ join }, { resolvePublicFilePath, servePublicFile }] = await Promise.all([import("path"), import("./public-route-
|
|
1071
|
+
const [{ join }, { resolvePublicFilePath, servePublicFile }] = await Promise.all([import("path"), import("./public-route-26FUVRO5.js")]);
|
|
885
1072
|
const publicRoot = join(projectRoot, subdir);
|
|
886
1073
|
const diskPath = await resolvePublicFilePath(publicRoot, subpath);
|
|
887
1074
|
if (diskPath === null) {
|
|
888
1075
|
return new Response("Not Found", { status: 404 });
|
|
889
1076
|
}
|
|
890
|
-
return await servePublicFile(
|
|
1077
|
+
return await servePublicFile(
|
|
1078
|
+
diskPath,
|
|
1079
|
+
options?.deferCors === true ? { deferCors: true } : {}
|
|
1080
|
+
);
|
|
891
1081
|
};
|
|
892
1082
|
}
|
|
893
1083
|
|
|
894
1084
|
// src/views/wire.ts
|
|
895
|
-
function buildToolUiMeta(viewName, visibility) {
|
|
896
|
-
if (viewName === void 0 && visibility === void 0) {
|
|
1085
|
+
function buildToolUiMeta(viewName, visibility, existingMetadata) {
|
|
1086
|
+
if (viewName === void 0 && visibility === void 0 && existingMetadata === void 0) {
|
|
897
1087
|
return void 0;
|
|
898
1088
|
}
|
|
899
|
-
const
|
|
900
|
-
const
|
|
1089
|
+
const meta = { ...existingMetadata };
|
|
1090
|
+
const existingUi = existingMetadata?.[UI_META_KEY];
|
|
1091
|
+
const existingUiIsObject = typeof existingUi === "object" && existingUi !== null && !Array.isArray(existingUi);
|
|
1092
|
+
const ui = existingUiIsObject ? { ...existingUi } : {};
|
|
901
1093
|
if (viewName !== void 0) {
|
|
902
1094
|
const resourceUri = viewResourceUri(viewName);
|
|
903
1095
|
ui["resourceUri"] = resourceUri;
|
|
904
1096
|
meta[UI_RESOURCE_URI_META_KEY] = resourceUri;
|
|
1097
|
+
} else {
|
|
1098
|
+
delete ui["resourceUri"];
|
|
1099
|
+
delete meta[UI_RESOURCE_URI_META_KEY];
|
|
905
1100
|
}
|
|
906
1101
|
if (visibility !== void 0) {
|
|
907
1102
|
ui["visibility"] = [visibility];
|
|
1103
|
+
} else {
|
|
1104
|
+
delete ui["visibility"];
|
|
1105
|
+
}
|
|
1106
|
+
if (viewName !== void 0 || visibility !== void 0 || existingUiIsObject) {
|
|
1107
|
+
meta[UI_META_KEY] = ui;
|
|
908
1108
|
}
|
|
909
1109
|
return meta;
|
|
910
1110
|
}
|
|
@@ -977,6 +1177,8 @@ var MCPServer = class _MCPServer {
|
|
|
977
1177
|
#oauthResourceConfigurationAbsent = false;
|
|
978
1178
|
/** Whether the mounted app validates Host headers (fixed at first mount). */
|
|
979
1179
|
#hostValidated = false;
|
|
1180
|
+
#mcpMiddlewares = [];
|
|
1181
|
+
#mcpEventListeners = [];
|
|
980
1182
|
/**
|
|
981
1183
|
* Create an MCP server from a parsed, bundled OpenAPI document.
|
|
982
1184
|
*
|
|
@@ -1159,7 +1361,72 @@ var MCPServer = class _MCPServer {
|
|
|
1159
1361
|
*/
|
|
1160
1362
|
getHandler(options = {}) {
|
|
1161
1363
|
const { fetch } = this.#ensureMounted("handler", void 0, options.bus);
|
|
1162
|
-
return fetch;
|
|
1364
|
+
return toFrameworkHandler(fetch);
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Node `(req, res) => void` handler for composing with an existing
|
|
1368
|
+
* `http.Server`. Uses the same internal `toNodeHandler` bridge as
|
|
1369
|
+
* {@link MCPServer.listen}; MCPServer users do not need to import
|
|
1370
|
+
* `mcp-use/node`.
|
|
1371
|
+
*
|
|
1372
|
+
* @example
|
|
1373
|
+
* ```ts
|
|
1374
|
+
* import { createServer } from "node:http";
|
|
1375
|
+
* const httpServer = createServer(await server.getNodeHandler());
|
|
1376
|
+
* httpServer.listen(3000);
|
|
1377
|
+
* ```
|
|
1378
|
+
*/
|
|
1379
|
+
async getNodeHandler() {
|
|
1380
|
+
const { fetch } = this.#ensureMounted("handler");
|
|
1381
|
+
const { toNodeHandler } = await import("./node-bridge.js");
|
|
1382
|
+
return toNodeHandler({ fetch });
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Register MCP operation middleware that intercepts JSON-RPC dispatch.
|
|
1386
|
+
*
|
|
1387
|
+
* Patterns use an `mcp:` prefix (for example `mcp:tools/call`, `mcp:*`).
|
|
1388
|
+
* Middleware runs in registration order; call `next()` to continue the chain.
|
|
1389
|
+
*
|
|
1390
|
+
* @example
|
|
1391
|
+
* ```ts
|
|
1392
|
+
* server.use("mcp:tools/call", async (ctx, next) => {
|
|
1393
|
+
* console.log(`Calling tool: ${ctx.params.name}`);
|
|
1394
|
+
* return next();
|
|
1395
|
+
* });
|
|
1396
|
+
* ```
|
|
1397
|
+
*/
|
|
1398
|
+
use(pattern, handler) {
|
|
1399
|
+
this.#assertNotStarted("middleware", pattern);
|
|
1400
|
+
this.#mcpMiddlewares.push({
|
|
1401
|
+
pattern: normalizeMcpMiddlewarePattern(pattern),
|
|
1402
|
+
handler
|
|
1403
|
+
});
|
|
1404
|
+
return this;
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* Register a read-only MCP observer. Unlike {@link MCPServer.use}, listeners
|
|
1408
|
+
* cannot block, override, or mutate params. Throwing is logged and does not
|
|
1409
|
+
* fail the request.
|
|
1410
|
+
*
|
|
1411
|
+
* Append `:complete` to run after the handler (for example
|
|
1412
|
+
* `mcp:tools/call:complete`).
|
|
1413
|
+
*
|
|
1414
|
+
* @example
|
|
1415
|
+
* ```ts
|
|
1416
|
+
* server.on("mcp:tools/call", (ctx) => {
|
|
1417
|
+
* metrics.increment("tools.call", { tool: ctx.params.name });
|
|
1418
|
+
* });
|
|
1419
|
+
* ```
|
|
1420
|
+
*/
|
|
1421
|
+
on(pattern, handler) {
|
|
1422
|
+
this.#assertNotStarted("event listener", pattern);
|
|
1423
|
+
const { pattern: stripped, phase } = parseMcpPattern(pattern);
|
|
1424
|
+
this.#mcpEventListeners.push({
|
|
1425
|
+
pattern: stripped,
|
|
1426
|
+
phase,
|
|
1427
|
+
handler
|
|
1428
|
+
});
|
|
1429
|
+
return this;
|
|
1163
1430
|
}
|
|
1164
1431
|
/**
|
|
1165
1432
|
* Publish a tools-list change to v2 clients with active subscriptions.
|
|
@@ -1372,6 +1639,11 @@ var MCPServer = class _MCPServer {
|
|
|
1372
1639
|
jsonBodyMiddleware(),
|
|
1373
1640
|
requestLogger(this.#config.logging)
|
|
1374
1641
|
];
|
|
1642
|
+
const corsConfig = this.#config.cors;
|
|
1643
|
+
if (corsConfig !== void 0) {
|
|
1644
|
+
middlewares.unshift(corsFetchMiddleware(corsConfig));
|
|
1645
|
+
}
|
|
1646
|
+
const deferViewCors = isGlobalCorsEnabled(corsConfig);
|
|
1375
1647
|
if (hosts !== void 0) {
|
|
1376
1648
|
middlewares.unshift(hostValidationMiddleware(hosts));
|
|
1377
1649
|
middlewares.push(originValidationMiddleware(origins ?? hosts));
|
|
@@ -1432,7 +1704,8 @@ var MCPServer = class _MCPServer {
|
|
|
1432
1704
|
const routes = [];
|
|
1433
1705
|
const viewHandler = createViewPublicHandler(basePath, this.#views, {
|
|
1434
1706
|
dev: this.#viewsDevMode,
|
|
1435
|
-
projectRoot: this.#viewsProjectRoot
|
|
1707
|
+
projectRoot: this.#viewsProjectRoot,
|
|
1708
|
+
deferCors: deferViewCors
|
|
1436
1709
|
});
|
|
1437
1710
|
if (viewHandler !== void 0) {
|
|
1438
1711
|
routes.push({
|
|
@@ -1446,7 +1719,7 @@ var MCPServer = class _MCPServer {
|
|
|
1446
1719
|
const viewAssetsHandler = createViewAssetsHandler(
|
|
1447
1720
|
basePath,
|
|
1448
1721
|
this.#views,
|
|
1449
|
-
{ projectRoot: this.#viewsProjectRoot }
|
|
1722
|
+
{ projectRoot: this.#viewsProjectRoot, deferCors: deferViewCors }
|
|
1450
1723
|
);
|
|
1451
1724
|
if (viewAssetsHandler !== void 0) {
|
|
1452
1725
|
routes.push({
|
|
@@ -1468,7 +1741,7 @@ var MCPServer = class _MCPServer {
|
|
|
1468
1741
|
return false;
|
|
1469
1742
|
}
|
|
1470
1743
|
const pathname = new URL(request.url).pathname;
|
|
1471
|
-
return pathname
|
|
1744
|
+
return matchesInspectorShellPath(pathname, basePath);
|
|
1472
1745
|
},
|
|
1473
1746
|
handler: inspectorHandler
|
|
1474
1747
|
});
|
|
@@ -1587,11 +1860,78 @@ var MCPServer = class _MCPServer {
|
|
|
1587
1860
|
basePath
|
|
1588
1861
|
);
|
|
1589
1862
|
}
|
|
1863
|
+
this.#wrapListHandlers(server);
|
|
1590
1864
|
return server;
|
|
1591
1865
|
}
|
|
1866
|
+
#createMiddlewareContext(method, params, ctx) {
|
|
1867
|
+
return {
|
|
1868
|
+
method,
|
|
1869
|
+
params,
|
|
1870
|
+
...ctx.http?.authInfo !== void 0 && { auth: ctx.http.authInfo },
|
|
1871
|
+
state: /* @__PURE__ */ new Map()
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
#runMcpHook(method, ctx, innerFn) {
|
|
1875
|
+
return runMcpOperation(
|
|
1876
|
+
this.#mcpMiddlewares,
|
|
1877
|
+
this.#mcpEventListeners,
|
|
1878
|
+
method,
|
|
1879
|
+
ctx,
|
|
1880
|
+
innerFn
|
|
1881
|
+
);
|
|
1882
|
+
}
|
|
1883
|
+
/**
|
|
1884
|
+
* Wrap native SDK list handlers with the MCP middleware chain.
|
|
1885
|
+
*
|
|
1886
|
+
* ponytail: uses SDK-private `_requestHandlers`; pin compile-time test.
|
|
1887
|
+
*
|
|
1888
|
+
* @internal
|
|
1889
|
+
*/
|
|
1890
|
+
#wrapListHandlers(server) {
|
|
1891
|
+
const handlers = server.server._requestHandlers;
|
|
1892
|
+
if (handlers === void 0) {
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
const wrapListMethod = (method, resultKey) => {
|
|
1896
|
+
const original = handlers.get(method);
|
|
1897
|
+
if (original === void 0) {
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1900
|
+
if (original.__mcpListWrapped) {
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
const wrapped = async (request, extra) => {
|
|
1904
|
+
const authInfo = extra?.http?.authInfo;
|
|
1905
|
+
const mwCtx = {
|
|
1906
|
+
method,
|
|
1907
|
+
params: {},
|
|
1908
|
+
...authInfo !== void 0 && { auth: authInfo },
|
|
1909
|
+
state: /* @__PURE__ */ new Map()
|
|
1910
|
+
};
|
|
1911
|
+
const innerFn = async () => {
|
|
1912
|
+
const result = await original(request, extra);
|
|
1913
|
+
return result[resultKey] ?? result;
|
|
1914
|
+
};
|
|
1915
|
+
const filtered = await this.#runMcpHook(method, mwCtx, innerFn);
|
|
1916
|
+
if (Array.isArray(filtered)) {
|
|
1917
|
+
return { [resultKey]: filtered };
|
|
1918
|
+
}
|
|
1919
|
+
return filtered;
|
|
1920
|
+
};
|
|
1921
|
+
wrapped.__mcpListWrapped = true;
|
|
1922
|
+
handlers.set(method, wrapped);
|
|
1923
|
+
};
|
|
1924
|
+
wrapListMethod("tools/list", "tools");
|
|
1925
|
+
wrapListMethod("resources/list", "resources");
|
|
1926
|
+
wrapListMethod("prompts/list", "prompts");
|
|
1927
|
+
}
|
|
1592
1928
|
#registerTool(server, { definition, callback }) {
|
|
1593
1929
|
const view = definition.view;
|
|
1594
|
-
const
|
|
1930
|
+
const toolMeta = buildToolUiMeta(
|
|
1931
|
+
view?.name,
|
|
1932
|
+
definition.visibility,
|
|
1933
|
+
definition._meta
|
|
1934
|
+
);
|
|
1595
1935
|
const config = {
|
|
1596
1936
|
...definition.title !== void 0 && { title: definition.title },
|
|
1597
1937
|
...definition.description !== void 0 && {
|
|
@@ -1603,29 +1943,22 @@ var MCPServer = class _MCPServer {
|
|
|
1603
1943
|
...definition.outputSchema !== void 0 && {
|
|
1604
1944
|
outputSchema: definition.outputSchema
|
|
1605
1945
|
},
|
|
1606
|
-
...
|
|
1946
|
+
...toolMeta !== void 0 && { _meta: toolMeta }
|
|
1607
1947
|
};
|
|
1608
1948
|
const wireResultMeta = view !== void 0 ? buildToolResultUiMeta(view.name) : void 0;
|
|
1609
1949
|
const inputSchema = resolveToolInputSchema(definition);
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
{
|
|
1614
|
-
|
|
1615
|
-
const params = args;
|
|
1616
|
-
const result = await callback(params, this.#toRequestContext(ctx));
|
|
1617
|
-
if (isInputRequiredResult(result) || wireResultMeta === void 0 || result.isError === true) {
|
|
1618
|
-
return result;
|
|
1619
|
-
}
|
|
1620
|
-
return {
|
|
1621
|
-
...result,
|
|
1622
|
-
_meta: { ...result._meta, ...wireResultMeta }
|
|
1623
|
-
};
|
|
1624
|
-
}
|
|
1950
|
+
const invokeTool = async (args, ctx) => {
|
|
1951
|
+
const mwCtx = this.#createMiddlewareContext(
|
|
1952
|
+
"tools/call",
|
|
1953
|
+
{ name: definition.name, arguments: args },
|
|
1954
|
+
ctx
|
|
1625
1955
|
);
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
const result = await callback(
|
|
1956
|
+
const innerFn = async () => {
|
|
1957
|
+
const effectiveArgs = mwCtx.params.arguments ?? {};
|
|
1958
|
+
const result = await callback(
|
|
1959
|
+
effectiveArgs,
|
|
1960
|
+
this.#toRequestContext(ctx)
|
|
1961
|
+
);
|
|
1629
1962
|
if (isInputRequiredResult(result) || wireResultMeta === void 0 || result.isError === true) {
|
|
1630
1963
|
return result;
|
|
1631
1964
|
}
|
|
@@ -1633,7 +1966,21 @@ var MCPServer = class _MCPServer {
|
|
|
1633
1966
|
...result,
|
|
1634
1967
|
_meta: { ...result._meta, ...wireResultMeta }
|
|
1635
1968
|
};
|
|
1636
|
-
}
|
|
1969
|
+
};
|
|
1970
|
+
return await this.#runMcpHook("tools/call", mwCtx, innerFn);
|
|
1971
|
+
};
|
|
1972
|
+
if (inputSchema !== void 0) {
|
|
1973
|
+
server.registerTool(
|
|
1974
|
+
definition.name,
|
|
1975
|
+
{ ...config, inputSchema },
|
|
1976
|
+
async (args, ctx) => invokeTool(args, ctx)
|
|
1977
|
+
);
|
|
1978
|
+
} else {
|
|
1979
|
+
server.registerTool(
|
|
1980
|
+
definition.name,
|
|
1981
|
+
config,
|
|
1982
|
+
async (ctx) => invokeTool({}, ctx)
|
|
1983
|
+
);
|
|
1637
1984
|
}
|
|
1638
1985
|
}
|
|
1639
1986
|
#registerViewResource(server, viewName, entry, metaOptions, basePath) {
|
|
@@ -1688,9 +2035,27 @@ var MCPServer = class _MCPServer {
|
|
|
1688
2035
|
},
|
|
1689
2036
|
...definition.mimeType !== void 0 && {
|
|
1690
2037
|
mimeType: definition.mimeType
|
|
2038
|
+
},
|
|
2039
|
+
...definition.annotations !== void 0 && {
|
|
2040
|
+
annotations: definition.annotations
|
|
2041
|
+
},
|
|
2042
|
+
...definition._meta !== void 0 && {
|
|
2043
|
+
_meta: { ...definition._meta }
|
|
1691
2044
|
}
|
|
1692
2045
|
},
|
|
1693
|
-
async (uri, ctx) =>
|
|
2046
|
+
async (uri, ctx) => {
|
|
2047
|
+
const mwCtx = this.#createMiddlewareContext(
|
|
2048
|
+
"resources/read",
|
|
2049
|
+
{ uri: uri.href },
|
|
2050
|
+
ctx
|
|
2051
|
+
);
|
|
2052
|
+
const innerFn = async () => callback(uri, this.#toRequestContext(ctx));
|
|
2053
|
+
return await this.#runMcpHook(
|
|
2054
|
+
"resources/read",
|
|
2055
|
+
mwCtx,
|
|
2056
|
+
innerFn
|
|
2057
|
+
);
|
|
2058
|
+
}
|
|
1694
2059
|
);
|
|
1695
2060
|
}
|
|
1696
2061
|
#registerResourceTemplate(server, { definition, callback }) {
|
|
@@ -1707,13 +2072,31 @@ var MCPServer = class _MCPServer {
|
|
|
1707
2072
|
},
|
|
1708
2073
|
...definition.mimeType !== void 0 && {
|
|
1709
2074
|
mimeType: definition.mimeType
|
|
2075
|
+
},
|
|
2076
|
+
...definition.annotations !== void 0 && {
|
|
2077
|
+
annotations: definition.annotations
|
|
2078
|
+
},
|
|
2079
|
+
...definition._meta !== void 0 && {
|
|
2080
|
+
_meta: { ...definition._meta }
|
|
1710
2081
|
}
|
|
1711
2082
|
},
|
|
1712
|
-
async (uri, variables, ctx) =>
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
2083
|
+
async (uri, variables, ctx) => {
|
|
2084
|
+
const mwCtx = this.#createMiddlewareContext(
|
|
2085
|
+
"resources/read",
|
|
2086
|
+
{ uri: uri.href },
|
|
2087
|
+
ctx
|
|
2088
|
+
);
|
|
2089
|
+
const innerFn = async () => callback(
|
|
2090
|
+
uri,
|
|
2091
|
+
variables,
|
|
2092
|
+
this.#toRequestContext(ctx)
|
|
2093
|
+
);
|
|
2094
|
+
return await this.#runMcpHook(
|
|
2095
|
+
"resources/read",
|
|
2096
|
+
mwCtx,
|
|
2097
|
+
innerFn
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
1717
2100
|
);
|
|
1718
2101
|
}
|
|
1719
2102
|
#viewResourceFacts(viewConfig) {
|
|
@@ -1741,17 +2124,26 @@ var MCPServer = class _MCPServer {
|
|
|
1741
2124
|
description: definition.description
|
|
1742
2125
|
}
|
|
1743
2126
|
};
|
|
2127
|
+
const invokePrompt = async (args, ctx) => {
|
|
2128
|
+
const mwCtx = this.#createMiddlewareContext(
|
|
2129
|
+
"prompts/get",
|
|
2130
|
+
{ name: definition.name, arguments: args },
|
|
2131
|
+
ctx
|
|
2132
|
+
);
|
|
2133
|
+
const innerFn = async () => {
|
|
2134
|
+
const effectiveArgs = mwCtx.params.arguments ?? {};
|
|
2135
|
+
return callback(effectiveArgs, this.#toRequestContext(ctx));
|
|
2136
|
+
};
|
|
2137
|
+
return await this.#runMcpHook("prompts/get", mwCtx, innerFn);
|
|
2138
|
+
};
|
|
1744
2139
|
if (definition.schema !== void 0) {
|
|
1745
2140
|
server.registerPrompt(
|
|
1746
2141
|
definition.name,
|
|
1747
2142
|
{ ...config, argsSchema: definition.schema },
|
|
1748
|
-
async (args, ctx) =>
|
|
1749
|
-
const params = args;
|
|
1750
|
-
return callback(params, this.#toRequestContext(ctx));
|
|
1751
|
-
}
|
|
2143
|
+
async (args, ctx) => invokePrompt(args, ctx)
|
|
1752
2144
|
);
|
|
1753
2145
|
} else {
|
|
1754
|
-
const handler = async (ctx) =>
|
|
2146
|
+
const handler = async (ctx) => invokePrompt({}, ctx);
|
|
1755
2147
|
server.registerPrompt(
|
|
1756
2148
|
definition.name,
|
|
1757
2149
|
config,
|
|
@@ -1798,6 +2190,7 @@ export {
|
|
|
1798
2190
|
acceptedContent,
|
|
1799
2191
|
completable,
|
|
1800
2192
|
composeFetch,
|
|
2193
|
+
composeMiddleware,
|
|
1801
2194
|
createMcpMount,
|
|
1802
2195
|
createRequestStateCodec,
|
|
1803
2196
|
getRequestBag,
|
|
@@ -1808,11 +2201,12 @@ export {
|
|
|
1808
2201
|
jsonBodyMiddleware,
|
|
1809
2202
|
matchesPath,
|
|
1810
2203
|
matchesPathPrefix,
|
|
1811
|
-
|
|
2204
|
+
matchesPattern,
|
|
1812
2205
|
originValidationMiddleware,
|
|
1813
2206
|
pathnameOf,
|
|
1814
2207
|
registerViews,
|
|
1815
2208
|
requestLogger,
|
|
1816
|
-
routeFetch
|
|
2209
|
+
routeFetch,
|
|
2210
|
+
toFrameworkHandler
|
|
1817
2211
|
};
|
|
1818
2212
|
//# sourceMappingURL=index.js.map
|