@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.cjs
CHANGED
|
@@ -56,101 +56,6 @@ let _mastra_core_signals = require("@mastra/core/signals");
|
|
|
56
56
|
// src/client/types.ts
|
|
57
57
|
/** The current protocol revision; the one `/mcp` servers speak. */
|
|
58
58
|
const MCP_CLIENT_PROTOCOL_VERSION = "2026-07-28";
|
|
59
|
-
// ../schema-compat/dist/json-schema-traverse-D0CId4oM.js
|
|
60
|
-
var __create$1 = Object.create;
|
|
61
|
-
var __defProp$2 = Object.defineProperty;
|
|
62
|
-
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
63
|
-
var __getOwnPropNames$1 = Object.getOwnPropertyNames;
|
|
64
|
-
var __getProtoOf$1 = Object.getPrototypeOf;
|
|
65
|
-
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
66
|
-
var __commonJSMin$1 = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod, mod.exports), cb = null), mod.exports);
|
|
67
|
-
var __copyProps$1 = (to, from, except, desc) => {
|
|
68
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames$1(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
69
|
-
key = keys[i];
|
|
70
|
-
if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$2(to, key, {
|
|
71
|
-
get: ((k) => from[k]).bind(null, key),
|
|
72
|
-
enumerable: !(desc = __getOwnPropDesc$1(from, key)) || desc.enumerable
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
return to;
|
|
76
|
-
};
|
|
77
|
-
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", {
|
|
78
|
-
value: mod,
|
|
79
|
-
enumerable: true
|
|
80
|
-
}) : target, mod));
|
|
81
|
-
var require_json_schema_traverse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
|
|
82
|
-
var traverse = module.exports = function(schema, opts, cb) {
|
|
83
|
-
if (typeof opts == "function") {
|
|
84
|
-
cb = opts;
|
|
85
|
-
opts = {};
|
|
86
|
-
}
|
|
87
|
-
cb = opts.cb || cb;
|
|
88
|
-
var pre = typeof cb == "function" ? cb : cb.pre || function() {};
|
|
89
|
-
var post = cb.post || function() {};
|
|
90
|
-
_traverse(opts, pre, post, schema, "", schema);
|
|
91
|
-
};
|
|
92
|
-
traverse.keywords = {
|
|
93
|
-
additionalItems: true,
|
|
94
|
-
items: true,
|
|
95
|
-
contains: true,
|
|
96
|
-
additionalProperties: true,
|
|
97
|
-
propertyNames: true,
|
|
98
|
-
not: true,
|
|
99
|
-
if: true,
|
|
100
|
-
then: true,
|
|
101
|
-
else: true
|
|
102
|
-
};
|
|
103
|
-
traverse.arrayKeywords = {
|
|
104
|
-
items: true,
|
|
105
|
-
allOf: true,
|
|
106
|
-
anyOf: true,
|
|
107
|
-
oneOf: true
|
|
108
|
-
};
|
|
109
|
-
traverse.propsKeywords = {
|
|
110
|
-
$defs: true,
|
|
111
|
-
definitions: true,
|
|
112
|
-
properties: true,
|
|
113
|
-
patternProperties: true,
|
|
114
|
-
dependencies: true
|
|
115
|
-
};
|
|
116
|
-
traverse.skipKeywords = {
|
|
117
|
-
default: true,
|
|
118
|
-
enum: true,
|
|
119
|
-
const: true,
|
|
120
|
-
required: true,
|
|
121
|
-
maximum: true,
|
|
122
|
-
minimum: true,
|
|
123
|
-
exclusiveMaximum: true,
|
|
124
|
-
exclusiveMinimum: true,
|
|
125
|
-
multipleOf: true,
|
|
126
|
-
maxLength: true,
|
|
127
|
-
minLength: true,
|
|
128
|
-
pattern: true,
|
|
129
|
-
format: true,
|
|
130
|
-
maxItems: true,
|
|
131
|
-
minItems: true,
|
|
132
|
-
uniqueItems: true,
|
|
133
|
-
maxProperties: true,
|
|
134
|
-
minProperties: true
|
|
135
|
-
};
|
|
136
|
-
function _traverse(opts, pre, post, schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
|
|
137
|
-
if (schema && typeof schema == "object" && !Array.isArray(schema)) {
|
|
138
|
-
pre(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
139
|
-
for (var key in schema) {
|
|
140
|
-
var sch = schema[key];
|
|
141
|
-
if (Array.isArray(sch)) {
|
|
142
|
-
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);
|
|
143
|
-
} else if (key in traverse.propsKeywords) {
|
|
144
|
-
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);
|
|
145
|
-
} else if (key in traverse.keywords || opts.allKeys && !(key in traverse.skipKeywords)) _traverse(opts, pre, post, sch, jsonPtr + "/" + key, rootSchema, jsonPtr, key, schema);
|
|
146
|
-
}
|
|
147
|
-
post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
function escapeJsonPtr(str) {
|
|
151
|
-
return str.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
152
|
-
}
|
|
153
|
-
}));
|
|
154
59
|
// ../schema-compat/dist/esm-BG70JlG8.js
|
|
155
60
|
const ignoreOverride$1 = Symbol("Let zodToJsonSchema decide on which parser to use");
|
|
156
61
|
const defaultOptions$1 = {
|
|
@@ -1356,6 +1261,101 @@ var AiSdkSchemaWrapper = class {
|
|
|
1356
1261
|
function toStandardSchema$2(schema) {
|
|
1357
1262
|
return new AiSdkSchemaWrapper(schema);
|
|
1358
1263
|
}
|
|
1264
|
+
// ../schema-compat/dist/json-schema-traverse-D0CId4oM.js
|
|
1265
|
+
var __create$1 = Object.create;
|
|
1266
|
+
var __defProp$2 = Object.defineProperty;
|
|
1267
|
+
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
1268
|
+
var __getOwnPropNames$1 = Object.getOwnPropertyNames;
|
|
1269
|
+
var __getProtoOf$1 = Object.getPrototypeOf;
|
|
1270
|
+
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
1271
|
+
var __commonJSMin$1 = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod, mod.exports), cb = null), mod.exports);
|
|
1272
|
+
var __copyProps$1 = (to, from, except, desc) => {
|
|
1273
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames$1(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
1274
|
+
key = keys[i];
|
|
1275
|
+
if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$2(to, key, {
|
|
1276
|
+
get: ((k) => from[k]).bind(null, key),
|
|
1277
|
+
enumerable: !(desc = __getOwnPropDesc$1(from, key)) || desc.enumerable
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
return to;
|
|
1281
|
+
};
|
|
1282
|
+
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", {
|
|
1283
|
+
value: mod,
|
|
1284
|
+
enumerable: true
|
|
1285
|
+
}) : target, mod));
|
|
1286
|
+
var require_json_schema_traverse = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
|
|
1287
|
+
var traverse = module.exports = function(schema, opts, cb) {
|
|
1288
|
+
if (typeof opts == "function") {
|
|
1289
|
+
cb = opts;
|
|
1290
|
+
opts = {};
|
|
1291
|
+
}
|
|
1292
|
+
cb = opts.cb || cb;
|
|
1293
|
+
var pre = typeof cb == "function" ? cb : cb.pre || function() {};
|
|
1294
|
+
var post = cb.post || function() {};
|
|
1295
|
+
_traverse(opts, pre, post, schema, "", schema);
|
|
1296
|
+
};
|
|
1297
|
+
traverse.keywords = {
|
|
1298
|
+
additionalItems: true,
|
|
1299
|
+
items: true,
|
|
1300
|
+
contains: true,
|
|
1301
|
+
additionalProperties: true,
|
|
1302
|
+
propertyNames: true,
|
|
1303
|
+
not: true,
|
|
1304
|
+
if: true,
|
|
1305
|
+
then: true,
|
|
1306
|
+
else: true
|
|
1307
|
+
};
|
|
1308
|
+
traverse.arrayKeywords = {
|
|
1309
|
+
items: true,
|
|
1310
|
+
allOf: true,
|
|
1311
|
+
anyOf: true,
|
|
1312
|
+
oneOf: true
|
|
1313
|
+
};
|
|
1314
|
+
traverse.propsKeywords = {
|
|
1315
|
+
$defs: true,
|
|
1316
|
+
definitions: true,
|
|
1317
|
+
properties: true,
|
|
1318
|
+
patternProperties: true,
|
|
1319
|
+
dependencies: true
|
|
1320
|
+
};
|
|
1321
|
+
traverse.skipKeywords = {
|
|
1322
|
+
default: true,
|
|
1323
|
+
enum: true,
|
|
1324
|
+
const: true,
|
|
1325
|
+
required: true,
|
|
1326
|
+
maximum: true,
|
|
1327
|
+
minimum: true,
|
|
1328
|
+
exclusiveMaximum: true,
|
|
1329
|
+
exclusiveMinimum: true,
|
|
1330
|
+
multipleOf: true,
|
|
1331
|
+
maxLength: true,
|
|
1332
|
+
minLength: true,
|
|
1333
|
+
pattern: true,
|
|
1334
|
+
format: true,
|
|
1335
|
+
maxItems: true,
|
|
1336
|
+
minItems: true,
|
|
1337
|
+
uniqueItems: true,
|
|
1338
|
+
maxProperties: true,
|
|
1339
|
+
minProperties: true
|
|
1340
|
+
};
|
|
1341
|
+
function _traverse(opts, pre, post, schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
|
|
1342
|
+
if (schema && typeof schema == "object" && !Array.isArray(schema)) {
|
|
1343
|
+
pre(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
1344
|
+
for (var key in schema) {
|
|
1345
|
+
var sch = schema[key];
|
|
1346
|
+
if (Array.isArray(sch)) {
|
|
1347
|
+
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);
|
|
1348
|
+
} else if (key in traverse.propsKeywords) {
|
|
1349
|
+
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);
|
|
1350
|
+
} else if (key in traverse.keywords || opts.allKeys && !(key in traverse.skipKeywords)) _traverse(opts, pre, post, sch, jsonPtr + "/" + key, rootSchema, jsonPtr, key, schema);
|
|
1351
|
+
}
|
|
1352
|
+
post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
function escapeJsonPtr(str) {
|
|
1356
|
+
return str.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
1357
|
+
}
|
|
1358
|
+
}));
|
|
1359
1359
|
// ../schema-compat/dist/json-schema-BdCwqjfN.js
|
|
1360
1360
|
var require_code$1 = /* @__PURE__ */ __commonJSMin$1(((exports) => {
|
|
1361
1361
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -14411,6 +14411,35 @@ function isReconnectableMCPError(error) {
|
|
|
14411
14411
|
const errorMessage = error.message.toLowerCase();
|
|
14412
14412
|
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");
|
|
14413
14413
|
}
|
|
14414
|
+
const CONNECTION_NOT_ESTABLISHED_CODES = /* @__PURE__ */ new Set([
|
|
14415
|
+
"ECONNREFUSED",
|
|
14416
|
+
"ENOTFOUND",
|
|
14417
|
+
"EAI_AGAIN",
|
|
14418
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
14419
|
+
]);
|
|
14420
|
+
const REJECTED_BEFORE_DISPATCH_STATUSES = /* @__PURE__ */ new Set([
|
|
14421
|
+
400,
|
|
14422
|
+
401,
|
|
14423
|
+
403,
|
|
14424
|
+
404
|
|
14425
|
+
]);
|
|
14426
|
+
/**
|
|
14427
|
+
* Whether a reconnectable failure proves the request never reached the server's
|
|
14428
|
+
* handler, so sending it again cannot repeat its effects.
|
|
14429
|
+
*
|
|
14430
|
+
* A reset socket (`fetch failed` with `UND_ERR_SOCKET`), a cut-off response
|
|
14431
|
+
* (`terminated`) or a closed transport (`Connection closed`) can all follow a
|
|
14432
|
+
* request the server already received and ran, so they return false.
|
|
14433
|
+
*/
|
|
14434
|
+
function isUnsentRequestError(error) {
|
|
14435
|
+
if (!isReconnectableMCPError(error)) return false;
|
|
14436
|
+
const { httpStatus, code } = getMCPDiscoveryErrorDetails(error);
|
|
14437
|
+
if (typeof code === "number") return false;
|
|
14438
|
+
if (httpStatus !== void 0) return REJECTED_BEFORE_DISPATCH_STATUSES.has(httpStatus);
|
|
14439
|
+
const message = error.message.toLowerCase();
|
|
14440
|
+
if (message.includes("not connected") || message.includes("econnrefused") || message.includes("connection refused") || /\bhttp 40[0134]\b/.test(message)) return true;
|
|
14441
|
+
return typeof code === "string" && CONNECTION_NOT_ESTABLISHED_CODES.has(code);
|
|
14442
|
+
}
|
|
14414
14443
|
const GATEWAY_UNAVAILABLE_STATUSES = /* @__PURE__ */ new Set([
|
|
14415
14444
|
502,
|
|
14416
14445
|
503,
|
|
@@ -15977,6 +16006,50 @@ function runOutsideDatadogTraceScope(callback) {
|
|
|
15977
16006
|
if (!scope) return callback();
|
|
15978
16007
|
return scope.activate(null, callback);
|
|
15979
16008
|
}
|
|
16009
|
+
const LOGGABLE_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
16010
|
+
"Error",
|
|
16011
|
+
"TypeError",
|
|
16012
|
+
"RangeError",
|
|
16013
|
+
"SyntaxError",
|
|
16014
|
+
"AbortError",
|
|
16015
|
+
"TimeoutError",
|
|
16016
|
+
"McpError",
|
|
16017
|
+
"ProtocolError",
|
|
16018
|
+
"SdkError",
|
|
16019
|
+
"SdkHttpError",
|
|
16020
|
+
"SseError",
|
|
16021
|
+
"StreamableHTTPError",
|
|
16022
|
+
"UnauthorizedError",
|
|
16023
|
+
"OAuthError",
|
|
16024
|
+
"UnsupportedProtocolVersionError"
|
|
16025
|
+
]);
|
|
16026
|
+
const LOGGABLE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
16027
|
+
"ECONNRESET",
|
|
16028
|
+
"ECONNREFUSED",
|
|
16029
|
+
"ECONNABORTED",
|
|
16030
|
+
"ETIMEDOUT",
|
|
16031
|
+
"ENOTFOUND",
|
|
16032
|
+
"EPIPE",
|
|
16033
|
+
"EAI_AGAIN",
|
|
16034
|
+
"ABORT_ERR",
|
|
16035
|
+
"UND_ERR_SOCKET",
|
|
16036
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
16037
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
16038
|
+
"UND_ERR_BODY_TIMEOUT"
|
|
16039
|
+
]);
|
|
16040
|
+
/**
|
|
16041
|
+
* Names a tool-call failure for logs without its message: server error text can echo the submitted
|
|
16042
|
+
* arguments back (Issue #29318). The full error still reaches the caller.
|
|
16043
|
+
*/
|
|
16044
|
+
function errorKind(error) {
|
|
16045
|
+
if (error instanceof _mastra_core_error.MastraError) return error.id;
|
|
16046
|
+
if (error instanceof Error) {
|
|
16047
|
+
const name = LOGGABLE_ERROR_NAMES.has(error.name) ? error.name : "Error";
|
|
16048
|
+
const code = error.code;
|
|
16049
|
+
return typeof code === "number" || typeof code === "string" && LOGGABLE_ERROR_CODES.has(code) ? `${name} (${code})` : name;
|
|
16050
|
+
}
|
|
16051
|
+
return typeof error;
|
|
16052
|
+
}
|
|
15980
16053
|
/**
|
|
15981
16054
|
* Convert an MCP LoggingLevel to a logger method name that exists in our logger
|
|
15982
16055
|
*/
|
|
@@ -17123,10 +17196,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
17123
17196
|
});
|
|
17124
17197
|
return res && finishToolCall(res);
|
|
17125
17198
|
}
|
|
17126
|
-
this.log("debug", `Executing tool: ${tool.name}`, {
|
|
17127
|
-
toolArgs: input,
|
|
17128
|
-
runId: context?.runId
|
|
17129
|
-
});
|
|
17199
|
+
this.log("debug", `Executing tool: ${tool.name}`, { runId: context?.runId });
|
|
17130
17200
|
const progressMeta = this.enableProgressTracking ? { progressToken: context?.runId || crypto.randomUUID() } : void 0;
|
|
17131
17201
|
const _meta = this.requestMeta({
|
|
17132
17202
|
...context?._meta,
|
|
@@ -17155,7 +17225,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
17155
17225
|
const finishToolCall = async (res) => {
|
|
17156
17226
|
if (res.isError && this.onToolError === "throw") {
|
|
17157
17227
|
const errorText = extractToolErrorText(res.content);
|
|
17158
|
-
this.log("debug", `Tool reported an error: ${tool.name}
|
|
17228
|
+
this.log("debug", `Tool reported an error: ${tool.name}`);
|
|
17159
17229
|
throw new _mastra_core_error.MastraError({
|
|
17160
17230
|
id: "MCP_CLIENT_TOOL_EXECUTION_FAILED",
|
|
17161
17231
|
domain: _mastra_core_error.ErrorDomain.MCP,
|
|
@@ -17174,7 +17244,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
17174
17244
|
const validationSchema = await getOutputValidationSchema();
|
|
17175
17245
|
const validation = (0, _mastra_core_tools.validateToolOutput)(validationSchema, res.structuredContent, tool.name);
|
|
17176
17246
|
if (validation.error) {
|
|
17177
|
-
this.log("debug", `Tool output failed schema validation: ${tool.name}`, {
|
|
17247
|
+
this.log("debug", `Tool output failed schema validation: ${tool.name}`, { issuePaths: (0, _mastra_core_tools.getValidationIssuePaths)(validation.error, validationSchema, "output") });
|
|
17178
17248
|
return validation.error;
|
|
17179
17249
|
}
|
|
17180
17250
|
}
|
|
@@ -17187,25 +17257,40 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
17187
17257
|
try {
|
|
17188
17258
|
return await executeToolCall();
|
|
17189
17259
|
} catch (e) {
|
|
17190
|
-
|
|
17191
|
-
|
|
17260
|
+
const isToolExecutionError = e instanceof _mastra_core_error.MastraError && (e.id === "MCP_CLIENT_TOOL_EXECUTION_FAILED" || e.id.startsWith("MCP_CLIENT_TOOL_TASK_"));
|
|
17261
|
+
if (!isToolExecutionError && isReconnectableMCPError(e) && !isUnsentRequestError(e)) {
|
|
17262
|
+
if (annotations?.readOnlyHint === true || annotations?.idempotentHint === true) {
|
|
17263
|
+
this.log("debug", `Retrying replay-safe tool ${tool.name} after a transport error`, { error: errorKind(e) });
|
|
17264
|
+
if (this.transport !== failedTransport || this.reconnectPromise) await this.reconnectAfterTransportFailure(failedTransport, lifecycleGeneration);
|
|
17265
|
+
return await executeToolCall();
|
|
17266
|
+
}
|
|
17267
|
+
this.log("error", `Lost the connection during tool ${tool.name}; it may have run`, { error: errorKind(e) });
|
|
17268
|
+
throw new _mastra_core_error.MastraError({
|
|
17269
|
+
id: "MCP_CLIENT_TOOL_CALL_OUTCOME_UNKNOWN",
|
|
17270
|
+
domain: _mastra_core_error.ErrorDomain.MCP,
|
|
17271
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
17272
|
+
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.`,
|
|
17273
|
+
details: {
|
|
17274
|
+
toolName: tool.name,
|
|
17275
|
+
serverName: this.name
|
|
17276
|
+
}
|
|
17277
|
+
}, e);
|
|
17278
|
+
}
|
|
17279
|
+
if (!isToolExecutionError && isReconnectableMCPError(e)) {
|
|
17280
|
+
this.log("debug", `Transport error detected for tool ${tool.name}, attempting reconnection...`, { error: errorKind(e) });
|
|
17192
17281
|
try {
|
|
17193
17282
|
await this.reconnectAfterTransportFailure(failedTransport, lifecycleGeneration);
|
|
17194
17283
|
this.log("debug", `Retrying tool ${tool.name} after reconnection...`);
|
|
17195
17284
|
return await executeToolCall();
|
|
17196
17285
|
} catch (reconnectError) {
|
|
17197
17286
|
this.log("error", `Reconnection or retry failed for tool ${tool.name}`, {
|
|
17198
|
-
originalError:
|
|
17199
|
-
reconnectError:
|
|
17200
|
-
toolArgs: input
|
|
17287
|
+
originalError: errorKind(e),
|
|
17288
|
+
reconnectError: errorKind(reconnectError)
|
|
17201
17289
|
});
|
|
17202
17290
|
throw reconnectError;
|
|
17203
17291
|
}
|
|
17204
17292
|
}
|
|
17205
|
-
this.log("error", `Error calling tool: ${tool.name}`, {
|
|
17206
|
-
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
|
|
17207
|
-
toolArgs: input
|
|
17208
|
-
});
|
|
17293
|
+
this.log("error", `Error calling tool: ${tool.name}`, { error: errorKind(e) });
|
|
17209
17294
|
throw e;
|
|
17210
17295
|
}
|
|
17211
17296
|
});
|
|
@@ -17633,12 +17718,12 @@ async function createOAuthCallbackServer(options) {
|
|
|
17633
17718
|
},
|
|
17634
17719
|
close() {
|
|
17635
17720
|
settle({ error: /* @__PURE__ */ new Error("OAuth callback server closed before receiving an authorization code") });
|
|
17636
|
-
server.closeIdleConnections();
|
|
17637
17721
|
return new Promise((resolve, reject) => {
|
|
17638
17722
|
server.close((error) => {
|
|
17639
17723
|
if (error && error.code !== "ERR_SERVER_NOT_RUNNING") reject(error);
|
|
17640
17724
|
else resolve();
|
|
17641
17725
|
});
|
|
17726
|
+
server.closeAllConnections();
|
|
17642
17727
|
});
|
|
17643
17728
|
}
|
|
17644
17729
|
};
|
|
@@ -19007,7 +19092,7 @@ onListChanged: async (serverName, handler) => {
|
|
|
19007
19092
|
const errors = {};
|
|
19008
19093
|
const errorDetails = {};
|
|
19009
19094
|
const durations = {};
|
|
19010
|
-
const settled = await this.discoverAcrossServers((serverName) => this.getToolsForServer(serverName), {
|
|
19095
|
+
const settled = await this.discoverAcrossServers(async (serverName) => modelVisibleTools(await this.getToolsForServer(serverName)), {
|
|
19011
19096
|
errorId: "MCP_CLIENT_GET_TOOLS_FAILED",
|
|
19012
19097
|
logMessage: "Failed to list tools from server:"
|
|
19013
19098
|
}, options);
|
|
@@ -19062,7 +19147,7 @@ onListChanged: async (serverName, handler) => {
|
|
|
19062
19147
|
const errors = {};
|
|
19063
19148
|
const errorDetails = {};
|
|
19064
19149
|
const durations = {};
|
|
19065
|
-
const settled = await this.discoverAcrossServers((serverName) => this.getToolsForServer(serverName), {
|
|
19150
|
+
const settled = await this.discoverAcrossServers(async (serverName) => modelVisibleTools(await this.getToolsForServer(serverName)), {
|
|
19066
19151
|
errorId: "MCP_CLIENT_GET_TOOLSETS_FAILED",
|
|
19067
19152
|
logMessage: "Failed to list toolsets from server:"
|
|
19068
19153
|
}, options);
|
|
@@ -19126,7 +19211,7 @@ onListChanged: async (serverName, handler) => {
|
|
|
19126
19211
|
const errorDetails = {};
|
|
19127
19212
|
const durations = {};
|
|
19128
19213
|
const settled = await this.discoverAcrossServers(async (serverName) => {
|
|
19129
|
-
return (await this.getConnectedClientForServer(serverName)).toolDefinitions();
|
|
19214
|
+
return modelVisibleDefinitions(await (await this.getConnectedClientForServer(serverName)).toolDefinitions());
|
|
19130
19215
|
}, {
|
|
19131
19216
|
errorId: "MCP_CLIENT_GET_TOOL_DEFINITIONS_FAILED",
|
|
19132
19217
|
logMessage: "Failed to list tool definitions from server:"
|
|
@@ -19195,7 +19280,7 @@ onListChanged: async (serverName, handler) => {
|
|
|
19195
19280
|
this.logger.warn("Skipping cached MCP tool definitions for a server that is no longer configured", { serverName });
|
|
19196
19281
|
continue;
|
|
19197
19282
|
}
|
|
19198
|
-
for (const [toolName, definition] of Object.entries(definitions)) try {
|
|
19283
|
+
for (const [toolName, definition] of Object.entries(modelVisibleDefinitions(definitions))) try {
|
|
19199
19284
|
tools[`${serverName}_${toolName}`] = await this.toolFromDefinition({
|
|
19200
19285
|
serverName,
|
|
19201
19286
|
definition
|
|
@@ -19463,6 +19548,22 @@ onListChanged: async (serverName, handler) => {
|
|
|
19463
19548
|
return {};
|
|
19464
19549
|
}
|
|
19465
19550
|
};
|
|
19551
|
+
/**
|
|
19552
|
+
* Whether a tool may be handed to the model. MCP App servers mark helpers their app calls itself
|
|
19553
|
+
* with `_meta.ui.visibility` lacking `'model'`; per the MCP Apps spec, hosts must not give those
|
|
19554
|
+
* to the model. They stay callable by the app through the server.
|
|
19555
|
+
*/
|
|
19556
|
+
function isModelVisible(meta) {
|
|
19557
|
+
const ui = meta?.ui;
|
|
19558
|
+
const visibility = ui && typeof ui === "object" && "visibility" in ui ? ui.visibility : void 0;
|
|
19559
|
+
return !Array.isArray(visibility) || visibility.includes("model");
|
|
19560
|
+
}
|
|
19561
|
+
function modelVisibleTools(tools) {
|
|
19562
|
+
return Object.fromEntries(Object.entries(tools).filter(([, tool]) => isModelVisible(tool.mcp?._meta)));
|
|
19563
|
+
}
|
|
19564
|
+
function modelVisibleDefinitions(definitions) {
|
|
19565
|
+
return Object.fromEntries(Object.entries(definitions).filter(([, definition]) => isModelVisible(definition._meta)));
|
|
19566
|
+
}
|
|
19466
19567
|
// src/server/actions.ts
|
|
19467
19568
|
/** Runtime tool catalogue mutations. Every change is published to listening clients. */
|
|
19468
19569
|
var ServerToolActions = class {
|
|
@@ -19594,8 +19695,17 @@ function callerTrace(ctx) {
|
|
|
19594
19695
|
return callerTraceContext(meta?.traceparent, meta?.tracestate) ?? callerTraceContext(headers?.get("traceparent"), headers?.get("tracestate"));
|
|
19595
19696
|
}
|
|
19596
19697
|
/**
|
|
19698
|
+
* Where `@mastra/server` attaches, on `req.auth`, the request context its auth
|
|
19699
|
+
* resolved (user, permissions, roles, resource id, tenant, auth mode). A symbol
|
|
19700
|
+
* cannot come out of a token or JSON payload, so only server code can supply it.
|
|
19701
|
+
*/
|
|
19702
|
+
const MCP_TRUSTED_REQUEST_CONTEXT = Symbol.for("mastra.mcp.trustedRequestContext");
|
|
19703
|
+
const MASTRA_USER_KEY = "mastra__user";
|
|
19704
|
+
/**
|
|
19597
19705
|
* Builds the trusted application context for one request. Auth is re-derived from
|
|
19598
|
-
* the transport every time; nothing is carried between continuation rounds.
|
|
19706
|
+
* the transport every time; nothing is carried between continuation rounds. When
|
|
19707
|
+
* the request came through a Mastra server route, the values its auth resolved are
|
|
19708
|
+
* copied in, so tools are authorized the same way as that server's routes. The W3C
|
|
19599
19709
|
* trace fields sent by the client are exposed under `traceContext` as opaque
|
|
19600
19710
|
* strings for observability only; they are never consulted for authorization.
|
|
19601
19711
|
*/
|
|
@@ -19605,6 +19715,12 @@ async function toRequestContext(ctx, mapAuthInfoToUser) {
|
|
|
19605
19715
|
if (traceContext) requestContext.set("traceContext", traceContext);
|
|
19606
19716
|
const authInfo = ctx.http?.authInfo;
|
|
19607
19717
|
if (!authInfo) return requestContext;
|
|
19718
|
+
const trusted = authInfo[MCP_TRUSTED_REQUEST_CONTEXT];
|
|
19719
|
+
if (trusted && typeof trusted === "object") {
|
|
19720
|
+
for (const [key, value] of Object.entries(trusted)) requestContext.set(key, value);
|
|
19721
|
+
const trustedUser = trusted[MASTRA_USER_KEY];
|
|
19722
|
+
if (trustedUser) requestContext.set("user", trustedUser);
|
|
19723
|
+
}
|
|
19608
19724
|
requestContext.set("authInfo", authInfo);
|
|
19609
19725
|
const user = await mapAuthInfoToUser?.({
|
|
19610
19726
|
authInfo,
|
|
@@ -22807,6 +22923,17 @@ function toSummary(listing) {
|
|
|
22807
22923
|
function isWorkflowTaskContext(context) {
|
|
22808
22924
|
return context?.kind === "workflow" && typeof context.runId === "string" && typeof context.workflowKey === "string";
|
|
22809
22925
|
}
|
|
22926
|
+
/**
|
|
22927
|
+
* A run's result with its step results read: a storage v2 result's `steps` is a loader that reads
|
|
22928
|
+
* them from storage, so a view, and the text a tool answers with, gets them as for v1.
|
|
22929
|
+
*/
|
|
22930
|
+
async function withLoadedSteps(result) {
|
|
22931
|
+
const steps = result.steps;
|
|
22932
|
+
return typeof steps === "function" ? {
|
|
22933
|
+
...result,
|
|
22934
|
+
steps: await steps()
|
|
22935
|
+
} : result;
|
|
22936
|
+
}
|
|
22810
22937
|
/** Statuses a run never leaves. */
|
|
22811
22938
|
const FINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
22812
22939
|
"success",
|
|
@@ -22872,6 +22999,136 @@ function stepAt(workflow, path) {
|
|
|
22872
22999
|
}
|
|
22873
23000
|
return step;
|
|
22874
23001
|
}
|
|
23002
|
+
// src/server/uri-template.ts
|
|
23003
|
+
/**
|
|
23004
|
+
* Whether `uri` is an RFC 6570 expansion of `template`. Decides membership only,
|
|
23005
|
+
* without extracting variables.
|
|
23006
|
+
*
|
|
23007
|
+
* The SDK's `UriTemplate.match` is a backtracking regex that takes minutes on a
|
|
23008
|
+
* few KB of client URI when variables are adjacent (`x://{a}-{b}-{c}-{d}`); this
|
|
23009
|
+
* walks the URI once per template segment instead.
|
|
23010
|
+
*
|
|
23011
|
+
* Plain `{x}` and `{+x}` must be non-empty, since an empty path segment never
|
|
23012
|
+
* names a resource. Outside `{+x}` and `{#x}`, values must be percent-encoded:
|
|
23013
|
+
* an ASCII reserved character other than `,` ends the value. Raw non-ASCII
|
|
23014
|
+
* characters are accepted because clients often send them unencoded.
|
|
23015
|
+
*/
|
|
23016
|
+
function matchesUriTemplate(template, uri) {
|
|
23017
|
+
return advance(uri, /* @__PURE__ */ new Set([0]), parse(template)).has(uri.length);
|
|
23018
|
+
}
|
|
23019
|
+
const encoded = (char) => /[\w\-.~,]/.test(char) || char.charCodeAt(0) > 127;
|
|
23020
|
+
const anything = () => true;
|
|
23021
|
+
const literal = (text) => ({
|
|
23022
|
+
kind: "literal",
|
|
23023
|
+
text
|
|
23024
|
+
});
|
|
23025
|
+
const run = (allowed, min = 0) => ({
|
|
23026
|
+
kind: "run",
|
|
23027
|
+
allowed,
|
|
23028
|
+
min
|
|
23029
|
+
});
|
|
23030
|
+
const optional = (...segments) => ({
|
|
23031
|
+
kind: "optional",
|
|
23032
|
+
segments
|
|
23033
|
+
});
|
|
23034
|
+
const repeat = (...segments) => ({
|
|
23035
|
+
kind: "repeat",
|
|
23036
|
+
segments
|
|
23037
|
+
});
|
|
23038
|
+
const choice = (options) => ({
|
|
23039
|
+
kind: "choice",
|
|
23040
|
+
options
|
|
23041
|
+
});
|
|
23042
|
+
function parse(template) {
|
|
23043
|
+
const segments = [];
|
|
23044
|
+
let i = 0;
|
|
23045
|
+
while (i < template.length) {
|
|
23046
|
+
const open = template.indexOf("{", i);
|
|
23047
|
+
const close = open === -1 ? -1 : template.indexOf("}", open);
|
|
23048
|
+
if (close === -1) {
|
|
23049
|
+
segments.push(literal(template.slice(i)));
|
|
23050
|
+
break;
|
|
23051
|
+
}
|
|
23052
|
+
if (open > i) segments.push(literal(template.slice(i, open)));
|
|
23053
|
+
segments.push(...expression(template.slice(open + 1, close)));
|
|
23054
|
+
i = close + 1;
|
|
23055
|
+
}
|
|
23056
|
+
return segments;
|
|
23057
|
+
}
|
|
23058
|
+
function expression(body) {
|
|
23059
|
+
const operator = "+#./;?&".includes(body[0] ?? "") ? body[0] : "";
|
|
23060
|
+
const specs = body.slice(operator.length).split(",").map((spec) => ({
|
|
23061
|
+
name: spec.replace(/[*]|:\d*$/g, "").trim(),
|
|
23062
|
+
exploded: spec.includes("*")
|
|
23063
|
+
})).filter((spec) => spec.name);
|
|
23064
|
+
switch (operator) {
|
|
23065
|
+
case "": return [run(encoded, 1)];
|
|
23066
|
+
case "+": return [run(anything, 1)];
|
|
23067
|
+
case "#": return [optional(literal("#"), run(anything))];
|
|
23068
|
+
case "/": return specs.map(({ exploded }) => exploded ? repeat(literal("/"), run(encoded)) : optional(literal("/"), run(encoded)));
|
|
23069
|
+
case ".": return specs.map(() => optional(literal("."), run(encoded)));
|
|
23070
|
+
case ";": return specs.map(({ name, exploded }) => (exploded ? repeat : optional)(literal(`;${name}`), optional(literal("="), run(encoded))));
|
|
23071
|
+
default: {
|
|
23072
|
+
const pair = ({ name, exploded }, separator) => {
|
|
23073
|
+
const first = [literal(`${separator}${name}=`), run(encoded)];
|
|
23074
|
+
return exploded ? [...first, repeat(literal(`&${name}=`), run(encoded))] : first;
|
|
23075
|
+
};
|
|
23076
|
+
const firstPresent = specs.map((spec, i) => [...pair(spec, operator), ...specs.slice(i + 1).map((later) => optional(...pair(later, "&")))]);
|
|
23077
|
+
return [optional(choice(firstPresent))];
|
|
23078
|
+
}
|
|
23079
|
+
}
|
|
23080
|
+
}
|
|
23081
|
+
/** Every URI offset reachable after matching `segments` from any offset in `from`. */
|
|
23082
|
+
function advance(uri, from, segments) {
|
|
23083
|
+
let positions = from;
|
|
23084
|
+
for (const segment of segments) {
|
|
23085
|
+
if (positions.size === 0) break;
|
|
23086
|
+
positions = step(uri, positions, segment);
|
|
23087
|
+
}
|
|
23088
|
+
return positions;
|
|
23089
|
+
}
|
|
23090
|
+
function step(uri, positions, segment) {
|
|
23091
|
+
const next = /* @__PURE__ */ new Set();
|
|
23092
|
+
switch (segment.kind) {
|
|
23093
|
+
case "literal":
|
|
23094
|
+
for (const p of positions) if (uri.startsWith(segment.text, p)) next.add(p + segment.text.length);
|
|
23095
|
+
return next;
|
|
23096
|
+
case "choice":
|
|
23097
|
+
for (const option of segment.options) for (const p of advance(uri, positions, option)) next.add(p);
|
|
23098
|
+
return next;
|
|
23099
|
+
case "run": {
|
|
23100
|
+
let end = 0;
|
|
23101
|
+
for (const p of [...positions].sort((a, b) => a - b)) {
|
|
23102
|
+
const covered = p < end && next.has(p);
|
|
23103
|
+
if (segment.min === 0) next.add(p);
|
|
23104
|
+
if (covered) continue;
|
|
23105
|
+
end = p;
|
|
23106
|
+
for (let width = charWidth(uri, end, segment.allowed); width > 0; width = charWidth(uri, end, segment.allowed)) next.add(end += width);
|
|
23107
|
+
}
|
|
23108
|
+
return next;
|
|
23109
|
+
}
|
|
23110
|
+
case "optional":
|
|
23111
|
+
for (const p of positions) next.add(p);
|
|
23112
|
+
for (const p of advance(uri, positions, segment.segments)) next.add(p);
|
|
23113
|
+
return next;
|
|
23114
|
+
case "repeat": {
|
|
23115
|
+
for (const p of positions) next.add(p);
|
|
23116
|
+
let frontier = positions;
|
|
23117
|
+
while (frontier.size > 0) {
|
|
23118
|
+
const reached = [...advance(uri, frontier, segment.segments)].filter((p) => !next.has(p));
|
|
23119
|
+
for (const p of reached) next.add(p);
|
|
23120
|
+
frontier = new Set(reached);
|
|
23121
|
+
}
|
|
23122
|
+
return next;
|
|
23123
|
+
}
|
|
23124
|
+
}
|
|
23125
|
+
}
|
|
23126
|
+
/** Characters a run consumes at `i`: a whole `%HH` triplet, one allowed character, or none. */
|
|
23127
|
+
function charWidth(uri, i, allowed) {
|
|
23128
|
+
if (i >= uri.length) return 0;
|
|
23129
|
+
if (uri[i] === "%") return /^%[0-9A-Fa-f]{2}/.test(uri.slice(i, i + 3)) ? 3 : 0;
|
|
23130
|
+
return allowed(uri[i]) ? 1 : 0;
|
|
23131
|
+
}
|
|
22875
23132
|
// src/server/server.ts
|
|
22876
23133
|
const EMPTY_OBJECT_SCHEMA = {
|
|
22877
23134
|
type: "object",
|
|
@@ -23076,11 +23333,11 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
23076
23333
|
inputSchema: workflow.inputSchema,
|
|
23077
23334
|
mcp: { toolType: "workflow" },
|
|
23078
23335
|
execute: async (inputData, context) => {
|
|
23079
|
-
return (await workflow.createRun({ runId: context?.requestContext?.get("runId") })).start({
|
|
23336
|
+
return withLoadedSteps(await (await workflow.createRun({ runId: context?.requestContext?.get("runId") })).start({
|
|
23080
23337
|
inputData,
|
|
23081
23338
|
requestContext: context?.requestContext,
|
|
23082
23339
|
tracingContext: context?.tracingContext
|
|
23083
|
-
});
|
|
23340
|
+
}));
|
|
23084
23341
|
}
|
|
23085
23342
|
}));
|
|
23086
23343
|
}
|
|
@@ -23870,7 +24127,7 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
23870
24127
|
if (!workflow) throw new Error(`Workflow '${workflowKey}' is not served`);
|
|
23871
24128
|
const input = (0, _mastra_core_tools.validateToolInput)(workflow.inputSchema, args, name);
|
|
23872
24129
|
if (input.error) {
|
|
23873
|
-
this.logger.warn(`Tool '${name}' rejected its input.`, {
|
|
24130
|
+
this.logger.warn(`Tool '${name}' rejected its input.`, { issuePaths: (0, _mastra_core_tools.getValidationIssuePaths)(input.error, workflow.inputSchema) });
|
|
23874
24131
|
return errorResult$1(input.error.message);
|
|
23875
24132
|
}
|
|
23876
24133
|
const context = {
|
|
@@ -23893,11 +24150,11 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
23893
24150
|
};
|
|
23894
24151
|
const start = (runTracing) => {
|
|
23895
24152
|
const run = workflow.createRun({ runId: context.runId });
|
|
23896
|
-
const result = run.then((started) => started.start({
|
|
24153
|
+
const result = run.then(async (started) => withLoadedSteps(await started.start({
|
|
23897
24154
|
inputData: input.data,
|
|
23898
24155
|
requestContext,
|
|
23899
24156
|
tracingContext: runTracing
|
|
23900
|
-
}));
|
|
24157
|
+
})));
|
|
23901
24158
|
const cancel = () => void run.then((started) => started.cancel()).catch((error) => this.logger.warn("Could not cancel workflow run", {
|
|
23902
24159
|
tool: name,
|
|
23903
24160
|
error
|
|
@@ -24026,12 +24283,12 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
24026
24283
|
error
|
|
24027
24284
|
})));
|
|
24028
24285
|
try {
|
|
24029
|
-
view = await run.resume({
|
|
24286
|
+
view = await withLoadedSteps(await run.resume({
|
|
24030
24287
|
step: answered.step,
|
|
24031
24288
|
resumeData: answer.content ?? {},
|
|
24032
24289
|
requestContext,
|
|
24033
24290
|
...span && { tracingContext: { currentSpan: span } }
|
|
24034
|
-
});
|
|
24291
|
+
}));
|
|
24035
24292
|
} catch (error) {
|
|
24036
24293
|
if (isResumeClaimLost(error)) return this.watchWorkflowRun(workflow, context, attempt.signal);
|
|
24037
24294
|
const now = await workflow.getWorkflowRunById(context.runId, { withNestedWorkflows: false });
|
|
@@ -24199,7 +24456,7 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
24199
24456
|
}
|
|
24200
24457
|
toCallToolResult(name, tool, value) {
|
|
24201
24458
|
if ((0, _mastra_core_tools.isValidationError)(value)) {
|
|
24202
|
-
this.logger.warn(`Tool '${name}' rejected its input.`, {
|
|
24459
|
+
this.logger.warn(`Tool '${name}' rejected its input.`, { issuePaths: (0, _mastra_core_tools.getValidationIssuePaths)(value, tool.parameters) });
|
|
24203
24460
|
return errorResult$1(value.message);
|
|
24204
24461
|
}
|
|
24205
24462
|
const resourceUri = uiResourceUri(tool.mcp?._meta);
|
|
@@ -24244,10 +24501,24 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
24244
24501
|
extra: toToolExecutionContext(ctx, this.name).extra,
|
|
24245
24502
|
requestContext
|
|
24246
24503
|
}) ?? []];
|
|
24504
|
+
const findResource = async (uri, ctx, requestContext) => {
|
|
24505
|
+
const listed = (await listResources(ctx, requestContext)).find((r) => r.uri === uri);
|
|
24506
|
+
if (listed || !options?.resourceTemplates) return listed;
|
|
24507
|
+
const template = (await options.resourceTemplates({
|
|
24508
|
+
extra: toToolExecutionContext(ctx, this.name).extra,
|
|
24509
|
+
requestContext
|
|
24510
|
+
})).find((t) => matchesUriTemplate(t.uriTemplate, uri));
|
|
24511
|
+
return template && {
|
|
24512
|
+
uri,
|
|
24513
|
+
name: template.name,
|
|
24514
|
+
mimeType: template.mimeType,
|
|
24515
|
+
_meta: template._meta
|
|
24516
|
+
};
|
|
24517
|
+
};
|
|
24247
24518
|
this.setTracedHandler(server, "resources/list", async (_request, ctx, trace) => ({ resources: await listResources(ctx, trace.requestContext) }));
|
|
24248
24519
|
this.setTracedHandler(server, "resources/read", async (request, ctx, trace) => {
|
|
24249
24520
|
const uri = request.params.uri;
|
|
24250
|
-
const resource =
|
|
24521
|
+
const resource = await findResource(uri, ctx, trace.requestContext);
|
|
24251
24522
|
if (!resource) throw new _modelcontextprotocol_server.ProtocolError(_modelcontextprotocol_server.ProtocolErrorCode.InvalidParams, `Resource not found: ${uri}`);
|
|
24252
24523
|
const html = this.appResourceHtml.get(uri);
|
|
24253
24524
|
if (html !== void 0) return { contents: [this.resourceContents(resource, { text: html })] };
|
|
@@ -24644,10 +24915,7 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
24644
24915
|
id: "MCP_SERVER_TOOL_EXECUTE_FAILED",
|
|
24645
24916
|
domain: _mastra_core_error.ErrorDomain.MCP,
|
|
24646
24917
|
category: _mastra_core_error.ErrorCategory.USER,
|
|
24647
|
-
details: {
|
|
24648
|
-
toolId,
|
|
24649
|
-
args: JSON.stringify(args)
|
|
24650
|
-
}
|
|
24918
|
+
details: { toolId }
|
|
24651
24919
|
}, error);
|
|
24652
24920
|
this.logger.trackException(mastraError);
|
|
24653
24921
|
throw mastraError;
|