@mastra/mcp 1.17.0-alpha.1 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +167 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/types.d.ts +29 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-auth-fga.md +26 -0
- package/dist/docs/references/docs-connections-overview.md +1 -1
- package/dist/docs/references/reference-tools-mcp-client.md +2 -0
- package/dist/docs/references/reference-tools-mcp-server.md +50 -2
- package/dist/index.cjs +315 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +318 -61
- package/dist/index.js.map +1 -1
- package/dist/server/mrtrElicitation.d.ts +39 -0
- package/dist/server/mrtrElicitation.d.ts.map +1 -0
- package/dist/server/promptActions.d.ts +8 -1
- package/dist/server/promptActions.d.ts.map +1 -1
- package/dist/server/resourceActions.d.ts +8 -1
- package/dist/server/resourceActions.d.ts.map +1 -1
- package/dist/server/server.d.ts +83 -17
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/toolActions.d.ts +8 -1
- package/dist/server/toolActions.d.ts.map +1 -1
- package/dist/server/types.d.ts +29 -1
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -5031,7 +5031,7 @@ const allowsEval = /* @__PURE__*/ cached(() => {
|
|
|
5031
5031
|
return false;
|
|
5032
5032
|
}
|
|
5033
5033
|
});
|
|
5034
|
-
function isPlainObject(o) {
|
|
5034
|
+
function isPlainObject$1(o) {
|
|
5035
5035
|
if (isObject(o) === false) return false;
|
|
5036
5036
|
const ctor = o.constructor;
|
|
5037
5037
|
if (ctor === void 0) return true;
|
|
@@ -5042,7 +5042,7 @@ function isPlainObject(o) {
|
|
|
5042
5042
|
return true;
|
|
5043
5043
|
}
|
|
5044
5044
|
function shallowClone(o) {
|
|
5045
|
-
if (isPlainObject(o)) return { ...o };
|
|
5045
|
+
if (isPlainObject$1(o)) return { ...o };
|
|
5046
5046
|
if (Array.isArray(o)) return [...o];
|
|
5047
5047
|
if (o instanceof Map) return new Map(o);
|
|
5048
5048
|
if (o instanceof Set) return new Set(o);
|
|
@@ -5125,7 +5125,7 @@ function omit(schema, mask) {
|
|
|
5125
5125
|
}));
|
|
5126
5126
|
}
|
|
5127
5127
|
function extend(schema, shape) {
|
|
5128
|
-
if (!isPlainObject(shape)) throw new Error("Invalid input to extend: expected a plain object");
|
|
5128
|
+
if (!isPlainObject$1(shape)) throw new Error("Invalid input to extend: expected a plain object");
|
|
5129
5129
|
const checks = schema._zod.def.checks;
|
|
5130
5130
|
if (checks && checks.length > 0) {
|
|
5131
5131
|
const existingShape = schema._zod.def.shape;
|
|
@@ -5141,7 +5141,7 @@ function extend(schema, shape) {
|
|
|
5141
5141
|
} }));
|
|
5142
5142
|
}
|
|
5143
5143
|
function safeExtend(schema, shape) {
|
|
5144
|
-
if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
5144
|
+
if (!isPlainObject$1(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
5145
5145
|
return clone(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
5146
5146
|
const _shape = {
|
|
5147
5147
|
...schema._zod.def.shape,
|
|
@@ -6826,7 +6826,7 @@ function mergeValues(a, b) {
|
|
|
6826
6826
|
valid: true,
|
|
6827
6827
|
data: a
|
|
6828
6828
|
};
|
|
6829
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
6829
|
+
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
6830
6830
|
const bKeys = Object.keys(b);
|
|
6831
6831
|
const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
|
|
6832
6832
|
const newObj = {
|
|
@@ -6994,7 +6994,7 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
|
|
|
6994
6994
|
$ZodType.init(inst, def);
|
|
6995
6995
|
inst._zod.parse = (payload, ctx) => {
|
|
6996
6996
|
const input = payload.value;
|
|
6997
|
-
if (!isPlainObject(input)) {
|
|
6997
|
+
if (!isPlainObject$1(input)) {
|
|
6998
6998
|
payload.issues.push({
|
|
6999
6999
|
expected: "record",
|
|
7000
7000
|
code: "invalid_type",
|
|
@@ -21322,44 +21322,21 @@ function extractModelTextFromToolContent(content) {
|
|
|
21322
21322
|
* `toModelOutput` can read MCP `content` without changing the execute return shape.
|
|
21323
21323
|
*/
|
|
21324
21324
|
const MCP_CALL_TOOL_CONTENT = Symbol.for("mastra.mcp.callToolContent");
|
|
21325
|
-
function
|
|
21326
|
-
|
|
21327
|
-
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
if (!reservation) return;
|
|
21332
|
-
const index = queue.indexOf(reservation);
|
|
21333
|
-
if (index !== -1) queue.splice(index, 1);
|
|
21334
|
-
}
|
|
21335
|
-
function attachMcpCallToolContent(structuredContent, content, scalarMcpContentQueue, reservation) {
|
|
21336
|
-
if (structuredContent !== null && typeof structuredContent === "object") {
|
|
21337
|
-
removeScalarMcpContentReservation(scalarMcpContentQueue, reservation);
|
|
21338
|
-
Object.defineProperty(structuredContent, MCP_CALL_TOOL_CONTENT, {
|
|
21339
|
-
value: content,
|
|
21340
|
-
enumerable: false,
|
|
21341
|
-
configurable: true
|
|
21342
|
-
});
|
|
21343
|
-
return structuredContent;
|
|
21344
|
-
}
|
|
21345
|
-
if (reservation) {
|
|
21346
|
-
reservation.output = structuredContent;
|
|
21347
|
-
reservation.content = content;
|
|
21348
|
-
reservation.ready = true;
|
|
21349
|
-
}
|
|
21325
|
+
function attachMcpCallToolContent(structuredContent, content) {
|
|
21326
|
+
if (structuredContent !== null && typeof structuredContent === "object") Object.defineProperty(structuredContent, MCP_CALL_TOOL_CONTENT, {
|
|
21327
|
+
value: content,
|
|
21328
|
+
enumerable: false,
|
|
21329
|
+
configurable: true
|
|
21330
|
+
});
|
|
21350
21331
|
return structuredContent;
|
|
21351
21332
|
}
|
|
21352
|
-
function getMcpCallToolContent(output
|
|
21353
|
-
if (output
|
|
21354
|
-
|
|
21355
|
-
if (attached !== void 0) return attached;
|
|
21356
|
-
}
|
|
21357
|
-
const index = scalarMcpContentQueue.findIndex((entry) => entry.ready && Object.is(entry.output, output));
|
|
21358
|
-
if (index !== -1) return scalarMcpContentQueue.splice(index, 1)[0]?.content;
|
|
21333
|
+
function getMcpCallToolContent(output) {
|
|
21334
|
+
if (output === null || typeof output !== "object") return void 0;
|
|
21335
|
+
return output[MCP_CALL_TOOL_CONTENT];
|
|
21359
21336
|
}
|
|
21360
|
-
function createStructuredToolToModelOutput(
|
|
21337
|
+
function createStructuredToolToModelOutput() {
|
|
21361
21338
|
return (output) => {
|
|
21362
|
-
const modelText = extractModelTextFromToolContent(getMcpCallToolContent(output
|
|
21339
|
+
const modelText = extractModelTextFromToolContent(getMcpCallToolContent(output));
|
|
21363
21340
|
if (modelText !== void 0) return {
|
|
21364
21341
|
type: "text",
|
|
21365
21342
|
value: modelText
|
|
@@ -21483,12 +21460,14 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
21483
21460
|
"io.modelcontextprotocol/ui": {}
|
|
21484
21461
|
}
|
|
21485
21462
|
};
|
|
21463
|
+
const versionNegotiation = server.protocolVersion === void 0 ? void 0 : { mode: server.protocolVersion === "auto" ? "auto" : { pin: server.protocolVersion } };
|
|
21486
21464
|
this.client = new _modelcontextprotocol_client.Client({
|
|
21487
21465
|
name,
|
|
21488
21466
|
version
|
|
21489
21467
|
}, {
|
|
21490
21468
|
capabilities: clientCapabilities,
|
|
21491
|
-
...server.jsonSchemaValidator ? { jsonSchemaValidator: server.jsonSchemaValidator } : {}
|
|
21469
|
+
...server.jsonSchemaValidator ? { jsonSchemaValidator: server.jsonSchemaValidator } : {},
|
|
21470
|
+
...versionNegotiation ? { versionNegotiation } : {}
|
|
21492
21471
|
});
|
|
21493
21472
|
this.setupLogging();
|
|
21494
21473
|
if (hasRoots) this.setupRootsHandler();
|
|
@@ -21656,7 +21635,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
21656
21635
|
this.markNeedsAuth(streamableTransport);
|
|
21657
21636
|
throw error;
|
|
21658
21637
|
}
|
|
21659
|
-
if (isUrlPolicyError(error)) throw error;
|
|
21638
|
+
if (isUrlPolicyError(error) || this.serverConfig.protocolVersion === "2026-07-28") throw error;
|
|
21660
21639
|
const status = error instanceof _modelcontextprotocol_client.SdkHttpError ? error.status : void 0;
|
|
21661
21640
|
if (status !== void 0 && !SSE_FALLBACK_STATUS_CODES.includes(status)) throw error;
|
|
21662
21641
|
shouldTrySSE = true;
|
|
@@ -22207,7 +22186,6 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
22207
22186
|
...toolMeta ? { _meta: toolMeta } : {},
|
|
22208
22187
|
...annotations ? { annotations } : {}
|
|
22209
22188
|
} } : {};
|
|
22210
|
-
const scalarMcpContentQueue = [];
|
|
22211
22189
|
const mastraTool = (0, _mastra_core_tools.createTool)({
|
|
22212
22190
|
id: `${this.name}_${tool.name}`,
|
|
22213
22191
|
description: tool.description || "",
|
|
@@ -22223,11 +22201,10 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
22223
22201
|
forwardInstructions: this.forwardInstructions,
|
|
22224
22202
|
instructionsMaxLength: this.instructionsMaxLength
|
|
22225
22203
|
},
|
|
22226
|
-
...tool.outputSchema ? { toModelOutput: createStructuredToolToModelOutput(
|
|
22204
|
+
...tool.outputSchema ? { toModelOutput: createStructuredToolToModelOutput() } : {},
|
|
22227
22205
|
execute: async (input, context) => {
|
|
22228
22206
|
if (serverMeta.connectFirst) await this.connect();
|
|
22229
22207
|
const operationContext = context?.requestContext ?? null;
|
|
22230
|
-
const scalarMcpContentReservation = tool.outputSchema ? reserveScalarMcpContent(scalarMcpContentQueue) : void 0;
|
|
22231
22208
|
return this.operationContextStore.run(operationContext, async () => {
|
|
22232
22209
|
const executeToolCall = async () => {
|
|
22233
22210
|
this.log("debug", `Executing tool: ${tool.name}`, {
|
|
@@ -22263,8 +22240,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
22263
22240
|
});
|
|
22264
22241
|
}
|
|
22265
22242
|
this.log("debug", `Tool executed successfully: ${tool.name}`);
|
|
22266
|
-
if (res.structuredContent !== void 0) return attachMcpCallToolContent(res.structuredContent, res.content
|
|
22267
|
-
removeScalarMcpContentReservation(scalarMcpContentQueue, scalarMcpContentReservation);
|
|
22243
|
+
if (res.structuredContent !== void 0) return attachMcpCallToolContent(res.structuredContent, res.content);
|
|
22268
22244
|
return res;
|
|
22269
22245
|
};
|
|
22270
22246
|
const failedTransport = this.transport;
|
|
@@ -22284,7 +22260,6 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
22284
22260
|
reconnectError: reconnectError instanceof Error ? reconnectError.stack : String(reconnectError),
|
|
22285
22261
|
toolArgs: input
|
|
22286
22262
|
});
|
|
22287
|
-
removeScalarMcpContentReservation(scalarMcpContentQueue, scalarMcpContentReservation);
|
|
22288
22263
|
throw reconnectError;
|
|
22289
22264
|
}
|
|
22290
22265
|
}
|
|
@@ -22292,7 +22267,6 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
|
|
|
22292
22267
|
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
|
|
22293
22268
|
toolArgs: input
|
|
22294
22269
|
});
|
|
22295
|
-
removeScalarMcpContentReservation(scalarMcpContentQueue, scalarMcpContentReservation);
|
|
22296
22270
|
throw e;
|
|
22297
22271
|
}
|
|
22298
22272
|
});
|
|
@@ -24320,7 +24294,7 @@ var streamSSE = (c, cb, onError) => {
|
|
|
24320
24294
|
return c.newResponse(stream.responseReadable);
|
|
24321
24295
|
};
|
|
24322
24296
|
//#endregion
|
|
24323
|
-
//#region ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@modelcontextprotocol/sdk/1.29.0/
|
|
24297
|
+
//#region ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@modelcontextprotocol/sdk/1.29.0/7d2f0982429dbe53f84f7249d02074ef571f5d1c95137997d9ed2dfe102a137b/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
24324
24298
|
const RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
|
|
24325
24299
|
/**
|
|
24326
24300
|
* Assert 'object' type schema.
|
|
@@ -26151,7 +26125,7 @@ union([
|
|
|
26151
26125
|
CreateTaskResultSchema
|
|
26152
26126
|
]);
|
|
26153
26127
|
//#endregion
|
|
26154
|
-
//#region ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/hono-mcp-server-sse-transport/0.0.7/
|
|
26128
|
+
//#region ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/hono-mcp-server-sse-transport/0.0.7/d5ae5a23aa2b79db7055621f11a7cbc8d27f7caba1eeb308ab2cf5bcb1a8e5b8/node_modules/hono-mcp-server-sse-transport/build/sse.js
|
|
26155
26129
|
const MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
|
|
26156
26130
|
var SSETransport = class {
|
|
26157
26131
|
messageUrl;
|
|
@@ -26226,6 +26200,132 @@ var SSETransport = class {
|
|
|
26226
26200
|
}
|
|
26227
26201
|
};
|
|
26228
26202
|
//#endregion
|
|
26203
|
+
//#region src/server/mrtrElicitation.ts
|
|
26204
|
+
/**
|
|
26205
|
+
* Elicitation on the 2026-07-28 protocol revision (multi-round-trip requests).
|
|
26206
|
+
*
|
|
26207
|
+
* The modern era has no server→client request channel, so `server.elicitInput()`
|
|
26208
|
+
* throws there by design. Instead, the `tools/call` handler must RETURN an
|
|
26209
|
+
* `input_required` result carrying the embedded elicitation request; the client
|
|
26210
|
+
* answers it locally and RETRIES the call with the response attached
|
|
26211
|
+
* (`inputResponses`). This module keeps the promise-shaped
|
|
26212
|
+
* `elicitation.sendRequest()` API tools already use by replaying the tool:
|
|
26213
|
+
*
|
|
26214
|
+
* 1. Each `sendRequest` call is assigned a deterministic sequence key.
|
|
26215
|
+
* 2. If the current (retried) request carries an answer for that key — either in
|
|
26216
|
+
* this round's `inputResponses` or in the accumulated `requestState` from
|
|
26217
|
+
* prior rounds — the promise resolves with it immediately.
|
|
26218
|
+
* 3. Otherwise a {@link ElicitationReplayInterrupt} is thrown; the `tools/call`
|
|
26219
|
+
* handler converts it into an {@link InputRequiredResult} return, and the
|
|
26220
|
+
* client's retry re-executes the tool from the top.
|
|
26221
|
+
*
|
|
26222
|
+
* Consequences tools must live with on the modern leg:
|
|
26223
|
+
* - Code before an unanswered elicitation re-executes on every round; keep side
|
|
26224
|
+
* effects idempotent or place them after the last elicitation.
|
|
26225
|
+
* - Elicitation order must be deterministic for a given input, since answers are
|
|
26226
|
+
* matched by call sequence.
|
|
26227
|
+
*/
|
|
26228
|
+
const ELICIT_KEY_PREFIX = "mastra_elicit_";
|
|
26229
|
+
/**
|
|
26230
|
+
* Thrown by the replay-based `sendRequest` when the current round carries no
|
|
26231
|
+
* answer for the elicitation. Never surfaces to tools or clients: the
|
|
26232
|
+
* `tools/call` handler converts it into an `input_required` result.
|
|
26233
|
+
*/
|
|
26234
|
+
var ElicitationReplayInterrupt = class extends Error {
|
|
26235
|
+
key;
|
|
26236
|
+
params;
|
|
26237
|
+
answered;
|
|
26238
|
+
constructor(key, params, answered) {
|
|
26239
|
+
super(`Elicitation '${key}' requires client input (multi-round-trip)`);
|
|
26240
|
+
this.key = key;
|
|
26241
|
+
this.params = params;
|
|
26242
|
+
this.answered = answered;
|
|
26243
|
+
this.name = "ElicitationReplayInterrupt";
|
|
26244
|
+
}
|
|
26245
|
+
};
|
|
26246
|
+
const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26247
|
+
const looksLikeElicitResult = (value) => isPlainObject(value) && typeof value.action === "string";
|
|
26248
|
+
/**
|
|
26249
|
+
* Decodes the accumulated prior-round answers from the request's opaque
|
|
26250
|
+
* `requestState` echo. The state round-trips through the client, so it is
|
|
26251
|
+
* attacker-controlled input on re-entry — but its only content is the client's
|
|
26252
|
+
* own past elicitation answers, which are untrusted user input either way, so
|
|
26253
|
+
* tampering grants the client nothing it does not already control. Anything
|
|
26254
|
+
* that does not parse as a map of elicitation results is discarded.
|
|
26255
|
+
*/
|
|
26256
|
+
const decodePriorAnswers = (extra) => {
|
|
26257
|
+
const raw = extra.mcpReq.requestState();
|
|
26258
|
+
if (typeof raw !== "string" || raw.length === 0) return {};
|
|
26259
|
+
try {
|
|
26260
|
+
const parsed = JSON.parse(raw);
|
|
26261
|
+
if (!isPlainObject(parsed)) return {};
|
|
26262
|
+
const answers = {};
|
|
26263
|
+
for (const [key, value] of Object.entries(parsed)) if (key.startsWith(ELICIT_KEY_PREFIX) && looksLikeElicitResult(value)) answers[key] = value;
|
|
26264
|
+
return answers;
|
|
26265
|
+
} catch {
|
|
26266
|
+
return {};
|
|
26267
|
+
}
|
|
26268
|
+
};
|
|
26269
|
+
/** This round's bare responses that answer our elicitation keys. */
|
|
26270
|
+
const currentRoundAnswers = (extra) => {
|
|
26271
|
+
const answers = {};
|
|
26272
|
+
for (const [key, value] of Object.entries(extra.mcpReq.inputResponses ?? {})) if (key.startsWith(ELICIT_KEY_PREFIX) && looksLikeElicitResult(value)) answers[key] = value;
|
|
26273
|
+
return answers;
|
|
26274
|
+
};
|
|
26275
|
+
/**
|
|
26276
|
+
* Whether this request is served on the 2026-07-28 era. Modern clients always
|
|
26277
|
+
* attach the reserved per-request `_meta` envelope (the 2026 codec enforces the
|
|
26278
|
+
* required keys at dispatch); legacy requests never carry it.
|
|
26279
|
+
*/
|
|
26280
|
+
const isModernEraRequest = (extra) => extra.mcpReq.envelope !== void 0;
|
|
26281
|
+
/**
|
|
26282
|
+
* Builds the replay-based {@link ElicitationActions} for one modern-era tool
|
|
26283
|
+
* execution. Answers already provided by the client resolve immediately; the
|
|
26284
|
+
* first unanswered elicitation throws {@link ElicitationReplayInterrupt}.
|
|
26285
|
+
*
|
|
26286
|
+
* The interrupt is also reported through `onInterrupt` before it is thrown:
|
|
26287
|
+
* tool wrappers (e.g. Mastra's tool builder) re-wrap thrown errors, so the
|
|
26288
|
+
* `tools/call` handler cannot rely on `instanceof` on whatever escapes the
|
|
26289
|
+
* tool — the out-of-band capture is the authoritative signal.
|
|
26290
|
+
*/
|
|
26291
|
+
const createReplayElicitation = (extra, onInterrupt) => {
|
|
26292
|
+
const prior = decodePriorAnswers(extra);
|
|
26293
|
+
const current = currentRoundAnswers(extra);
|
|
26294
|
+
const answered = {
|
|
26295
|
+
...prior,
|
|
26296
|
+
...current
|
|
26297
|
+
};
|
|
26298
|
+
let sequence = 0;
|
|
26299
|
+
return { sendRequest: async (request) => {
|
|
26300
|
+
const key = `${ELICIT_KEY_PREFIX}${sequence++}`;
|
|
26301
|
+
const answer = answered[key];
|
|
26302
|
+
if (answer !== void 0) return answer;
|
|
26303
|
+
const interrupt = new ElicitationReplayInterrupt(key, request, answered);
|
|
26304
|
+
onInterrupt(interrupt);
|
|
26305
|
+
throw interrupt;
|
|
26306
|
+
} };
|
|
26307
|
+
};
|
|
26308
|
+
/**
|
|
26309
|
+
* Converts a caught {@link ElicitationReplayInterrupt} into the
|
|
26310
|
+
* `input_required` result the `tools/call` handler returns to the client.
|
|
26311
|
+
* Prior answers travel in `requestState` because each retry only carries the
|
|
26312
|
+
* current round's `inputResponses`.
|
|
26313
|
+
*/
|
|
26314
|
+
const replayInterruptToInputRequired = (interrupt) => {
|
|
26315
|
+
const params = {
|
|
26316
|
+
mode: "form",
|
|
26317
|
+
...interrupt.params
|
|
26318
|
+
};
|
|
26319
|
+
return {
|
|
26320
|
+
resultType: "input_required",
|
|
26321
|
+
inputRequests: { [interrupt.key]: {
|
|
26322
|
+
method: "elicitation/create",
|
|
26323
|
+
params
|
|
26324
|
+
} },
|
|
26325
|
+
...Object.keys(interrupt.answered).length > 0 ? { requestState: JSON.stringify(interrupt.answered) } : {}
|
|
26326
|
+
};
|
|
26327
|
+
};
|
|
26328
|
+
//#endregion
|
|
26229
26329
|
//#region src/server/notificationBroadcast.ts
|
|
26230
26330
|
/**
|
|
26231
26331
|
* Sends a notification to every active server instance (the main stdio/SSE
|
|
@@ -26282,6 +26382,7 @@ var ServerPromptActions = class {
|
|
|
26282
26382
|
getLogger;
|
|
26283
26383
|
getSdkServers;
|
|
26284
26384
|
clearDefinedPrompts;
|
|
26385
|
+
getModernEraNotifier;
|
|
26285
26386
|
/**
|
|
26286
26387
|
* @internal
|
|
26287
26388
|
*/
|
|
@@ -26289,6 +26390,7 @@ var ServerPromptActions = class {
|
|
|
26289
26390
|
this.getLogger = dependencies.getLogger;
|
|
26290
26391
|
this.getSdkServers = dependencies.getSdkServers;
|
|
26291
26392
|
this.clearDefinedPrompts = dependencies.clearDefinedPrompts;
|
|
26393
|
+
this.getModernEraNotifier = dependencies.getModernEraNotifier;
|
|
26292
26394
|
}
|
|
26293
26395
|
/**
|
|
26294
26396
|
* Notifies clients that the overall list of available prompts has changed.
|
|
@@ -26307,6 +26409,7 @@ var ServerPromptActions = class {
|
|
|
26307
26409
|
async notifyListChanged() {
|
|
26308
26410
|
this.getLogger().info("Prompt list change externally notified. Clearing definedPrompts and sending notification.");
|
|
26309
26411
|
this.clearDefinedPrompts();
|
|
26412
|
+
this.getModernEraNotifier?.()?.promptsChanged();
|
|
26310
26413
|
await broadcastNotification({
|
|
26311
26414
|
servers: this.getSdkServers(),
|
|
26312
26415
|
send: (server) => server.sendPromptListChanged(),
|
|
@@ -26333,6 +26436,7 @@ var ServerResourceActions = class {
|
|
|
26333
26436
|
getSubscribedServers;
|
|
26334
26437
|
getLogger;
|
|
26335
26438
|
getSdkServers;
|
|
26439
|
+
getModernEraNotifier;
|
|
26336
26440
|
/**
|
|
26337
26441
|
* @internal
|
|
26338
26442
|
*/
|
|
@@ -26340,6 +26444,7 @@ var ServerResourceActions = class {
|
|
|
26340
26444
|
this.getSubscribedServers = dependencies.getSubscribedServers;
|
|
26341
26445
|
this.getLogger = dependencies.getLogger;
|
|
26342
26446
|
this.getSdkServers = dependencies.getSdkServers;
|
|
26447
|
+
this.getModernEraNotifier = dependencies.getModernEraNotifier;
|
|
26343
26448
|
}
|
|
26344
26449
|
/**
|
|
26345
26450
|
* Notifies subscribed clients that a specific resource has been updated.
|
|
@@ -26359,6 +26464,7 @@ var ServerResourceActions = class {
|
|
|
26359
26464
|
* ```
|
|
26360
26465
|
*/
|
|
26361
26466
|
async notifyUpdated({ uri }) {
|
|
26467
|
+
this.getModernEraNotifier?.()?.resourceUpdated(uri);
|
|
26362
26468
|
const subscribedServers = this.getSubscribedServers(uri);
|
|
26363
26469
|
if (subscribedServers.length === 0) {
|
|
26364
26470
|
this.getLogger().debug(`Resource ${uri} was updated, but no active subscriptions for it.`);
|
|
@@ -26391,6 +26497,7 @@ var ServerResourceActions = class {
|
|
|
26391
26497
|
*/
|
|
26392
26498
|
async notifyListChanged() {
|
|
26393
26499
|
this.getLogger().info("Resource list change externally notified. Sending notification.");
|
|
26500
|
+
this.getModernEraNotifier?.()?.resourcesChanged();
|
|
26394
26501
|
await broadcastNotification({
|
|
26395
26502
|
servers: this.getSdkServers(),
|
|
26396
26503
|
send: (server) => server.sendResourceListChanged(),
|
|
@@ -26416,6 +26523,7 @@ var ServerToolActions = class {
|
|
|
26416
26523
|
getSdkServers;
|
|
26417
26524
|
addTools;
|
|
26418
26525
|
removeTools;
|
|
26526
|
+
getModernEraNotifier;
|
|
26419
26527
|
/**
|
|
26420
26528
|
* @internal
|
|
26421
26529
|
*/
|
|
@@ -26424,6 +26532,7 @@ var ServerToolActions = class {
|
|
|
26424
26532
|
this.getSdkServers = dependencies.getSdkServers;
|
|
26425
26533
|
this.addTools = dependencies.addTools;
|
|
26426
26534
|
this.removeTools = dependencies.removeTools;
|
|
26535
|
+
this.getModernEraNotifier = dependencies.getModernEraNotifier;
|
|
26427
26536
|
}
|
|
26428
26537
|
/**
|
|
26429
26538
|
* Registers new tools on the running server and notifies connected clients
|
|
@@ -26482,6 +26591,7 @@ var ServerToolActions = class {
|
|
|
26482
26591
|
*/
|
|
26483
26592
|
async notifyListChanged() {
|
|
26484
26593
|
this.getLogger().info("Tool list changed. Sending notification.");
|
|
26594
|
+
this.getModernEraNotifier?.()?.toolsChanged();
|
|
26485
26595
|
await broadcastNotification({
|
|
26486
26596
|
servers: this.getSdkServers(),
|
|
26487
26597
|
send: (server) => server.sendToolListChanged(),
|
|
@@ -26522,6 +26632,14 @@ const LOG_LEVEL_SEVERITY = {
|
|
|
26522
26632
|
alert: 6,
|
|
26523
26633
|
emergency: 7
|
|
26524
26634
|
};
|
|
26635
|
+
const ACCEPTED_MODERN_ERA_HTTP_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
26636
|
+
"allowedHosts",
|
|
26637
|
+
"allowedOrigins",
|
|
26638
|
+
"enableDnsRebindingProtection",
|
|
26639
|
+
"serverless",
|
|
26640
|
+
"serverlessStreaming",
|
|
26641
|
+
"sessionIdGenerator"
|
|
26642
|
+
]);
|
|
26525
26643
|
/**
|
|
26526
26644
|
* MCPServer exposes Mastra tools, agents, and workflows as a Model Context Protocol (MCP) server.
|
|
26527
26645
|
*
|
|
@@ -26568,6 +26686,12 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
26568
26686
|
fga;
|
|
26569
26687
|
subscriptionsByInstance = /* @__PURE__ */ new WeakMap();
|
|
26570
26688
|
loggingLevels = /* @__PURE__ */ new WeakMap();
|
|
26689
|
+
protocolVersion;
|
|
26690
|
+
cacheHints;
|
|
26691
|
+
modernEraHandler;
|
|
26692
|
+
modernEraNodeHandler;
|
|
26693
|
+
stdioHandle;
|
|
26694
|
+
stdioServerInstance;
|
|
26571
26695
|
/**
|
|
26572
26696
|
* Provides methods to notify clients about resource changes.
|
|
26573
26697
|
*
|
|
@@ -26719,6 +26843,8 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
26719
26843
|
*/
|
|
26720
26844
|
constructor(opts) {
|
|
26721
26845
|
super(opts);
|
|
26846
|
+
this.protocolVersion = opts.protocolVersion;
|
|
26847
|
+
this.cacheHints = opts.cacheHints;
|
|
26722
26848
|
this.resourceOptions = this.mergeAppResources(opts.resources, opts.appResources);
|
|
26723
26849
|
this.hasUiResources = !!opts.appResources && Object.keys(opts.appResources).length > 0;
|
|
26724
26850
|
this.promptOptions = opts.prompts;
|
|
@@ -26744,7 +26870,8 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
26744
26870
|
}, {
|
|
26745
26871
|
capabilities,
|
|
26746
26872
|
...this.instructions ? { instructions: this.instructions } : {},
|
|
26747
|
-
...this.jsonSchemaValidator ? { jsonSchemaValidator: this.jsonSchemaValidator } : {}
|
|
26873
|
+
...this.jsonSchemaValidator ? { jsonSchemaValidator: this.jsonSchemaValidator } : {},
|
|
26874
|
+
...this.servesModernEra() && this.cacheHints ? { cacheHints: this.cacheHints } : {}
|
|
26748
26875
|
});
|
|
26749
26876
|
this.logger.info("Initialized MCPServer", {
|
|
26750
26877
|
name: this.name,
|
|
@@ -26755,23 +26882,27 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
26755
26882
|
});
|
|
26756
26883
|
this.sseHonoTransports = /* @__PURE__ */ new Map();
|
|
26757
26884
|
this.registerHandlersOnServer(this.server);
|
|
26885
|
+
const getModernEraNotifier = () => this.servesModernEra() ? this.modernEraHandler?.notify : void 0;
|
|
26758
26886
|
this.resources = new ServerResourceActions({
|
|
26759
26887
|
getSubscribedServers: (uri) => this.getAllSdkServers().filter((server) => this.subscriptionsByInstance.get(server)?.has(uri)),
|
|
26760
26888
|
getLogger: () => this.logger,
|
|
26761
|
-
getSdkServers: () => this.getAllSdkServers()
|
|
26889
|
+
getSdkServers: () => this.getAllSdkServers(),
|
|
26890
|
+
getModernEraNotifier
|
|
26762
26891
|
});
|
|
26763
26892
|
this.prompts = new ServerPromptActions({
|
|
26764
26893
|
getLogger: () => this.logger,
|
|
26765
26894
|
getSdkServers: () => this.getAllSdkServers(),
|
|
26766
26895
|
clearDefinedPrompts: () => {
|
|
26767
26896
|
this.definedPrompts = void 0;
|
|
26768
|
-
}
|
|
26897
|
+
},
|
|
26898
|
+
getModernEraNotifier
|
|
26769
26899
|
});
|
|
26770
26900
|
this.toolActions = new ServerToolActions({
|
|
26771
26901
|
getLogger: () => this.logger,
|
|
26772
26902
|
getSdkServers: () => this.getAllSdkServers(),
|
|
26773
26903
|
addTools: (tools) => this.addTools(tools),
|
|
26774
|
-
removeTools: (toolIds) => this.removeTools(toolIds)
|
|
26904
|
+
removeTools: (toolIds) => this.removeTools(toolIds),
|
|
26905
|
+
getModernEraNotifier
|
|
26775
26906
|
});
|
|
26776
26907
|
this.elicitation = { sendRequest: async (request, options) => {
|
|
26777
26908
|
return this.handleElicitationRequest(request, void 0, options);
|
|
@@ -26787,7 +26918,69 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
26787
26918
|
* cannot receive notifications.
|
|
26788
26919
|
*/
|
|
26789
26920
|
getAllSdkServers() {
|
|
26790
|
-
return [
|
|
26921
|
+
return [
|
|
26922
|
+
this.server,
|
|
26923
|
+
this.stdioServerInstance,
|
|
26924
|
+
...this.httpServerInstances.values()
|
|
26925
|
+
].filter((server) => server?.transport !== void 0);
|
|
26926
|
+
}
|
|
26927
|
+
/**
|
|
26928
|
+
* Whether the server is pinned to the `2026-07-28` protocol revision.
|
|
26929
|
+
* When false (the default), all behavior is byte-identical to the legacy era.
|
|
26930
|
+
*/
|
|
26931
|
+
servesModernEra() {
|
|
26932
|
+
return this.protocolVersion === "2026-07-28";
|
|
26933
|
+
}
|
|
26934
|
+
assertModernEraHTTPOptions(options) {
|
|
26935
|
+
if (!options) return;
|
|
26936
|
+
const incompatibleOptions = new Set(Object.keys(options).filter((option) => !ACCEPTED_MODERN_ERA_HTTP_OPTION_KEYS.has(option)));
|
|
26937
|
+
if (options.sessionIdGenerator !== void 0) incompatibleOptions.add("sessionIdGenerator");
|
|
26938
|
+
if (options.serverless === false) incompatibleOptions.add("serverless");
|
|
26939
|
+
if (options.serverlessStreaming === false) incompatibleOptions.add("serverlessStreaming");
|
|
26940
|
+
if (incompatibleOptions.size === 0) return;
|
|
26941
|
+
const names = [...incompatibleOptions].sort();
|
|
26942
|
+
throw new _mastra_core_error.MastraError({
|
|
26943
|
+
id: "MCP_SERVER_MODERN_HTTP_OPTIONS_INCOMPATIBLE",
|
|
26944
|
+
domain: _mastra_core_error.ErrorDomain.MCP,
|
|
26945
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
26946
|
+
text: `startHTTP options ${names.map((name) => `"${name}"`).join(", ")} are incompatible with protocolVersion "2026-07-28"`,
|
|
26947
|
+
details: { incompatibleOptions: names.join(", ") }
|
|
26948
|
+
});
|
|
26949
|
+
}
|
|
26950
|
+
validateHTTPRequestHeaders(req, res, options) {
|
|
26951
|
+
if (!options?.enableDnsRebindingProtection) return true;
|
|
26952
|
+
if (options.allowedHosts?.length) {
|
|
26953
|
+
if (!(0, _modelcontextprotocol_node.hostHeaderValidation)(options.allowedHosts.map((host) => new URL(`http://${host}`).hostname))(req, res)) return false;
|
|
26954
|
+
}
|
|
26955
|
+
if (options.allowedOrigins?.length) {
|
|
26956
|
+
if (!(0, _modelcontextprotocol_node.originValidation)(options.allowedOrigins.map((origin) => new URL(origin).hostname))(req, res)) return false;
|
|
26957
|
+
}
|
|
26958
|
+
return true;
|
|
26959
|
+
}
|
|
26960
|
+
/**
|
|
26961
|
+
* Lazily creates the dual-era HTTP handler used when `protocolVersion: '2026-07-28'`
|
|
26962
|
+
* is set: modern (per-request envelope) clients are served natively and legacy
|
|
26963
|
+
* clients are served through the SDK's built-in stateless fallback, both from the
|
|
26964
|
+
* same endpoint. Each request gets a fresh server instance from
|
|
26965
|
+
* `createServerInstance()`, so all registered handlers apply to both eras.
|
|
26966
|
+
*/
|
|
26967
|
+
getModernEraHandler() {
|
|
26968
|
+
if (!this.modernEraHandler) this.modernEraHandler = (0, _modelcontextprotocol_server.createMcpHandler)(() => this.createServerInstance(), {
|
|
26969
|
+
legacy: "stateless",
|
|
26970
|
+
onerror: (error) => {
|
|
26971
|
+
this.logger.error("MCP handler error", { error: error.toString() });
|
|
26972
|
+
}
|
|
26973
|
+
});
|
|
26974
|
+
return this.modernEraHandler;
|
|
26975
|
+
}
|
|
26976
|
+
/**
|
|
26977
|
+
* Node `(req, res)` adapter over the dual-era handler's web-standard `fetch`.
|
|
26978
|
+
*/
|
|
26979
|
+
getModernEraNodeHandler() {
|
|
26980
|
+
if (!this.modernEraNodeHandler) this.modernEraNodeHandler = (0, _modelcontextprotocol_node.toNodeHandler)(this.getModernEraHandler(), { onerror: (error) => {
|
|
26981
|
+
this.logger.error("MCP Node handler adapter error", { error: error.toString() });
|
|
26982
|
+
} });
|
|
26983
|
+
return this.modernEraNodeHandler;
|
|
26791
26984
|
}
|
|
26792
26985
|
/**
|
|
26793
26986
|
* Determines whether a log message at the given level should be sent to the
|
|
@@ -27024,7 +27217,8 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
27024
27217
|
}, {
|
|
27025
27218
|
capabilities,
|
|
27026
27219
|
...this.instructions ? { instructions: this.instructions } : {},
|
|
27027
|
-
...this.jsonSchemaValidator ? { jsonSchemaValidator: this.jsonSchemaValidator } : {}
|
|
27220
|
+
...this.jsonSchemaValidator ? { jsonSchemaValidator: this.jsonSchemaValidator } : {},
|
|
27221
|
+
...this.servesModernEra() && this.cacheHints ? { cacheHints: this.cacheHints } : {}
|
|
27028
27222
|
});
|
|
27029
27223
|
this.registerHandlersOnServer(serverInstance);
|
|
27030
27224
|
return serverInstance;
|
|
@@ -27067,6 +27261,7 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
27067
27261
|
serverInstance.setRequestHandler("tools/call", async (request, ctx) => {
|
|
27068
27262
|
const startTime = Date.now();
|
|
27069
27263
|
const extra = toMCPRequestHandlerExtra(ctx);
|
|
27264
|
+
let replayInterrupt;
|
|
27070
27265
|
try {
|
|
27071
27266
|
const tool = this.convertedTools[request.params.name];
|
|
27072
27267
|
if (!tool) {
|
|
@@ -27106,11 +27301,20 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
27106
27301
|
isError: true
|
|
27107
27302
|
};
|
|
27108
27303
|
}
|
|
27109
|
-
const sessionElicitation =
|
|
27304
|
+
const sessionElicitation = isModernEraRequest(extra) ? createReplayElicitation(extra, (interrupt) => {
|
|
27305
|
+
replayInterrupt = interrupt;
|
|
27306
|
+
}) : { sendRequest: async (request, options) => {
|
|
27110
27307
|
return this.handleElicitationRequest(request, serverInstance, options);
|
|
27111
27308
|
} };
|
|
27112
27309
|
const proxiedContext = await this.createProxiedRequestContext(extra);
|
|
27113
27310
|
const sessionLog = async (level, message, data) => {
|
|
27311
|
+
if (this.servesModernEra()) {
|
|
27312
|
+
await extra.mcpReq.log(level, {
|
|
27313
|
+
message,
|
|
27314
|
+
...data
|
|
27315
|
+
}, this.name);
|
|
27316
|
+
return;
|
|
27317
|
+
}
|
|
27114
27318
|
if (!this.shouldSendLog(serverInstance, level)) return;
|
|
27115
27319
|
await extra.sendNotification({
|
|
27116
27320
|
method: "notifications/message",
|
|
@@ -27200,6 +27404,10 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
27200
27404
|
}];
|
|
27201
27405
|
return response;
|
|
27202
27406
|
} catch (error) {
|
|
27407
|
+
if (replayInterrupt !== void 0) {
|
|
27408
|
+
this.logger.debug(`CallTool: Tool '${request.params.name}' requires client input (multi-round-trip).`, { key: replayInterrupt.key });
|
|
27409
|
+
return replayInterruptToInputRequired(replayInterrupt);
|
|
27410
|
+
}
|
|
27203
27411
|
const duration = Date.now() - startTime;
|
|
27204
27412
|
if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
|
|
27205
27413
|
const issues = error.issues;
|
|
@@ -27615,6 +27823,17 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
27615
27823
|
* ```
|
|
27616
27824
|
*/
|
|
27617
27825
|
async startStdio() {
|
|
27826
|
+
if (this.servesModernEra()) {
|
|
27827
|
+
this.stdioHandle = (0, _modelcontextprotocol_server_stdio.serveStdio)(() => {
|
|
27828
|
+
const serverInstance = this.createServerInstance();
|
|
27829
|
+
this.stdioServerInstance = serverInstance;
|
|
27830
|
+
return serverInstance;
|
|
27831
|
+
}, { onerror: (error) => {
|
|
27832
|
+
this.logger.error("MCP stdio handler error", { error: error.toString() });
|
|
27833
|
+
} });
|
|
27834
|
+
this.logger.info("Started MCP Server (stdio, 2026-07-28 dual-era)");
|
|
27835
|
+
return;
|
|
27836
|
+
}
|
|
27618
27837
|
this.stdioTransport = new _modelcontextprotocol_server_stdio.StdioServerTransport();
|
|
27619
27838
|
try {
|
|
27620
27839
|
await this.server.connect(this.stdioTransport);
|
|
@@ -27849,6 +28068,34 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
27849
28068
|
res.end();
|
|
27850
28069
|
return;
|
|
27851
28070
|
}
|
|
28071
|
+
if (this.servesModernEra()) this.assertModernEraHTTPOptions(options);
|
|
28072
|
+
if (!this.validateHTTPRequestHeaders(req, res, options)) return;
|
|
28073
|
+
if (this.servesModernEra()) {
|
|
28074
|
+
try {
|
|
28075
|
+
await this.getModernEraNodeHandler()(req, res);
|
|
28076
|
+
} catch (error) {
|
|
28077
|
+
const mastraError = new _mastra_core_error.MastraError({
|
|
28078
|
+
id: "MCP_SERVER_HTTP_CONNECTION_FAILED",
|
|
28079
|
+
domain: _mastra_core_error.ErrorDomain.MCP,
|
|
28080
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
28081
|
+
text: "Failed to handle MCP request on the 2026-07-28 protocol path"
|
|
28082
|
+
}, error);
|
|
28083
|
+
this.logger.trackException(mastraError);
|
|
28084
|
+
this.logger.error("Error handling HTTP request (2026-07-28 path)", { error: mastraError });
|
|
28085
|
+
if (!res.headersSent) {
|
|
28086
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
28087
|
+
res.end(JSON.stringify({
|
|
28088
|
+
jsonrpc: "2.0",
|
|
28089
|
+
error: {
|
|
28090
|
+
code: -32603,
|
|
28091
|
+
message: "Internal server error"
|
|
28092
|
+
},
|
|
28093
|
+
id: null
|
|
28094
|
+
}));
|
|
28095
|
+
}
|
|
28096
|
+
}
|
|
28097
|
+
return;
|
|
28098
|
+
}
|
|
27852
28099
|
if (options?.serverless || options && "sessionIdGenerator" in options && options.sessionIdGenerator === void 0) {
|
|
27853
28100
|
this.logger.debug("Running in stateless mode");
|
|
27854
28101
|
const enableJsonResponse = options?.enableJsonResponse ?? !options?.serverlessStreaming;
|
|
@@ -28157,6 +28404,16 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
|
|
|
28157
28404
|
*/
|
|
28158
28405
|
async close() {
|
|
28159
28406
|
try {
|
|
28407
|
+
if (this.stdioHandle) {
|
|
28408
|
+
await this.stdioHandle.close();
|
|
28409
|
+
this.stdioHandle = void 0;
|
|
28410
|
+
this.stdioServerInstance = void 0;
|
|
28411
|
+
}
|
|
28412
|
+
if (this.modernEraHandler) {
|
|
28413
|
+
await this.modernEraHandler.close();
|
|
28414
|
+
this.modernEraHandler = void 0;
|
|
28415
|
+
this.modernEraNodeHandler = void 0;
|
|
28416
|
+
}
|
|
28160
28417
|
if (this.stdioTransport) {
|
|
28161
28418
|
await this.stdioTransport.close?.();
|
|
28162
28419
|
this.stdioTransport = void 0;
|