@mastra/mcp 2.3.0 → 2.4.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/client.d.ts +2 -1
- package/dist/client/client.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 +0 -1
- package/dist/docs/references/reference-editor-tools.md +11 -3
- package/dist/docs/references/reference-migrations-mcp-v2.md +2 -2
- package/dist/docs/references/reference-tools-mcp-client.md +1 -1
- package/dist/docs/references/reference-tools-mcp-server.md +17 -0
- package/dist/index.cjs +152 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +152 -15
- package/dist/index.js.map +1 -1
- package/dist/server/request.d.ts +7 -0
- package/dist/server/request.d.ts.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/shared/index.d.ts +2 -1
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/trace-context.d.ts +51 -3
- package/dist/shared/trace-context.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -6,13 +6,13 @@ import { createTool, isValidationError, noopObserve, validateToolOutput } from "
|
|
|
6
6
|
import { Client, DEFAULT_REQUEST_TIMEOUT_MSEC, LOG_LEVEL_META_KEY, ProtocolErrorCode, StreamableHTTPClientTransport, UnauthorizedError, auth, buildDiscoveryUrls, discoverAuthorizationServerMetadata, discoverOAuthMetadata, discoverOAuthProtectedResourceMetadata, exchangeAuthorization, extractResourceMetadataUrl, parseErrorResponse, refreshAuthorization, selectResourceURL, startAuthorization, validateClientMetadataUrl } from "@modelcontextprotocol/client";
|
|
7
7
|
import { StdioClientTransport, getDefaultEnvironment } from "@modelcontextprotocol/client/stdio";
|
|
8
8
|
import { asyncExitHook, gracefulExit } from "exit-hook";
|
|
9
|
+
import { EntityType, SpanType, formatTraceparent, getOrCreateSpan, parseTraceparent, resolveExportedSpanId } from "@mastra/core/observability";
|
|
9
10
|
import { createHash, timingSafeEqual } from "crypto";
|
|
10
11
|
import equal from "fast-deep-equal";
|
|
11
12
|
import { createServer } from "http";
|
|
12
13
|
import { MCPServerBase } from "@mastra/core/mcp";
|
|
13
14
|
import { isStandardSchemaWithJSON, standardSchemaToJSONSchema, toStandardSchema } from "@mastra/core/schema";
|
|
14
15
|
import { readFileSync } from "fs";
|
|
15
|
-
import { EntityType, SpanType, getOrCreateSpan } from "@mastra/core/observability";
|
|
16
16
|
import { RequestContext } from "@mastra/core/request-context";
|
|
17
17
|
import { makeCoreTool } from "@mastra/core/utils";
|
|
18
18
|
import { PromptSchema } from "@modelcontextprotocol/core";
|
|
@@ -22301,21 +22301,21 @@ function rewrite(schema, depth, budget, isRoot = false) {
|
|
|
22301
22301
|
}
|
|
22302
22302
|
//#endregion
|
|
22303
22303
|
//#region src/shared/mastra-tool-meta.ts
|
|
22304
|
-
const MASTRA_META_KEY = "mastra";
|
|
22304
|
+
const MASTRA_META_KEY$1 = "mastra";
|
|
22305
22305
|
const STRICT_META_KEY = "strict";
|
|
22306
22306
|
function withMastraToolStrictMeta(meta, strict) {
|
|
22307
22307
|
if (strict == null) return meta;
|
|
22308
|
-
const mastraMeta = meta?.[MASTRA_META_KEY] && typeof meta[MASTRA_META_KEY] === "object" ? meta[MASTRA_META_KEY] : void 0;
|
|
22308
|
+
const mastraMeta = meta?.[MASTRA_META_KEY$1] && typeof meta[MASTRA_META_KEY$1] === "object" ? meta[MASTRA_META_KEY$1] : void 0;
|
|
22309
22309
|
return {
|
|
22310
22310
|
...meta ?? {},
|
|
22311
|
-
[MASTRA_META_KEY]: {
|
|
22311
|
+
[MASTRA_META_KEY$1]: {
|
|
22312
22312
|
...mastraMeta ?? {},
|
|
22313
22313
|
[STRICT_META_KEY]: strict
|
|
22314
22314
|
}
|
|
22315
22315
|
};
|
|
22316
22316
|
}
|
|
22317
22317
|
function getMastraToolStrictMeta(meta) {
|
|
22318
|
-
const mastraMeta = meta?.[MASTRA_META_KEY];
|
|
22318
|
+
const mastraMeta = meta?.[MASTRA_META_KEY$1];
|
|
22319
22319
|
if (!mastraMeta || typeof mastraMeta !== "object") return;
|
|
22320
22320
|
const strict = mastraMeta[STRICT_META_KEY];
|
|
22321
22321
|
return typeof strict === "boolean" ? strict : void 0;
|
|
@@ -22409,6 +22409,122 @@ function traceContextToMeta(traceContext) {
|
|
|
22409
22409
|
...traceContext.baggage !== void 0 ? { [BAGGAGE_META_KEY]: traceContext.baggage } : {}
|
|
22410
22410
|
};
|
|
22411
22411
|
}
|
|
22412
|
+
/**
|
|
22413
|
+
* Request params without the W3C trace fields in `_meta`. They are removed
|
|
22414
|
+
* whenever present, valid or not: a valid caller span is recorded as a link,
|
|
22415
|
+
* and `tracestate` and `baggage` are untrusted data the span doesn't need.
|
|
22416
|
+
*/
|
|
22417
|
+
function withoutTraceContext(params) {
|
|
22418
|
+
const meta = params?._meta;
|
|
22419
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta) || ![
|
|
22420
|
+
TRACEPARENT_META_KEY,
|
|
22421
|
+
TRACESTATE_META_KEY,
|
|
22422
|
+
BAGGAGE_META_KEY
|
|
22423
|
+
].some((key) => key in meta)) return params;
|
|
22424
|
+
const { [TRACEPARENT_META_KEY]: _traceparent, [TRACESTATE_META_KEY]: _tracestate, [BAGGAGE_META_KEY]: _baggage, ...restMeta } = meta;
|
|
22425
|
+
const { _meta, ...rest } = params;
|
|
22426
|
+
return Object.keys(restMeta).length > 0 ? {
|
|
22427
|
+
...rest,
|
|
22428
|
+
_meta: restMeta
|
|
22429
|
+
} : rest;
|
|
22430
|
+
}
|
|
22431
|
+
/**
|
|
22432
|
+
* Reads the caller's trace context from a `traceparent` and its `tracestate`.
|
|
22433
|
+
* A `traceparent` that doesn't parse yields nothing, and its `tracestate` is
|
|
22434
|
+
* ignored with it, as the W3C spec requires.
|
|
22435
|
+
*/
|
|
22436
|
+
function callerTraceContext(traceparent, tracestate) {
|
|
22437
|
+
const parts = parseTraceparent(traceparent);
|
|
22438
|
+
if (!parts) return void 0;
|
|
22439
|
+
const cappedTracestate = typeof tracestate === "string" ? capTracestate(tracestate) : void 0;
|
|
22440
|
+
return {
|
|
22441
|
+
link: {
|
|
22442
|
+
traceId: parts.traceId,
|
|
22443
|
+
spanId: parts.spanId
|
|
22444
|
+
},
|
|
22445
|
+
traceparent: traceparent.trim(),
|
|
22446
|
+
...cappedTracestate ? { tracestate: cappedTracestate } : {}
|
|
22447
|
+
};
|
|
22448
|
+
}
|
|
22449
|
+
const TRACESTATE_MAX_LENGTH = 512;
|
|
22450
|
+
const TRACESTATE_MAX_MEMBERS = 32;
|
|
22451
|
+
const TRACESTATE_LONG_MEMBER = 128;
|
|
22452
|
+
/**
|
|
22453
|
+
* Caps a `tracestate` at 512 characters the way the W3C spec asks: keep at most
|
|
22454
|
+
* 32 entries, drop entries longer than 128 characters first, then drop entries
|
|
22455
|
+
* from the end. Entries are never cut in the middle.
|
|
22456
|
+
* @see https://www.w3.org/TR/trace-context/#tracestate-limits
|
|
22457
|
+
*/
|
|
22458
|
+
function capTracestate(value) {
|
|
22459
|
+
let members = value.split(",").map((member) => member.trim()).filter(Boolean).slice(0, TRACESTATE_MAX_MEMBERS);
|
|
22460
|
+
const length = () => members.join(",").length;
|
|
22461
|
+
if (length() > TRACESTATE_MAX_LENGTH) members = members.filter((member) => member.length <= TRACESTATE_LONG_MEMBER);
|
|
22462
|
+
while (members.length > 0 && length() > TRACESTATE_MAX_LENGTH) members.pop();
|
|
22463
|
+
return members.length > 0 ? members.join(",") : void 0;
|
|
22464
|
+
}
|
|
22465
|
+
/**
|
|
22466
|
+
* The trace context that makes `span` the parent of an outgoing request. A span
|
|
22467
|
+
* that is not recorded, or whose ids are not W3C-sized, propagates nothing. A
|
|
22468
|
+
* span hidden from exporters is replaced by its closest exported ancestor.
|
|
22469
|
+
*/
|
|
22470
|
+
function traceContextFromSpan(span) {
|
|
22471
|
+
if (!span?.isValid) return void 0;
|
|
22472
|
+
const traceparent = formatTraceparent(span.traceId, resolveExportedSpanId(span) ?? "", true);
|
|
22473
|
+
return parseTraceparent(traceparent) ? { traceparent } : void 0;
|
|
22474
|
+
}
|
|
22475
|
+
/**
|
|
22476
|
+
* Reply `_meta` key under which a Mastra server returns the `traceparent` of the
|
|
22477
|
+
* span that served the request, so the caller can link back to it.
|
|
22478
|
+
*/
|
|
22479
|
+
const MASTRA_META_KEY = "mastra";
|
|
22480
|
+
const SERVER_TRACEPARENT_KEY = "traceparent";
|
|
22481
|
+
/**
|
|
22482
|
+
* Adds the `traceparent` of `span`, the span serving the request, to the reply
|
|
22483
|
+
* `_meta`. Only callers that sent their own trace context get it back.
|
|
22484
|
+
*/
|
|
22485
|
+
function withServerTraceContext(result, span, callerSentTrace) {
|
|
22486
|
+
const traceparent = callerSentTrace ? traceContextFromSpan(span)?.traceparent : void 0;
|
|
22487
|
+
if (!traceparent || !result || typeof result !== "object" || Array.isArray(result)) return result;
|
|
22488
|
+
const meta = result._meta ?? {};
|
|
22489
|
+
const mastraMeta = meta[MASTRA_META_KEY];
|
|
22490
|
+
return {
|
|
22491
|
+
...result,
|
|
22492
|
+
_meta: {
|
|
22493
|
+
...meta,
|
|
22494
|
+
[MASTRA_META_KEY]: {
|
|
22495
|
+
...mastraMeta && typeof mastraMeta === "object" ? mastraMeta : {},
|
|
22496
|
+
[SERVER_TRACEPARENT_KEY]: traceparent
|
|
22497
|
+
}
|
|
22498
|
+
}
|
|
22499
|
+
};
|
|
22500
|
+
}
|
|
22501
|
+
/**
|
|
22502
|
+
* Splits the server's span out of a reply: returns the span the server named in
|
|
22503
|
+
* its reply `_meta`, if any, and the reply without that key.
|
|
22504
|
+
*/
|
|
22505
|
+
function takeServerTraceContext(result) {
|
|
22506
|
+
const meta = result?._meta;
|
|
22507
|
+
const mastraMeta = meta?.[MASTRA_META_KEY];
|
|
22508
|
+
if (!mastraMeta || typeof mastraMeta !== "object" || !(SERVER_TRACEPARENT_KEY in mastraMeta)) return { result };
|
|
22509
|
+
const { [SERVER_TRACEPARENT_KEY]: traceparent, ...restMastra } = mastraMeta;
|
|
22510
|
+
const { [MASTRA_META_KEY]: _mastra, ...restMeta } = meta;
|
|
22511
|
+
const nextMeta = Object.keys(restMastra).length > 0 ? {
|
|
22512
|
+
...restMeta,
|
|
22513
|
+
[MASTRA_META_KEY]: restMastra
|
|
22514
|
+
} : restMeta;
|
|
22515
|
+
const { _meta, ...rest } = result;
|
|
22516
|
+
const parts = parseTraceparent(traceparent);
|
|
22517
|
+
return {
|
|
22518
|
+
result: Object.keys(nextMeta).length > 0 ? {
|
|
22519
|
+
...rest,
|
|
22520
|
+
_meta: nextMeta
|
|
22521
|
+
} : rest,
|
|
22522
|
+
...parts ? { serverSpan: {
|
|
22523
|
+
traceId: parts.traceId,
|
|
22524
|
+
spanId: parts.spanId
|
|
22525
|
+
} } : {}
|
|
22526
|
+
};
|
|
22527
|
+
}
|
|
22412
22528
|
//#endregion
|
|
22413
22529
|
//#region src/client/actions/progress.ts
|
|
22414
22530
|
/**
|
|
@@ -23316,10 +23432,11 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
23316
23432
|
/**
|
|
23317
23433
|
* Request metadata every outgoing request carries: the per-request log-level
|
|
23318
23434
|
* opt-in (when enabled) and the W3C trace fields resolved for this request,
|
|
23319
|
-
* merged under caller-supplied keys.
|
|
23435
|
+
* merged under caller-supplied keys. A configured `traceContext` provider owns
|
|
23436
|
+
* the trace fields; without one they name `span`, the span making the request.
|
|
23320
23437
|
*/
|
|
23321
|
-
requestMeta(meta) {
|
|
23322
|
-
const traceContext = this.serverConfig.traceContext
|
|
23438
|
+
requestMeta(meta, span) {
|
|
23439
|
+
const traceContext = this.serverConfig.traceContext ? this.serverConfig.traceContext() : traceContextFromSpan(span);
|
|
23323
23440
|
const merged = {
|
|
23324
23441
|
...this.serverLogLevel ? { [LOG_LEVEL_META_KEY]: this.serverLogLevel } : {},
|
|
23325
23442
|
...traceContext ? traceContextToMeta(traceContext) : {},
|
|
@@ -24059,15 +24176,17 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
24059
24176
|
const _meta = this.requestMeta({
|
|
24060
24177
|
...context?._meta,
|
|
24061
24178
|
...progressMeta
|
|
24062
|
-
});
|
|
24063
|
-
const res = await this.client.callTool({
|
|
24179
|
+
}, context?.tracingContext?.currentSpan);
|
|
24180
|
+
const { result: res, serverSpan } = takeServerTraceContext(await this.client.callTool({
|
|
24064
24181
|
name: tool.name,
|
|
24065
24182
|
arguments: input,
|
|
24066
24183
|
..._meta ? { _meta } : {}
|
|
24067
24184
|
}, {
|
|
24068
24185
|
timeout: this.timeout,
|
|
24069
24186
|
signal: context?.abortSignal
|
|
24070
|
-
});
|
|
24187
|
+
}));
|
|
24188
|
+
const toolCallSpan = context?.tracingContext?.currentSpan;
|
|
24189
|
+
if (toolCallSpan && serverSpan) toolCallSpan.links = [...toolCallSpan.links ?? [], serverSpan];
|
|
24071
24190
|
if (res.isError && this.onToolError === "throw") {
|
|
24072
24191
|
const errorText = extractToolErrorText(res.content);
|
|
24073
24192
|
this.log("debug", `Tool reported an error: ${tool.name}`, { error: errorText });
|
|
@@ -26141,6 +26260,16 @@ function toToolExecutionContext(ctx, loggerName) {
|
|
|
26141
26260
|
};
|
|
26142
26261
|
}
|
|
26143
26262
|
/**
|
|
26263
|
+
* The caller's trace context a request names: `traceparent` and `tracestate` in
|
|
26264
|
+
* `_meta`, else the HTTP headers, which is where OpenTelemetry-instrumented hosts
|
|
26265
|
+
* put them.
|
|
26266
|
+
*/
|
|
26267
|
+
function callerTrace(ctx) {
|
|
26268
|
+
const meta = ctx.mcpReq._meta;
|
|
26269
|
+
const headers = ctx.http?.req?.headers;
|
|
26270
|
+
return callerTraceContext(meta?.traceparent, meta?.tracestate) ?? callerTraceContext(headers?.get("traceparent"), headers?.get("tracestate"));
|
|
26271
|
+
}
|
|
26272
|
+
/**
|
|
26144
26273
|
* Builds the trusted application context for one request. Auth is re-derived from
|
|
26145
26274
|
* the transport every time; nothing is carried between continuation rounds. The W3C
|
|
26146
26275
|
* trace fields sent by the client are exposed under `traceContext` as opaque
|
|
@@ -26560,29 +26689,33 @@ var MCPServer = class extends MCPServerBase {
|
|
|
26560
26689
|
setTracedHandler(server, method, handler) {
|
|
26561
26690
|
server.setRequestHandler(method, async (request, ctx) => {
|
|
26562
26691
|
const params = request.params;
|
|
26692
|
+
const caller = callerTrace(ctx);
|
|
26563
26693
|
let requestContext;
|
|
26564
26694
|
try {
|
|
26565
26695
|
requestContext = await toRequestContext(ctx, this.mapAuthInfoToUser);
|
|
26566
26696
|
} catch (error) {
|
|
26567
26697
|
this.startRequestSpan(method, params, {
|
|
26568
26698
|
server,
|
|
26569
|
-
ctx
|
|
26699
|
+
ctx,
|
|
26700
|
+
caller
|
|
26570
26701
|
})?.error({ error });
|
|
26571
26702
|
throw error;
|
|
26572
26703
|
}
|
|
26573
26704
|
const requestSpan = this.startRequestSpan(method, params, {
|
|
26574
26705
|
server,
|
|
26575
26706
|
ctx,
|
|
26707
|
+
caller,
|
|
26576
26708
|
requestContext
|
|
26577
26709
|
});
|
|
26578
26710
|
let reportedError;
|
|
26579
|
-
|
|
26711
|
+
const result = await this.traceRequest(requestSpan, () => handler(request, ctx, {
|
|
26580
26712
|
requestSpan,
|
|
26581
26713
|
requestContext,
|
|
26582
26714
|
reportError: (error) => {
|
|
26583
26715
|
reportedError = error;
|
|
26584
26716
|
}
|
|
26585
26717
|
}), () => reportedError);
|
|
26718
|
+
return method === "tools/call" ? withServerTraceContext(result, requestSpan, caller !== void 0) : result;
|
|
26586
26719
|
});
|
|
26587
26720
|
}
|
|
26588
26721
|
/**
|
|
@@ -26595,13 +26728,14 @@ var MCPServer = class extends MCPServerBase {
|
|
|
26595
26728
|
const client = envelope?.[CLIENT_INFO_META_KEY] ?? connection?.server?.getClientVersion();
|
|
26596
26729
|
const target = params?.name ?? params?.uri;
|
|
26597
26730
|
const targetName = typeof target === "string" ? target : void 0;
|
|
26731
|
+
const caller = connection?.caller;
|
|
26598
26732
|
return getOrCreateSpan({
|
|
26599
26733
|
type: SpanType.MCP_SERVER_REQUEST,
|
|
26600
26734
|
name: targetName ? `${method} ${targetName}` : method,
|
|
26601
26735
|
entityType: EntityType.MCP_SERVER,
|
|
26602
26736
|
entityId: this.id,
|
|
26603
26737
|
entityName: this.name,
|
|
26604
|
-
input: params,
|
|
26738
|
+
input: withoutTraceContext(params),
|
|
26605
26739
|
attributes: {
|
|
26606
26740
|
mcpMethod: method,
|
|
26607
26741
|
targetName,
|
|
@@ -26609,9 +26743,12 @@ var MCPServer = class extends MCPServerBase {
|
|
|
26609
26743
|
serverVersion: this.version,
|
|
26610
26744
|
mcpProtocolVersion: typeof protocolVersion === "string" ? protocolVersion : void 0,
|
|
26611
26745
|
clientName: client?.name,
|
|
26612
|
-
clientVersion: client?.version
|
|
26746
|
+
clientVersion: client?.version,
|
|
26747
|
+
callerTraceparent: caller?.traceparent,
|
|
26748
|
+
callerTracestate: caller?.tracestate
|
|
26613
26749
|
},
|
|
26614
26750
|
tracingContext: {},
|
|
26751
|
+
links: caller && [caller.link],
|
|
26615
26752
|
requestContext: connection?.requestContext,
|
|
26616
26753
|
mastra: this.mastra
|
|
26617
26754
|
});
|