@mastra/mcp 2.8.0 → 2.9.0-alpha.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/dist/client/client.d.ts.map +1 -1
- package/dist/client/error-utils.d.ts +9 -0
- package/dist/client/error-utils.d.ts.map +1 -1
- package/dist/client/oauth-callback-server.d.ts.map +1 -1
- package/dist/docs/SKILL.md +1 -4
- package/dist/docs/assets/SOURCE_MAP.json +193 -2
- package/dist/docs/references/docs-connections-mcp.md +66 -1
- package/dist/docs/references/reference-tools-mcp-client.md +4 -0
- package/dist/docs/references/reference-tools-mcp-server.md +6 -2
- package/dist/index.cjs +397 -129
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +398 -130
- package/dist/index.js.map +1 -1
- package/dist/server/request.d.ts +3 -1
- package/dist/server/request.d.ts.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/tasks/workflow-runs.d.ts +7 -0
- package/dist/server/tasks/workflow-runs.d.ts.map +1 -1
- package/dist/server/uri-template.d.ts +15 -0
- package/dist/server/uri-template.d.ts.map +1 -0
- package/package.json +5 -5
- package/dist/docs/references/docs-connections-overview.md +0 -96
- package/dist/docs/references/reference-migrations-mcp-v2.md +0 -268
- package/dist/docs/references/reference-migrations-upgrade-to-v1-mcp.md +0 -103
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createRequire } from "module";
|
|
|
2
2
|
import { AsyncLocalStorage } from "async_hooks";
|
|
3
3
|
import { MastraBase } from "@mastra/core/base";
|
|
4
4
|
import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
|
|
5
|
-
import { createTool, isValidationError, noopObserve, validateToolInput, validateToolOutput } from "@mastra/core/tools";
|
|
5
|
+
import { createTool, getValidationIssuePaths, isValidationError, noopObserve, validateToolInput, validateToolOutput } from "@mastra/core/tools";
|
|
6
6
|
import z3, { ZodFirstPartyTypeKind } from "zod/v3";
|
|
7
7
|
import { toJSONSchema, z } from "zod/v4";
|
|
8
8
|
import { z as z$1 } from "zod";
|
|
@@ -30,101 +30,6 @@ import { SignalProvider } from "@mastra/core/signals";
|
|
|
30
30
|
// src/client/types.ts
|
|
31
31
|
/** The current protocol revision; the one `/mcp` servers speak. */
|
|
32
32
|
const MCP_CLIENT_PROTOCOL_VERSION = "2026-07-28";
|
|
33
|
-
// ../schema-compat/dist/json-schema-traverse-D0CId4oM.js
|
|
34
|
-
var __create$1 = Object.create;
|
|
35
|
-
var __defProp$2 = Object.defineProperty;
|
|
36
|
-
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
37
|
-
var __getOwnPropNames$1 = Object.getOwnPropertyNames;
|
|
38
|
-
var __getProtoOf$1 = Object.getPrototypeOf;
|
|
39
|
-
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
40
|
-
var __commonJSMin$1 = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod, mod.exports), cb = null), mod.exports);
|
|
41
|
-
var __copyProps$1 = (to, from, except, desc) => {
|
|
42
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames$1(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
43
|
-
key = keys[i];
|
|
44
|
-
if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$2(to, key, {
|
|
45
|
-
get: ((k) => from[k]).bind(null, key),
|
|
46
|
-
enumerable: !(desc = __getOwnPropDesc$1(from, key)) || desc.enumerable
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
return to;
|
|
50
|
-
};
|
|
51
|
-
var __toESM$1 = (mod, isNodeMode, target) => (target = mod != null ? __create$1(__getProtoOf$1(mod)) : {}, __copyProps$1(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp$1.call(mod, "default") ? __defProp$2(target, "default", {
|
|
52
|
-
value: mod,
|
|
53
|
-
enumerable: true
|
|
54
|
-
}) : target, mod));
|
|
55
|
-
var require_json_schema_traverse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
|
|
56
|
-
var traverse = module.exports = function(schema, opts, cb) {
|
|
57
|
-
if (typeof opts == "function") {
|
|
58
|
-
cb = opts;
|
|
59
|
-
opts = {};
|
|
60
|
-
}
|
|
61
|
-
cb = opts.cb || cb;
|
|
62
|
-
var pre = typeof cb == "function" ? cb : cb.pre || function() {};
|
|
63
|
-
var post = cb.post || function() {};
|
|
64
|
-
_traverse(opts, pre, post, schema, "", schema);
|
|
65
|
-
};
|
|
66
|
-
traverse.keywords = {
|
|
67
|
-
additionalItems: true,
|
|
68
|
-
items: true,
|
|
69
|
-
contains: true,
|
|
70
|
-
additionalProperties: true,
|
|
71
|
-
propertyNames: true,
|
|
72
|
-
not: true,
|
|
73
|
-
if: true,
|
|
74
|
-
then: true,
|
|
75
|
-
else: true
|
|
76
|
-
};
|
|
77
|
-
traverse.arrayKeywords = {
|
|
78
|
-
items: true,
|
|
79
|
-
allOf: true,
|
|
80
|
-
anyOf: true,
|
|
81
|
-
oneOf: true
|
|
82
|
-
};
|
|
83
|
-
traverse.propsKeywords = {
|
|
84
|
-
$defs: true,
|
|
85
|
-
definitions: true,
|
|
86
|
-
properties: true,
|
|
87
|
-
patternProperties: true,
|
|
88
|
-
dependencies: true
|
|
89
|
-
};
|
|
90
|
-
traverse.skipKeywords = {
|
|
91
|
-
default: true,
|
|
92
|
-
enum: true,
|
|
93
|
-
const: true,
|
|
94
|
-
required: true,
|
|
95
|
-
maximum: true,
|
|
96
|
-
minimum: true,
|
|
97
|
-
exclusiveMaximum: true,
|
|
98
|
-
exclusiveMinimum: true,
|
|
99
|
-
multipleOf: true,
|
|
100
|
-
maxLength: true,
|
|
101
|
-
minLength: true,
|
|
102
|
-
pattern: true,
|
|
103
|
-
format: true,
|
|
104
|
-
maxItems: true,
|
|
105
|
-
minItems: true,
|
|
106
|
-
uniqueItems: true,
|
|
107
|
-
maxProperties: true,
|
|
108
|
-
minProperties: true
|
|
109
|
-
};
|
|
110
|
-
function _traverse(opts, pre, post, schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
|
|
111
|
-
if (schema && typeof schema == "object" && !Array.isArray(schema)) {
|
|
112
|
-
pre(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
113
|
-
for (var key in schema) {
|
|
114
|
-
var sch = schema[key];
|
|
115
|
-
if (Array.isArray(sch)) {
|
|
116
|
-
if (key in traverse.arrayKeywords) for (var i = 0; i < sch.length; i++) _traverse(opts, pre, post, sch[i], jsonPtr + "/" + key + "/" + i, rootSchema, jsonPtr, key, schema, i);
|
|
117
|
-
} else if (key in traverse.propsKeywords) {
|
|
118
|
-
if (sch && typeof sch == "object") for (var prop in sch) _traverse(opts, pre, post, sch[prop], jsonPtr + "/" + key + "/" + escapeJsonPtr(prop), rootSchema, jsonPtr, key, schema, prop);
|
|
119
|
-
} else if (key in traverse.keywords || opts.allKeys && !(key in traverse.skipKeywords)) _traverse(opts, pre, post, sch, jsonPtr + "/" + key, rootSchema, jsonPtr, key, schema);
|
|
120
|
-
}
|
|
121
|
-
post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function escapeJsonPtr(str) {
|
|
125
|
-
return str.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
126
|
-
}
|
|
127
|
-
}));
|
|
128
33
|
// ../schema-compat/dist/esm-BG70JlG8.js
|
|
129
34
|
const ignoreOverride$1 = Symbol("Let zodToJsonSchema decide on which parser to use");
|
|
130
35
|
const defaultOptions$1 = {
|
|
@@ -1330,6 +1235,101 @@ var AiSdkSchemaWrapper = class {
|
|
|
1330
1235
|
function toStandardSchema$4(schema) {
|
|
1331
1236
|
return new AiSdkSchemaWrapper(schema);
|
|
1332
1237
|
}
|
|
1238
|
+
// ../schema-compat/dist/json-schema-traverse-D0CId4oM.js
|
|
1239
|
+
var __create$1 = Object.create;
|
|
1240
|
+
var __defProp$2 = Object.defineProperty;
|
|
1241
|
+
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
1242
|
+
var __getOwnPropNames$1 = Object.getOwnPropertyNames;
|
|
1243
|
+
var __getProtoOf$1 = Object.getPrototypeOf;
|
|
1244
|
+
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
1245
|
+
var __commonJSMin$1 = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod, mod.exports), cb = null), mod.exports);
|
|
1246
|
+
var __copyProps$1 = (to, from, except, desc) => {
|
|
1247
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames$1(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
1248
|
+
key = keys[i];
|
|
1249
|
+
if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$2(to, key, {
|
|
1250
|
+
get: ((k) => from[k]).bind(null, key),
|
|
1251
|
+
enumerable: !(desc = __getOwnPropDesc$1(from, key)) || desc.enumerable
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
return to;
|
|
1255
|
+
};
|
|
1256
|
+
var __toESM$1 = (mod, isNodeMode, target) => (target = mod != null ? __create$1(__getProtoOf$1(mod)) : {}, __copyProps$1(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp$1.call(mod, "default") ? __defProp$2(target, "default", {
|
|
1257
|
+
value: mod,
|
|
1258
|
+
enumerable: true
|
|
1259
|
+
}) : target, mod));
|
|
1260
|
+
var require_json_schema_traverse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
|
|
1261
|
+
var traverse = module.exports = function(schema, opts, cb) {
|
|
1262
|
+
if (typeof opts == "function") {
|
|
1263
|
+
cb = opts;
|
|
1264
|
+
opts = {};
|
|
1265
|
+
}
|
|
1266
|
+
cb = opts.cb || cb;
|
|
1267
|
+
var pre = typeof cb == "function" ? cb : cb.pre || function() {};
|
|
1268
|
+
var post = cb.post || function() {};
|
|
1269
|
+
_traverse(opts, pre, post, schema, "", schema);
|
|
1270
|
+
};
|
|
1271
|
+
traverse.keywords = {
|
|
1272
|
+
additionalItems: true,
|
|
1273
|
+
items: true,
|
|
1274
|
+
contains: true,
|
|
1275
|
+
additionalProperties: true,
|
|
1276
|
+
propertyNames: true,
|
|
1277
|
+
not: true,
|
|
1278
|
+
if: true,
|
|
1279
|
+
then: true,
|
|
1280
|
+
else: true
|
|
1281
|
+
};
|
|
1282
|
+
traverse.arrayKeywords = {
|
|
1283
|
+
items: true,
|
|
1284
|
+
allOf: true,
|
|
1285
|
+
anyOf: true,
|
|
1286
|
+
oneOf: true
|
|
1287
|
+
};
|
|
1288
|
+
traverse.propsKeywords = {
|
|
1289
|
+
$defs: true,
|
|
1290
|
+
definitions: true,
|
|
1291
|
+
properties: true,
|
|
1292
|
+
patternProperties: true,
|
|
1293
|
+
dependencies: true
|
|
1294
|
+
};
|
|
1295
|
+
traverse.skipKeywords = {
|
|
1296
|
+
default: true,
|
|
1297
|
+
enum: true,
|
|
1298
|
+
const: true,
|
|
1299
|
+
required: true,
|
|
1300
|
+
maximum: true,
|
|
1301
|
+
minimum: true,
|
|
1302
|
+
exclusiveMaximum: true,
|
|
1303
|
+
exclusiveMinimum: true,
|
|
1304
|
+
multipleOf: true,
|
|
1305
|
+
maxLength: true,
|
|
1306
|
+
minLength: true,
|
|
1307
|
+
pattern: true,
|
|
1308
|
+
format: true,
|
|
1309
|
+
maxItems: true,
|
|
1310
|
+
minItems: true,
|
|
1311
|
+
uniqueItems: true,
|
|
1312
|
+
maxProperties: true,
|
|
1313
|
+
minProperties: true
|
|
1314
|
+
};
|
|
1315
|
+
function _traverse(opts, pre, post, schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
|
|
1316
|
+
if (schema && typeof schema == "object" && !Array.isArray(schema)) {
|
|
1317
|
+
pre(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
1318
|
+
for (var key in schema) {
|
|
1319
|
+
var sch = schema[key];
|
|
1320
|
+
if (Array.isArray(sch)) {
|
|
1321
|
+
if (key in traverse.arrayKeywords) for (var i = 0; i < sch.length; i++) _traverse(opts, pre, post, sch[i], jsonPtr + "/" + key + "/" + i, rootSchema, jsonPtr, key, schema, i);
|
|
1322
|
+
} else if (key in traverse.propsKeywords) {
|
|
1323
|
+
if (sch && typeof sch == "object") for (var prop in sch) _traverse(opts, pre, post, sch[prop], jsonPtr + "/" + key + "/" + escapeJsonPtr(prop), rootSchema, jsonPtr, key, schema, prop);
|
|
1324
|
+
} else if (key in traverse.keywords || opts.allKeys && !(key in traverse.skipKeywords)) _traverse(opts, pre, post, sch, jsonPtr + "/" + key, rootSchema, jsonPtr, key, schema);
|
|
1325
|
+
}
|
|
1326
|
+
post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
function escapeJsonPtr(str) {
|
|
1330
|
+
return str.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
1331
|
+
}
|
|
1332
|
+
}));
|
|
1333
1333
|
// ../schema-compat/dist/json-schema-BdCwqjfN.js
|
|
1334
1334
|
var require_code$1 = /* @__PURE__ */ __commonJSMin$1(((exports) => {
|
|
1335
1335
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -14385,6 +14385,35 @@ function isReconnectableMCPError(error) {
|
|
|
14385
14385
|
const errorMessage = error.message.toLowerCase();
|
|
14386
14386
|
return errorMessage.includes("not connected") || errorMessage.includes("http 400") || errorMessage.includes("http 401") || errorMessage.includes("http 403") || errorMessage.includes("http 404") || errorMessage.includes("econnrefused") || errorMessage.includes("fetch failed") || errorMessage.includes("connection refused") || errorMessage.includes("connection closed") || errorMessage.includes("typeerror: terminated");
|
|
14387
14387
|
}
|
|
14388
|
+
const CONNECTION_NOT_ESTABLISHED_CODES = /* @__PURE__ */ new Set([
|
|
14389
|
+
"ECONNREFUSED",
|
|
14390
|
+
"ENOTFOUND",
|
|
14391
|
+
"EAI_AGAIN",
|
|
14392
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
14393
|
+
]);
|
|
14394
|
+
const REJECTED_BEFORE_DISPATCH_STATUSES = /* @__PURE__ */ new Set([
|
|
14395
|
+
400,
|
|
14396
|
+
401,
|
|
14397
|
+
403,
|
|
14398
|
+
404
|
|
14399
|
+
]);
|
|
14400
|
+
/**
|
|
14401
|
+
* Whether a reconnectable failure proves the request never reached the server's
|
|
14402
|
+
* handler, so sending it again cannot repeat its effects.
|
|
14403
|
+
*
|
|
14404
|
+
* A reset socket (`fetch failed` with `UND_ERR_SOCKET`), a cut-off response
|
|
14405
|
+
* (`terminated`) or a closed transport (`Connection closed`) can all follow a
|
|
14406
|
+
* request the server already received and ran, so they return false.
|
|
14407
|
+
*/
|
|
14408
|
+
function isUnsentRequestError(error) {
|
|
14409
|
+
if (!isReconnectableMCPError(error)) return false;
|
|
14410
|
+
const { httpStatus, code } = getMCPDiscoveryErrorDetails(error);
|
|
14411
|
+
if (typeof code === "number") return false;
|
|
14412
|
+
if (httpStatus !== void 0) return REJECTED_BEFORE_DISPATCH_STATUSES.has(httpStatus);
|
|
14413
|
+
const message = error.message.toLowerCase();
|
|
14414
|
+
if (message.includes("not connected") || message.includes("econnrefused") || message.includes("connection refused") || /\bhttp 40[0134]\b/.test(message)) return true;
|
|
14415
|
+
return typeof code === "string" && CONNECTION_NOT_ESTABLISHED_CODES.has(code);
|
|
14416
|
+
}
|
|
14388
14417
|
const GATEWAY_UNAVAILABLE_STATUSES = /* @__PURE__ */ new Set([
|
|
14389
14418
|
502,
|
|
14390
14419
|
503,
|
|
@@ -15951,6 +15980,50 @@ function runOutsideDatadogTraceScope(callback) {
|
|
|
15951
15980
|
if (!scope) return callback();
|
|
15952
15981
|
return scope.activate(null, callback);
|
|
15953
15982
|
}
|
|
15983
|
+
const LOGGABLE_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
15984
|
+
"Error",
|
|
15985
|
+
"TypeError",
|
|
15986
|
+
"RangeError",
|
|
15987
|
+
"SyntaxError",
|
|
15988
|
+
"AbortError",
|
|
15989
|
+
"TimeoutError",
|
|
15990
|
+
"McpError",
|
|
15991
|
+
"ProtocolError",
|
|
15992
|
+
"SdkError",
|
|
15993
|
+
"SdkHttpError",
|
|
15994
|
+
"SseError",
|
|
15995
|
+
"StreamableHTTPError",
|
|
15996
|
+
"UnauthorizedError",
|
|
15997
|
+
"OAuthError",
|
|
15998
|
+
"UnsupportedProtocolVersionError"
|
|
15999
|
+
]);
|
|
16000
|
+
const LOGGABLE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
16001
|
+
"ECONNRESET",
|
|
16002
|
+
"ECONNREFUSED",
|
|
16003
|
+
"ECONNABORTED",
|
|
16004
|
+
"ETIMEDOUT",
|
|
16005
|
+
"ENOTFOUND",
|
|
16006
|
+
"EPIPE",
|
|
16007
|
+
"EAI_AGAIN",
|
|
16008
|
+
"ABORT_ERR",
|
|
16009
|
+
"UND_ERR_SOCKET",
|
|
16010
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
16011
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
16012
|
+
"UND_ERR_BODY_TIMEOUT"
|
|
16013
|
+
]);
|
|
16014
|
+
/**
|
|
16015
|
+
* Names a tool-call failure for logs without its message: server error text can echo the submitted
|
|
16016
|
+
* arguments back (Issue #29318). The full error still reaches the caller.
|
|
16017
|
+
*/
|
|
16018
|
+
function errorKind(error) {
|
|
16019
|
+
if (error instanceof MastraError) return error.id;
|
|
16020
|
+
if (error instanceof Error) {
|
|
16021
|
+
const name = LOGGABLE_ERROR_NAMES.has(error.name) ? error.name : "Error";
|
|
16022
|
+
const code = error.code;
|
|
16023
|
+
return typeof code === "number" || typeof code === "string" && LOGGABLE_ERROR_CODES.has(code) ? `${name} (${code})` : name;
|
|
16024
|
+
}
|
|
16025
|
+
return typeof error;
|
|
16026
|
+
}
|
|
15954
16027
|
/**
|
|
15955
16028
|
* Convert an MCP LoggingLevel to a logger method name that exists in our logger
|
|
15956
16029
|
*/
|
|
@@ -17097,10 +17170,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
17097
17170
|
});
|
|
17098
17171
|
return res && finishToolCall(res);
|
|
17099
17172
|
}
|
|
17100
|
-
this.log("debug", `Executing tool: ${tool.name}`, {
|
|
17101
|
-
toolArgs: input,
|
|
17102
|
-
runId: context?.runId
|
|
17103
|
-
});
|
|
17173
|
+
this.log("debug", `Executing tool: ${tool.name}`, { runId: context?.runId });
|
|
17104
17174
|
const progressMeta = this.enableProgressTracking ? { progressToken: context?.runId || crypto.randomUUID() } : void 0;
|
|
17105
17175
|
const _meta = this.requestMeta({
|
|
17106
17176
|
...context?._meta,
|
|
@@ -17129,7 +17199,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
17129
17199
|
const finishToolCall = async (res) => {
|
|
17130
17200
|
if (res.isError && this.onToolError === "throw") {
|
|
17131
17201
|
const errorText = extractToolErrorText(res.content);
|
|
17132
|
-
this.log("debug", `Tool reported an error: ${tool.name}
|
|
17202
|
+
this.log("debug", `Tool reported an error: ${tool.name}`);
|
|
17133
17203
|
throw new MastraError({
|
|
17134
17204
|
id: "MCP_CLIENT_TOOL_EXECUTION_FAILED",
|
|
17135
17205
|
domain: ErrorDomain.MCP,
|
|
@@ -17148,7 +17218,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
17148
17218
|
const validationSchema = await getOutputValidationSchema();
|
|
17149
17219
|
const validation = validateToolOutput(validationSchema, res.structuredContent, tool.name);
|
|
17150
17220
|
if (validation.error) {
|
|
17151
|
-
this.log("debug", `Tool output failed schema validation: ${tool.name}`, {
|
|
17221
|
+
this.log("debug", `Tool output failed schema validation: ${tool.name}`, { issuePaths: getValidationIssuePaths(validation.error, validationSchema, "output") });
|
|
17152
17222
|
return validation.error;
|
|
17153
17223
|
}
|
|
17154
17224
|
}
|
|
@@ -17161,25 +17231,40 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
17161
17231
|
try {
|
|
17162
17232
|
return await executeToolCall();
|
|
17163
17233
|
} catch (e) {
|
|
17164
|
-
|
|
17165
|
-
|
|
17234
|
+
const isToolExecutionError = e instanceof MastraError && (e.id === "MCP_CLIENT_TOOL_EXECUTION_FAILED" || e.id.startsWith("MCP_CLIENT_TOOL_TASK_"));
|
|
17235
|
+
if (!isToolExecutionError && isReconnectableMCPError(e) && !isUnsentRequestError(e)) {
|
|
17236
|
+
if (annotations?.readOnlyHint === true || annotations?.idempotentHint === true) {
|
|
17237
|
+
this.log("debug", `Retrying replay-safe tool ${tool.name} after a transport error`, { error: errorKind(e) });
|
|
17238
|
+
if (this.transport !== failedTransport || this.reconnectPromise) await this.reconnectAfterTransportFailure(failedTransport, lifecycleGeneration);
|
|
17239
|
+
return await executeToolCall();
|
|
17240
|
+
}
|
|
17241
|
+
this.log("error", `Lost the connection during tool ${tool.name}; it may have run`, { error: errorKind(e) });
|
|
17242
|
+
throw new MastraError({
|
|
17243
|
+
id: "MCP_CLIENT_TOOL_CALL_OUTCOME_UNKNOWN",
|
|
17244
|
+
domain: ErrorDomain.MCP,
|
|
17245
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
17246
|
+
text: `The connection to MCP server "${this.name}" failed before tool "${tool.name}" returned a result. The tool may have run on the server, so it was not called again.`,
|
|
17247
|
+
details: {
|
|
17248
|
+
toolName: tool.name,
|
|
17249
|
+
serverName: this.name
|
|
17250
|
+
}
|
|
17251
|
+
}, e);
|
|
17252
|
+
}
|
|
17253
|
+
if (!isToolExecutionError && isReconnectableMCPError(e)) {
|
|
17254
|
+
this.log("debug", `Transport error detected for tool ${tool.name}, attempting reconnection...`, { error: errorKind(e) });
|
|
17166
17255
|
try {
|
|
17167
17256
|
await this.reconnectAfterTransportFailure(failedTransport, lifecycleGeneration);
|
|
17168
17257
|
this.log("debug", `Retrying tool ${tool.name} after reconnection...`);
|
|
17169
17258
|
return await executeToolCall();
|
|
17170
17259
|
} catch (reconnectError) {
|
|
17171
17260
|
this.log("error", `Reconnection or retry failed for tool ${tool.name}`, {
|
|
17172
|
-
originalError:
|
|
17173
|
-
reconnectError:
|
|
17174
|
-
toolArgs: input
|
|
17261
|
+
originalError: errorKind(e),
|
|
17262
|
+
reconnectError: errorKind(reconnectError)
|
|
17175
17263
|
});
|
|
17176
17264
|
throw reconnectError;
|
|
17177
17265
|
}
|
|
17178
17266
|
}
|
|
17179
|
-
this.log("error", `Error calling tool: ${tool.name}`, {
|
|
17180
|
-
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
|
|
17181
|
-
toolArgs: input
|
|
17182
|
-
});
|
|
17267
|
+
this.log("error", `Error calling tool: ${tool.name}`, { error: errorKind(e) });
|
|
17183
17268
|
throw e;
|
|
17184
17269
|
}
|
|
17185
17270
|
});
|
|
@@ -17607,12 +17692,12 @@ async function createOAuthCallbackServer(options) {
|
|
|
17607
17692
|
},
|
|
17608
17693
|
close() {
|
|
17609
17694
|
settle({ error: /* @__PURE__ */ new Error("OAuth callback server closed before receiving an authorization code") });
|
|
17610
|
-
server.closeIdleConnections();
|
|
17611
17695
|
return new Promise((resolve, reject) => {
|
|
17612
17696
|
server.close((error) => {
|
|
17613
17697
|
if (error && error.code !== "ERR_SERVER_NOT_RUNNING") reject(error);
|
|
17614
17698
|
else resolve();
|
|
17615
17699
|
});
|
|
17700
|
+
server.closeAllConnections();
|
|
17616
17701
|
});
|
|
17617
17702
|
}
|
|
17618
17703
|
};
|
|
@@ -18981,7 +19066,7 @@ onListChanged: async (serverName, handler) => {
|
|
|
18981
19066
|
const errors = {};
|
|
18982
19067
|
const errorDetails = {};
|
|
18983
19068
|
const durations = {};
|
|
18984
|
-
const settled = await this.discoverAcrossServers((serverName) => this.getToolsForServer(serverName), {
|
|
19069
|
+
const settled = await this.discoverAcrossServers(async (serverName) => modelVisibleTools(await this.getToolsForServer(serverName)), {
|
|
18985
19070
|
errorId: "MCP_CLIENT_GET_TOOLS_FAILED",
|
|
18986
19071
|
logMessage: "Failed to list tools from server:"
|
|
18987
19072
|
}, options);
|
|
@@ -19036,7 +19121,7 @@ onListChanged: async (serverName, handler) => {
|
|
|
19036
19121
|
const errors = {};
|
|
19037
19122
|
const errorDetails = {};
|
|
19038
19123
|
const durations = {};
|
|
19039
|
-
const settled = await this.discoverAcrossServers((serverName) => this.getToolsForServer(serverName), {
|
|
19124
|
+
const settled = await this.discoverAcrossServers(async (serverName) => modelVisibleTools(await this.getToolsForServer(serverName)), {
|
|
19040
19125
|
errorId: "MCP_CLIENT_GET_TOOLSETS_FAILED",
|
|
19041
19126
|
logMessage: "Failed to list toolsets from server:"
|
|
19042
19127
|
}, options);
|
|
@@ -19100,7 +19185,7 @@ onListChanged: async (serverName, handler) => {
|
|
|
19100
19185
|
const errorDetails = {};
|
|
19101
19186
|
const durations = {};
|
|
19102
19187
|
const settled = await this.discoverAcrossServers(async (serverName) => {
|
|
19103
|
-
return (await this.getConnectedClientForServer(serverName)).toolDefinitions();
|
|
19188
|
+
return modelVisibleDefinitions(await (await this.getConnectedClientForServer(serverName)).toolDefinitions());
|
|
19104
19189
|
}, {
|
|
19105
19190
|
errorId: "MCP_CLIENT_GET_TOOL_DEFINITIONS_FAILED",
|
|
19106
19191
|
logMessage: "Failed to list tool definitions from server:"
|
|
@@ -19169,7 +19254,7 @@ onListChanged: async (serverName, handler) => {
|
|
|
19169
19254
|
this.logger.warn("Skipping cached MCP tool definitions for a server that is no longer configured", { serverName });
|
|
19170
19255
|
continue;
|
|
19171
19256
|
}
|
|
19172
|
-
for (const [toolName, definition] of Object.entries(definitions)) try {
|
|
19257
|
+
for (const [toolName, definition] of Object.entries(modelVisibleDefinitions(definitions))) try {
|
|
19173
19258
|
tools[`${serverName}_${toolName}`] = await this.toolFromDefinition({
|
|
19174
19259
|
serverName,
|
|
19175
19260
|
definition
|
|
@@ -19437,6 +19522,22 @@ onListChanged: async (serverName, handler) => {
|
|
|
19437
19522
|
return {};
|
|
19438
19523
|
}
|
|
19439
19524
|
};
|
|
19525
|
+
/**
|
|
19526
|
+
* Whether a tool may be handed to the model. MCP App servers mark helpers their app calls itself
|
|
19527
|
+
* with `_meta.ui.visibility` lacking `'model'`; per the MCP Apps spec, hosts must not give those
|
|
19528
|
+
* to the model. They stay callable by the app through the server.
|
|
19529
|
+
*/
|
|
19530
|
+
function isModelVisible(meta) {
|
|
19531
|
+
const ui = meta?.ui;
|
|
19532
|
+
const visibility = ui && typeof ui === "object" && "visibility" in ui ? ui.visibility : void 0;
|
|
19533
|
+
return !Array.isArray(visibility) || visibility.includes("model");
|
|
19534
|
+
}
|
|
19535
|
+
function modelVisibleTools(tools) {
|
|
19536
|
+
return Object.fromEntries(Object.entries(tools).filter(([, tool]) => isModelVisible(tool.mcp?._meta)));
|
|
19537
|
+
}
|
|
19538
|
+
function modelVisibleDefinitions(definitions) {
|
|
19539
|
+
return Object.fromEntries(Object.entries(definitions).filter(([, definition]) => isModelVisible(definition._meta)));
|
|
19540
|
+
}
|
|
19440
19541
|
// src/server/actions.ts
|
|
19441
19542
|
/** Runtime tool catalogue mutations. Every change is published to listening clients. */
|
|
19442
19543
|
var ServerToolActions = class {
|
|
@@ -19568,8 +19669,17 @@ function callerTrace(ctx) {
|
|
|
19568
19669
|
return callerTraceContext(meta?.traceparent, meta?.tracestate) ?? callerTraceContext(headers?.get("traceparent"), headers?.get("tracestate"));
|
|
19569
19670
|
}
|
|
19570
19671
|
/**
|
|
19672
|
+
* Where `@mastra/server` attaches, on `req.auth`, the request context its auth
|
|
19673
|
+
* resolved (user, permissions, roles, resource id, tenant, auth mode). A symbol
|
|
19674
|
+
* cannot come out of a token or JSON payload, so only server code can supply it.
|
|
19675
|
+
*/
|
|
19676
|
+
const MCP_TRUSTED_REQUEST_CONTEXT = Symbol.for("mastra.mcp.trustedRequestContext");
|
|
19677
|
+
const MASTRA_USER_KEY = "mastra__user";
|
|
19678
|
+
/**
|
|
19571
19679
|
* Builds the trusted application context for one request. Auth is re-derived from
|
|
19572
|
-
* the transport every time; nothing is carried between continuation rounds.
|
|
19680
|
+
* the transport every time; nothing is carried between continuation rounds. When
|
|
19681
|
+
* the request came through a Mastra server route, the values its auth resolved are
|
|
19682
|
+
* copied in, so tools are authorized the same way as that server's routes. The W3C
|
|
19573
19683
|
* trace fields sent by the client are exposed under `traceContext` as opaque
|
|
19574
19684
|
* strings for observability only; they are never consulted for authorization.
|
|
19575
19685
|
*/
|
|
@@ -19579,6 +19689,12 @@ async function toRequestContext(ctx, mapAuthInfoToUser) {
|
|
|
19579
19689
|
if (traceContext) requestContext.set("traceContext", traceContext);
|
|
19580
19690
|
const authInfo = ctx.http?.authInfo;
|
|
19581
19691
|
if (!authInfo) return requestContext;
|
|
19692
|
+
const trusted = authInfo[MCP_TRUSTED_REQUEST_CONTEXT];
|
|
19693
|
+
if (trusted && typeof trusted === "object") {
|
|
19694
|
+
for (const [key, value] of Object.entries(trusted)) requestContext.set(key, value);
|
|
19695
|
+
const trustedUser = trusted[MASTRA_USER_KEY];
|
|
19696
|
+
if (trustedUser) requestContext.set("user", trustedUser);
|
|
19697
|
+
}
|
|
19582
19698
|
requestContext.set("authInfo", authInfo);
|
|
19583
19699
|
const user = await mapAuthInfoToUser?.({
|
|
19584
19700
|
authInfo,
|
|
@@ -22781,6 +22897,17 @@ function toSummary(listing) {
|
|
|
22781
22897
|
function isWorkflowTaskContext(context) {
|
|
22782
22898
|
return context?.kind === "workflow" && typeof context.runId === "string" && typeof context.workflowKey === "string";
|
|
22783
22899
|
}
|
|
22900
|
+
/**
|
|
22901
|
+
* A run's result with its step results read: a storage v2 result's `steps` is a loader that reads
|
|
22902
|
+
* them from storage, so a view, and the text a tool answers with, gets them as for v1.
|
|
22903
|
+
*/
|
|
22904
|
+
async function withLoadedSteps(result) {
|
|
22905
|
+
const steps = result.steps;
|
|
22906
|
+
return typeof steps === "function" ? {
|
|
22907
|
+
...result,
|
|
22908
|
+
steps: await steps()
|
|
22909
|
+
} : result;
|
|
22910
|
+
}
|
|
22784
22911
|
/** Statuses a run never leaves. */
|
|
22785
22912
|
const FINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
22786
22913
|
"success",
|
|
@@ -22846,6 +22973,136 @@ function stepAt(workflow, path) {
|
|
|
22846
22973
|
}
|
|
22847
22974
|
return step;
|
|
22848
22975
|
}
|
|
22976
|
+
// src/server/uri-template.ts
|
|
22977
|
+
/**
|
|
22978
|
+
* Whether `uri` is an RFC 6570 expansion of `template`. Decides membership only,
|
|
22979
|
+
* without extracting variables.
|
|
22980
|
+
*
|
|
22981
|
+
* The SDK's `UriTemplate.match` is a backtracking regex that takes minutes on a
|
|
22982
|
+
* few KB of client URI when variables are adjacent (`x://{a}-{b}-{c}-{d}`); this
|
|
22983
|
+
* walks the URI once per template segment instead.
|
|
22984
|
+
*
|
|
22985
|
+
* Plain `{x}` and `{+x}` must be non-empty, since an empty path segment never
|
|
22986
|
+
* names a resource. Outside `{+x}` and `{#x}`, values must be percent-encoded:
|
|
22987
|
+
* an ASCII reserved character other than `,` ends the value. Raw non-ASCII
|
|
22988
|
+
* characters are accepted because clients often send them unencoded.
|
|
22989
|
+
*/
|
|
22990
|
+
function matchesUriTemplate(template, uri) {
|
|
22991
|
+
return advance(uri, /* @__PURE__ */ new Set([0]), parse(template)).has(uri.length);
|
|
22992
|
+
}
|
|
22993
|
+
const encoded = (char) => /[\w\-.~,]/.test(char) || char.charCodeAt(0) > 127;
|
|
22994
|
+
const anything = () => true;
|
|
22995
|
+
const literal = (text) => ({
|
|
22996
|
+
kind: "literal",
|
|
22997
|
+
text
|
|
22998
|
+
});
|
|
22999
|
+
const run = (allowed, min = 0) => ({
|
|
23000
|
+
kind: "run",
|
|
23001
|
+
allowed,
|
|
23002
|
+
min
|
|
23003
|
+
});
|
|
23004
|
+
const optional = (...segments) => ({
|
|
23005
|
+
kind: "optional",
|
|
23006
|
+
segments
|
|
23007
|
+
});
|
|
23008
|
+
const repeat = (...segments) => ({
|
|
23009
|
+
kind: "repeat",
|
|
23010
|
+
segments
|
|
23011
|
+
});
|
|
23012
|
+
const choice = (options) => ({
|
|
23013
|
+
kind: "choice",
|
|
23014
|
+
options
|
|
23015
|
+
});
|
|
23016
|
+
function parse(template) {
|
|
23017
|
+
const segments = [];
|
|
23018
|
+
let i = 0;
|
|
23019
|
+
while (i < template.length) {
|
|
23020
|
+
const open = template.indexOf("{", i);
|
|
23021
|
+
const close = open === -1 ? -1 : template.indexOf("}", open);
|
|
23022
|
+
if (close === -1) {
|
|
23023
|
+
segments.push(literal(template.slice(i)));
|
|
23024
|
+
break;
|
|
23025
|
+
}
|
|
23026
|
+
if (open > i) segments.push(literal(template.slice(i, open)));
|
|
23027
|
+
segments.push(...expression(template.slice(open + 1, close)));
|
|
23028
|
+
i = close + 1;
|
|
23029
|
+
}
|
|
23030
|
+
return segments;
|
|
23031
|
+
}
|
|
23032
|
+
function expression(body) {
|
|
23033
|
+
const operator = "+#./;?&".includes(body[0] ?? "") ? body[0] : "";
|
|
23034
|
+
const specs = body.slice(operator.length).split(",").map((spec) => ({
|
|
23035
|
+
name: spec.replace(/[*]|:\d*$/g, "").trim(),
|
|
23036
|
+
exploded: spec.includes("*")
|
|
23037
|
+
})).filter((spec) => spec.name);
|
|
23038
|
+
switch (operator) {
|
|
23039
|
+
case "": return [run(encoded, 1)];
|
|
23040
|
+
case "+": return [run(anything, 1)];
|
|
23041
|
+
case "#": return [optional(literal("#"), run(anything))];
|
|
23042
|
+
case "/": return specs.map(({ exploded }) => exploded ? repeat(literal("/"), run(encoded)) : optional(literal("/"), run(encoded)));
|
|
23043
|
+
case ".": return specs.map(() => optional(literal("."), run(encoded)));
|
|
23044
|
+
case ";": return specs.map(({ name, exploded }) => (exploded ? repeat : optional)(literal(`;${name}`), optional(literal("="), run(encoded))));
|
|
23045
|
+
default: {
|
|
23046
|
+
const pair = ({ name, exploded }, separator) => {
|
|
23047
|
+
const first = [literal(`${separator}${name}=`), run(encoded)];
|
|
23048
|
+
return exploded ? [...first, repeat(literal(`&${name}=`), run(encoded))] : first;
|
|
23049
|
+
};
|
|
23050
|
+
const firstPresent = specs.map((spec, i) => [...pair(spec, operator), ...specs.slice(i + 1).map((later) => optional(...pair(later, "&")))]);
|
|
23051
|
+
return [optional(choice(firstPresent))];
|
|
23052
|
+
}
|
|
23053
|
+
}
|
|
23054
|
+
}
|
|
23055
|
+
/** Every URI offset reachable after matching `segments` from any offset in `from`. */
|
|
23056
|
+
function advance(uri, from, segments) {
|
|
23057
|
+
let positions = from;
|
|
23058
|
+
for (const segment of segments) {
|
|
23059
|
+
if (positions.size === 0) break;
|
|
23060
|
+
positions = step(uri, positions, segment);
|
|
23061
|
+
}
|
|
23062
|
+
return positions;
|
|
23063
|
+
}
|
|
23064
|
+
function step(uri, positions, segment) {
|
|
23065
|
+
const next = /* @__PURE__ */ new Set();
|
|
23066
|
+
switch (segment.kind) {
|
|
23067
|
+
case "literal":
|
|
23068
|
+
for (const p of positions) if (uri.startsWith(segment.text, p)) next.add(p + segment.text.length);
|
|
23069
|
+
return next;
|
|
23070
|
+
case "choice":
|
|
23071
|
+
for (const option of segment.options) for (const p of advance(uri, positions, option)) next.add(p);
|
|
23072
|
+
return next;
|
|
23073
|
+
case "run": {
|
|
23074
|
+
let end = 0;
|
|
23075
|
+
for (const p of [...positions].sort((a, b) => a - b)) {
|
|
23076
|
+
const covered = p < end && next.has(p);
|
|
23077
|
+
if (segment.min === 0) next.add(p);
|
|
23078
|
+
if (covered) continue;
|
|
23079
|
+
end = p;
|
|
23080
|
+
for (let width = charWidth(uri, end, segment.allowed); width > 0; width = charWidth(uri, end, segment.allowed)) next.add(end += width);
|
|
23081
|
+
}
|
|
23082
|
+
return next;
|
|
23083
|
+
}
|
|
23084
|
+
case "optional":
|
|
23085
|
+
for (const p of positions) next.add(p);
|
|
23086
|
+
for (const p of advance(uri, positions, segment.segments)) next.add(p);
|
|
23087
|
+
return next;
|
|
23088
|
+
case "repeat": {
|
|
23089
|
+
for (const p of positions) next.add(p);
|
|
23090
|
+
let frontier = positions;
|
|
23091
|
+
while (frontier.size > 0) {
|
|
23092
|
+
const reached = [...advance(uri, frontier, segment.segments)].filter((p) => !next.has(p));
|
|
23093
|
+
for (const p of reached) next.add(p);
|
|
23094
|
+
frontier = new Set(reached);
|
|
23095
|
+
}
|
|
23096
|
+
return next;
|
|
23097
|
+
}
|
|
23098
|
+
}
|
|
23099
|
+
}
|
|
23100
|
+
/** Characters a run consumes at `i`: a whole `%HH` triplet, one allowed character, or none. */
|
|
23101
|
+
function charWidth(uri, i, allowed) {
|
|
23102
|
+
if (i >= uri.length) return 0;
|
|
23103
|
+
if (uri[i] === "%") return /^%[0-9A-Fa-f]{2}/.test(uri.slice(i, i + 3)) ? 3 : 0;
|
|
23104
|
+
return allowed(uri[i]) ? 1 : 0;
|
|
23105
|
+
}
|
|
22849
23106
|
// src/server/server.ts
|
|
22850
23107
|
const EMPTY_OBJECT_SCHEMA = {
|
|
22851
23108
|
type: "object",
|
|
@@ -23050,11 +23307,11 @@ var MCPServer = class extends MCPServerBase {
|
|
|
23050
23307
|
inputSchema: workflow.inputSchema,
|
|
23051
23308
|
mcp: { toolType: "workflow" },
|
|
23052
23309
|
execute: async (inputData, context) => {
|
|
23053
|
-
return (await workflow.createRun({ runId: context?.requestContext?.get("runId") })).start({
|
|
23310
|
+
return withLoadedSteps(await (await workflow.createRun({ runId: context?.requestContext?.get("runId") })).start({
|
|
23054
23311
|
inputData,
|
|
23055
23312
|
requestContext: context?.requestContext,
|
|
23056
23313
|
tracingContext: context?.tracingContext
|
|
23057
|
-
});
|
|
23314
|
+
}));
|
|
23058
23315
|
}
|
|
23059
23316
|
}));
|
|
23060
23317
|
}
|
|
@@ -23844,7 +24101,7 @@ var MCPServer = class extends MCPServerBase {
|
|
|
23844
24101
|
if (!workflow) throw new Error(`Workflow '${workflowKey}' is not served`);
|
|
23845
24102
|
const input = validateToolInput(workflow.inputSchema, args, name);
|
|
23846
24103
|
if (input.error) {
|
|
23847
|
-
this.logger.warn(`Tool '${name}' rejected its input.`, {
|
|
24104
|
+
this.logger.warn(`Tool '${name}' rejected its input.`, { issuePaths: getValidationIssuePaths(input.error, workflow.inputSchema) });
|
|
23848
24105
|
return errorResult$1(input.error.message);
|
|
23849
24106
|
}
|
|
23850
24107
|
const context = {
|
|
@@ -23867,11 +24124,11 @@ var MCPServer = class extends MCPServerBase {
|
|
|
23867
24124
|
};
|
|
23868
24125
|
const start = (runTracing) => {
|
|
23869
24126
|
const run = workflow.createRun({ runId: context.runId });
|
|
23870
|
-
const result = run.then((started) => started.start({
|
|
24127
|
+
const result = run.then(async (started) => withLoadedSteps(await started.start({
|
|
23871
24128
|
inputData: input.data,
|
|
23872
24129
|
requestContext,
|
|
23873
24130
|
tracingContext: runTracing
|
|
23874
|
-
}));
|
|
24131
|
+
})));
|
|
23875
24132
|
const cancel = () => void run.then((started) => started.cancel()).catch((error) => this.logger.warn("Could not cancel workflow run", {
|
|
23876
24133
|
tool: name,
|
|
23877
24134
|
error
|
|
@@ -24000,12 +24257,12 @@ var MCPServer = class extends MCPServerBase {
|
|
|
24000
24257
|
error
|
|
24001
24258
|
})));
|
|
24002
24259
|
try {
|
|
24003
|
-
view = await run.resume({
|
|
24260
|
+
view = await withLoadedSteps(await run.resume({
|
|
24004
24261
|
step: answered.step,
|
|
24005
24262
|
resumeData: answer.content ?? {},
|
|
24006
24263
|
requestContext,
|
|
24007
24264
|
...span && { tracingContext: { currentSpan: span } }
|
|
24008
|
-
});
|
|
24265
|
+
}));
|
|
24009
24266
|
} catch (error) {
|
|
24010
24267
|
if (isResumeClaimLost(error)) return this.watchWorkflowRun(workflow, context, attempt.signal);
|
|
24011
24268
|
const now = await workflow.getWorkflowRunById(context.runId, { withNestedWorkflows: false });
|
|
@@ -24173,7 +24430,7 @@ var MCPServer = class extends MCPServerBase {
|
|
|
24173
24430
|
}
|
|
24174
24431
|
toCallToolResult(name, tool, value) {
|
|
24175
24432
|
if (isValidationError(value)) {
|
|
24176
|
-
this.logger.warn(`Tool '${name}' rejected its input.`, {
|
|
24433
|
+
this.logger.warn(`Tool '${name}' rejected its input.`, { issuePaths: getValidationIssuePaths(value, tool.parameters) });
|
|
24177
24434
|
return errorResult$1(value.message);
|
|
24178
24435
|
}
|
|
24179
24436
|
const resourceUri = uiResourceUri(tool.mcp?._meta);
|
|
@@ -24218,10 +24475,24 @@ var MCPServer = class extends MCPServerBase {
|
|
|
24218
24475
|
extra: toToolExecutionContext(ctx, this.name).extra,
|
|
24219
24476
|
requestContext
|
|
24220
24477
|
}) ?? []];
|
|
24478
|
+
const findResource = async (uri, ctx, requestContext) => {
|
|
24479
|
+
const listed = (await listResources(ctx, requestContext)).find((r) => r.uri === uri);
|
|
24480
|
+
if (listed || !options?.resourceTemplates) return listed;
|
|
24481
|
+
const template = (await options.resourceTemplates({
|
|
24482
|
+
extra: toToolExecutionContext(ctx, this.name).extra,
|
|
24483
|
+
requestContext
|
|
24484
|
+
})).find((t) => matchesUriTemplate(t.uriTemplate, uri));
|
|
24485
|
+
return template && {
|
|
24486
|
+
uri,
|
|
24487
|
+
name: template.name,
|
|
24488
|
+
mimeType: template.mimeType,
|
|
24489
|
+
_meta: template._meta
|
|
24490
|
+
};
|
|
24491
|
+
};
|
|
24221
24492
|
this.setTracedHandler(server, "resources/list", async (_request, ctx, trace) => ({ resources: await listResources(ctx, trace.requestContext) }));
|
|
24222
24493
|
this.setTracedHandler(server, "resources/read", async (request, ctx, trace) => {
|
|
24223
24494
|
const uri = request.params.uri;
|
|
24224
|
-
const resource =
|
|
24495
|
+
const resource = await findResource(uri, ctx, trace.requestContext);
|
|
24225
24496
|
if (!resource) throw new ProtocolError$1(ProtocolErrorCode$1.InvalidParams, `Resource not found: ${uri}`);
|
|
24226
24497
|
const html = this.appResourceHtml.get(uri);
|
|
24227
24498
|
if (html !== void 0) return { contents: [this.resourceContents(resource, { text: html })] };
|
|
@@ -24618,10 +24889,7 @@ var MCPServer = class extends MCPServerBase {
|
|
|
24618
24889
|
id: "MCP_SERVER_TOOL_EXECUTE_FAILED",
|
|
24619
24890
|
domain: ErrorDomain.MCP,
|
|
24620
24891
|
category: ErrorCategory.USER,
|
|
24621
|
-
details: {
|
|
24622
|
-
toolId,
|
|
24623
|
-
args: JSON.stringify(args)
|
|
24624
|
-
}
|
|
24892
|
+
details: { toolId }
|
|
24625
24893
|
}, error);
|
|
24626
24894
|
this.logger.trackException(mastraError);
|
|
24627
24895
|
throw mastraError;
|