@mastra/mcp 1.6.0 → 1.6.1-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/CHANGELOG.md +18 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/docs/SKILL.md +1 -2
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-mcp-overview.md +25 -0
- package/dist/docs/references/reference-tools-mcp-server.md +1 -3
- package/dist/index.cjs +137 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +136 -7
- package/dist/index.js.map +1 -1
- package/dist/server/server.d.ts +16 -2
- package/dist/server/server.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/docs/references/docs-mcp-publishing-mcp-server.md +0 -115
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
2
|
+
import { createRequire } from 'module';
|
|
2
3
|
import { MastraBase } from '@mastra/core/base';
|
|
3
4
|
import { createTool, isValidationError } from '@mastra/core/tools';
|
|
4
5
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
@@ -415,7 +416,57 @@ function isReconnectableMCPError(error) {
|
|
|
415
416
|
|
|
416
417
|
// src/client/client.ts
|
|
417
418
|
var DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC = 3e3;
|
|
419
|
+
var require2 = createRequire(import.meta.url);
|
|
418
420
|
var SSE_FALLBACK_STATUS_CODES = [400, 404, 405];
|
|
421
|
+
var DATADOG_TRACER_TEST_SYMBOL = /* @__PURE__ */ Symbol.for("mastra.mcp.dd-trace-test-tracer");
|
|
422
|
+
function shouldDetachPersistentTransportRequest(init) {
|
|
423
|
+
return (init?.method ?? "GET").toUpperCase() === "GET";
|
|
424
|
+
}
|
|
425
|
+
function getDatadogScope() {
|
|
426
|
+
const testTracer = globalThis[DATADOG_TRACER_TEST_SYMBOL];
|
|
427
|
+
const tracer = testTracer ?? loadDatadogTracer();
|
|
428
|
+
if (typeof tracer?.scope === "function") {
|
|
429
|
+
return tracer.scope();
|
|
430
|
+
}
|
|
431
|
+
if (typeof tracer?.default?.scope === "function") {
|
|
432
|
+
return tracer.default.scope();
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
function loadDatadogTracer() {
|
|
437
|
+
if (!isDatadogTracerLikelyLoaded()) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
return require2("dd-trace");
|
|
442
|
+
} catch {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function isDatadogTracerLikelyLoaded() {
|
|
447
|
+
if (globalThis[DATADOG_TRACER_TEST_SYMBOL]) {
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
if (process.execArgv.some((arg) => arg.includes("dd-trace"))) {
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
if (process.env.NODE_OPTIONS?.includes("dd-trace")) {
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
const resolvedPath = require2.resolve("dd-trace");
|
|
458
|
+
return Boolean(require2.cache[resolvedPath]);
|
|
459
|
+
} catch {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function runOutsideDatadogTraceScope(callback) {
|
|
464
|
+
const scope = getDatadogScope();
|
|
465
|
+
if (!scope) {
|
|
466
|
+
return callback();
|
|
467
|
+
}
|
|
468
|
+
return scope.activate(null, callback);
|
|
469
|
+
}
|
|
419
470
|
function convertLogLevelToLoggerMethod(level) {
|
|
420
471
|
switch (level) {
|
|
421
472
|
case "debug":
|
|
@@ -610,7 +661,11 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
610
661
|
}
|
|
611
662
|
async connectHttp(url) {
|
|
612
663
|
const { requestInit, eventSourceInit, authProvider, connectTimeout, fetch: userFetch } = this.serverConfig;
|
|
613
|
-
const fetch2 =
|
|
664
|
+
const fetch2 = (requestUrl, init) => {
|
|
665
|
+
const requestContext = this.operationContextStore.getStore() ?? null;
|
|
666
|
+
const executeFetch = () => userFetch ? userFetch(requestUrl, init, requestContext) : globalThis.fetch(requestUrl, init);
|
|
667
|
+
return shouldDetachPersistentTransportRequest(init) ? runOutsideDatadogTraceScope(executeFetch) : executeFetch();
|
|
668
|
+
};
|
|
614
669
|
this.log("debug", `Attempting to connect to URL: ${url}`);
|
|
615
670
|
let shouldTrySSE = url.pathname.endsWith(`/sse`);
|
|
616
671
|
if (!shouldTrySSE) {
|
|
@@ -639,7 +694,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
639
694
|
if (shouldTrySSE) {
|
|
640
695
|
this.log("debug", "Falling back to deprecated HTTP+SSE transport...");
|
|
641
696
|
try {
|
|
642
|
-
const sseEventSourceInit =
|
|
697
|
+
const sseEventSourceInit = { ...eventSourceInit, fetch: fetch2 };
|
|
643
698
|
const sseTransport = new SSEClientTransport(url, {
|
|
644
699
|
requestInit,
|
|
645
700
|
eventSourceInit: sseEventSourceInit,
|
|
@@ -2764,9 +2819,11 @@ var MCPServer = class extends MCPServerBase {
|
|
|
2764
2819
|
* This allows us to create multiple server instances with identical functionality.
|
|
2765
2820
|
*/
|
|
2766
2821
|
registerHandlersOnServer(serverInstance) {
|
|
2767
|
-
serverInstance.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2822
|
+
serverInstance.setRequestHandler(ListToolsRequestSchema, async (_request, extra) => {
|
|
2823
|
+
const proxiedContext = this.createProxiedRequestContext(extra);
|
|
2824
|
+
const tools = await this.getAuthorizedConvertedToolEntries(proxiedContext);
|
|
2768
2825
|
return {
|
|
2769
|
-
tools:
|
|
2826
|
+
tools: tools.map(([, tool]) => {
|
|
2770
2827
|
const toolSpec = {
|
|
2771
2828
|
name: tool.id || "unknown",
|
|
2772
2829
|
description: tool.description,
|
|
@@ -2858,6 +2915,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2858
2915
|
throw new Error(`The "extra" key is now nested under "mcp.extra" in tool arguments`);
|
|
2859
2916
|
}
|
|
2860
2917
|
};
|
|
2918
|
+
await this.enforceToolExecutionFGA(request.params.name, proxiedContext);
|
|
2861
2919
|
const result = await tool.execute(validation?.value ?? request.params.arguments ?? {}, mcpOptions);
|
|
2862
2920
|
const duration = Date.now() - startTime;
|
|
2863
2921
|
if (isValidationError(result)) {
|
|
@@ -4049,7 +4107,24 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
4049
4107
|
* });
|
|
4050
4108
|
* ```
|
|
4051
4109
|
*/
|
|
4052
|
-
getToolListInfo() {
|
|
4110
|
+
getToolListInfo(requestContext) {
|
|
4111
|
+
const fgaProvider = this.mastra?.getServer?.()?.fga;
|
|
4112
|
+
if (fgaProvider && requestContext) {
|
|
4113
|
+
return this.getAuthorizedConvertedToolEntries(requestContext).then((tools) => ({
|
|
4114
|
+
tools: tools.map(([toolId, tool]) => ({
|
|
4115
|
+
id: toolId,
|
|
4116
|
+
name: tool.id || toolId,
|
|
4117
|
+
description: tool.description,
|
|
4118
|
+
inputSchema: this.convertSchema(tool.parameters),
|
|
4119
|
+
outputSchema: this.convertSchema(tool.outputSchema),
|
|
4120
|
+
toolType: tool.mcp?.toolType,
|
|
4121
|
+
_meta: withMastraToolStrictMeta(tool.mcp?._meta, tool.strict)
|
|
4122
|
+
}))
|
|
4123
|
+
}));
|
|
4124
|
+
}
|
|
4125
|
+
if (fgaProvider && !requestContext) {
|
|
4126
|
+
return { tools: [] };
|
|
4127
|
+
}
|
|
4053
4128
|
this.logger.debug("Getting tool list", { server: this.name });
|
|
4054
4129
|
return {
|
|
4055
4130
|
tools: Object.entries(this.convertedTools).map(([toolId, tool]) => ({
|
|
@@ -4057,7 +4132,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
4057
4132
|
name: tool.id || toolId,
|
|
4058
4133
|
description: tool.description,
|
|
4059
4134
|
inputSchema: this.convertSchema(tool.parameters),
|
|
4060
|
-
outputSchema: this.convertSchema(tool.
|
|
4135
|
+
outputSchema: this.convertSchema(tool.outputSchema),
|
|
4061
4136
|
toolType: tool.mcp?.toolType,
|
|
4062
4137
|
_meta: withMastraToolStrictMeta(tool.mcp?._meta, tool.strict)
|
|
4063
4138
|
}))
|
|
@@ -4097,6 +4172,58 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
4097
4172
|
_meta: withMastraToolStrictMeta(tool.mcp?._meta, tool.strict)
|
|
4098
4173
|
};
|
|
4099
4174
|
}
|
|
4175
|
+
createProxiedRequestContext(extra) {
|
|
4176
|
+
const proxiedContext = new RequestContext();
|
|
4177
|
+
if (extra && typeof extra === "object") {
|
|
4178
|
+
Object.entries(extra).forEach(([key, value]) => {
|
|
4179
|
+
proxiedContext.set(key, value);
|
|
4180
|
+
});
|
|
4181
|
+
}
|
|
4182
|
+
return proxiedContext;
|
|
4183
|
+
}
|
|
4184
|
+
async getAuthorizedConvertedToolEntries(requestContext) {
|
|
4185
|
+
const entries = Object.entries(this.convertedTools);
|
|
4186
|
+
const fgaProvider = this.mastra?.getServer?.()?.fga;
|
|
4187
|
+
if (!fgaProvider) {
|
|
4188
|
+
return entries;
|
|
4189
|
+
}
|
|
4190
|
+
const user = requestContext.get("user");
|
|
4191
|
+
if (!user) {
|
|
4192
|
+
return [];
|
|
4193
|
+
}
|
|
4194
|
+
const accessible = await Promise.all(
|
|
4195
|
+
entries.map(async ([toolId, tool]) => {
|
|
4196
|
+
try {
|
|
4197
|
+
await this.enforceToolExecutionFGA(toolId, requestContext);
|
|
4198
|
+
return [toolId, tool];
|
|
4199
|
+
} catch (error) {
|
|
4200
|
+
if (error instanceof Error && error.name === "FGADeniedError") {
|
|
4201
|
+
return null;
|
|
4202
|
+
}
|
|
4203
|
+
throw error;
|
|
4204
|
+
}
|
|
4205
|
+
})
|
|
4206
|
+
);
|
|
4207
|
+
return accessible.filter((entry) => entry !== null);
|
|
4208
|
+
}
|
|
4209
|
+
async enforceToolExecutionFGA(toolId, requestContext) {
|
|
4210
|
+
const fgaProvider = this.mastra?.getServer?.()?.fga;
|
|
4211
|
+
if (!fgaProvider) {
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4214
|
+
const { checkFGA, FGADeniedError, MastraFGAPermissions } = await import('@mastra/core/auth/ee');
|
|
4215
|
+
const resourceId = JSON.stringify([this.id, toolId]);
|
|
4216
|
+
const user = requestContext?.get("user");
|
|
4217
|
+
if (!user) {
|
|
4218
|
+
throw new FGADeniedError({ id: "unknown" }, { type: "tool", id: resourceId }, MastraFGAPermissions.TOOLS_EXECUTE);
|
|
4219
|
+
}
|
|
4220
|
+
await checkFGA({
|
|
4221
|
+
fgaProvider,
|
|
4222
|
+
user,
|
|
4223
|
+
resource: { type: "tool", id: resourceId },
|
|
4224
|
+
permission: MastraFGAPermissions.TOOLS_EXECUTE
|
|
4225
|
+
});
|
|
4226
|
+
}
|
|
4100
4227
|
/**
|
|
4101
4228
|
* Executes a specific tool provided by this MCP server.
|
|
4102
4229
|
*
|
|
@@ -4179,8 +4306,10 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
|
|
|
4179
4306
|
try {
|
|
4180
4307
|
const finalExecutionContext = {
|
|
4181
4308
|
messages: executionContext?.messages || [],
|
|
4182
|
-
toolCallId: executionContext?.toolCallId || randomUUID()
|
|
4309
|
+
toolCallId: executionContext?.toolCallId || randomUUID(),
|
|
4310
|
+
requestContext: executionContext?.requestContext
|
|
4183
4311
|
};
|
|
4312
|
+
await this.enforceToolExecutionFGA(toolId, finalExecutionContext.requestContext);
|
|
4184
4313
|
const result = await tool.execute(validatedArgs, finalExecutionContext);
|
|
4185
4314
|
this.logger.info("Tool executed successfully", { tool: toolId });
|
|
4186
4315
|
return result;
|