@mastra/mcp 0.14.2 → 1.0.0-beta.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 +74 -13
- package/README.md +8 -8
- package/dist/__fixtures__/tools.d.ts +1 -7
- package/dist/__fixtures__/tools.d.ts.map +1 -1
- package/dist/client/client.d.ts +4 -9
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/configuration.d.ts +10 -64
- package/dist/client/configuration.d.ts.map +1 -1
- package/dist/client/index.d.ts +0 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/index.cjs +175 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +175 -94
- package/dist/index.js.map +1 -1
- package/dist/server/server.d.ts +44 -6
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/types.d.ts +0 -54
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +8 -12
package/dist/index.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import $RefParser from '@apidevtools/json-schema-ref-parser';
|
|
2
1
|
import { MastraBase } from '@mastra/core/base';
|
|
3
2
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
+
import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
4
|
+
import equal from 'fast-deep-equal';
|
|
5
|
+
import { v5 } from 'uuid';
|
|
6
|
+
import $RefParser from '@apidevtools/json-schema-ref-parser';
|
|
4
7
|
import { createTool } from '@mastra/core/tools';
|
|
5
8
|
import { makeCoreTool, isZodType } from '@mastra/core/utils';
|
|
6
9
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
7
10
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
8
11
|
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
9
12
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
10
|
-
import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
11
13
|
import { ListToolsRequestSchema, CallToolRequestSchema, SetLevelRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, ListPromptsRequestSchema, PromptSchema, GetPromptRequestSchema, ListResourcesResultSchema, ReadResourceResultSchema, ListResourceTemplatesResultSchema, ListPromptsResultSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ResourceUpdatedNotificationSchema, ResourceListChangedNotificationSchema, ElicitRequestSchema, CallToolResultSchema, JSONRPCMessageSchema, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
|
12
14
|
import { asyncExitHook, gracefulExit } from 'exit-hook';
|
|
13
15
|
import { z } from 'zod';
|
|
14
16
|
import { convertJsonSchemaToZod } from 'zod-from-json-schema';
|
|
15
17
|
import { convertJsonSchemaToZod as convertJsonSchemaToZod$1 } from 'zod-from-json-schema-v3';
|
|
16
|
-
import equal from 'fast-deep-equal';
|
|
17
|
-
import { v5 } from 'uuid';
|
|
18
18
|
import { randomUUID } from 'crypto';
|
|
19
19
|
import { MCPServerBase } from '@mastra/core/mcp';
|
|
20
|
-
import {
|
|
20
|
+
import { RequestContext } from '@mastra/core/request-context';
|
|
21
21
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
22
22
|
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
23
23
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
24
24
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
25
25
|
|
|
26
|
-
// src/client/
|
|
26
|
+
// src/client/configuration.ts
|
|
27
27
|
|
|
28
28
|
// src/client/elicitationActions.ts
|
|
29
29
|
var ElicitationClientActions = class {
|
|
@@ -447,7 +447,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
447
447
|
timestamp: /* @__PURE__ */ new Date(),
|
|
448
448
|
serverName: this.name,
|
|
449
449
|
details,
|
|
450
|
-
|
|
450
|
+
requestContext: this.currentOperationContext
|
|
451
451
|
});
|
|
452
452
|
}
|
|
453
453
|
}
|
|
@@ -777,15 +777,15 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
777
777
|
description: tool.description || "",
|
|
778
778
|
inputSchema: await this.convertInputSchema(tool.inputSchema),
|
|
779
779
|
outputSchema: await this.convertOutputSchema(tool.outputSchema),
|
|
780
|
-
execute: async (
|
|
780
|
+
execute: async (input, context) => {
|
|
781
781
|
const previousContext = this.currentOperationContext;
|
|
782
|
-
this.currentOperationContext =
|
|
782
|
+
this.currentOperationContext = context?.requestContext || null;
|
|
783
783
|
try {
|
|
784
|
-
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs:
|
|
784
|
+
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input });
|
|
785
785
|
const res = await this.client.callTool(
|
|
786
786
|
{
|
|
787
787
|
name: tool.name,
|
|
788
|
-
arguments:
|
|
788
|
+
arguments: input
|
|
789
789
|
},
|
|
790
790
|
CallToolResultSchema,
|
|
791
791
|
{
|
|
@@ -797,7 +797,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
797
797
|
} catch (e) {
|
|
798
798
|
this.log("error", `Error calling tool: ${tool.name}`, {
|
|
799
799
|
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
|
|
800
|
-
toolArgs:
|
|
800
|
+
toolArgs: input
|
|
801
801
|
});
|
|
802
802
|
throw e;
|
|
803
803
|
} finally {
|
|
@@ -818,19 +818,8 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
818
818
|
return toolsRes;
|
|
819
819
|
}
|
|
820
820
|
};
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
super(args);
|
|
824
|
-
throw new MastraError(
|
|
825
|
-
{
|
|
826
|
-
id: "MASTRA_MCP_CLIENT_DEPRECATED",
|
|
827
|
-
domain: ErrorDomain.MCP,
|
|
828
|
-
category: ErrorCategory.USER,
|
|
829
|
-
text: "[DEPRECATION] MastraMCPClient is deprecated and will be removed in a future release. Please use MCPClient instead."
|
|
830
|
-
}
|
|
831
|
-
);
|
|
832
|
-
}
|
|
833
|
-
};
|
|
821
|
+
|
|
822
|
+
// src/client/configuration.ts
|
|
834
823
|
var mcpClientInstances = /* @__PURE__ */ new Map();
|
|
835
824
|
var MCPClient = class extends MastraBase {
|
|
836
825
|
serverConfigs = {};
|
|
@@ -1431,14 +1420,15 @@ To fix this you have three different options:
|
|
|
1431
1420
|
* @example
|
|
1432
1421
|
* ```typescript
|
|
1433
1422
|
* const agent = new Agent({
|
|
1423
|
+
* id: 'multi-tool-agent',
|
|
1434
1424
|
* name: 'Multi-tool Agent',
|
|
1435
1425
|
* instructions: 'You have access to weather and stock tools.',
|
|
1436
1426
|
* model: 'openai/gpt-4',
|
|
1437
|
-
* tools: await mcp.
|
|
1427
|
+
* tools: await mcp.listTools(), // weather_getWeather, stockPrice_getPrice
|
|
1438
1428
|
* });
|
|
1439
1429
|
* ```
|
|
1440
1430
|
*/
|
|
1441
|
-
async
|
|
1431
|
+
async listTools() {
|
|
1442
1432
|
this.addToInstanceCache();
|
|
1443
1433
|
const connectedTools = {};
|
|
1444
1434
|
try {
|
|
@@ -1462,7 +1452,7 @@ To fix this you have three different options:
|
|
|
1462
1452
|
/**
|
|
1463
1453
|
* Returns toolsets organized by server name for dynamic tool injection.
|
|
1464
1454
|
*
|
|
1465
|
-
* Unlike
|
|
1455
|
+
* Unlike listTools(), this returns tools grouped by server without namespacing.
|
|
1466
1456
|
* This is intended to be passed dynamically to the generate() or stream() method.
|
|
1467
1457
|
*
|
|
1468
1458
|
* @returns Object mapping server names to their tool collections
|
|
@@ -1471,17 +1461,18 @@ To fix this you have three different options:
|
|
|
1471
1461
|
* @example
|
|
1472
1462
|
* ```typescript
|
|
1473
1463
|
* const agent = new Agent({
|
|
1464
|
+
* id: 'dynamic-agent',
|
|
1474
1465
|
* name: 'Dynamic Agent',
|
|
1475
1466
|
* instructions: 'You can use tools dynamically.',
|
|
1476
1467
|
* model: 'openai/gpt-4',
|
|
1477
1468
|
* });
|
|
1478
1469
|
*
|
|
1479
1470
|
* const response = await agent.stream(prompt, {
|
|
1480
|
-
* toolsets: await mcp.
|
|
1471
|
+
* toolsets: await mcp.listToolsets(), // { weather: {...}, stockPrice: {...} }
|
|
1481
1472
|
* });
|
|
1482
1473
|
* ```
|
|
1483
1474
|
*/
|
|
1484
|
-
async
|
|
1475
|
+
async listToolsets() {
|
|
1485
1476
|
this.addToInstanceCache();
|
|
1486
1477
|
const connectedToolsets = {};
|
|
1487
1478
|
try {
|
|
@@ -1502,12 +1493,6 @@ To fix this you have three different options:
|
|
|
1502
1493
|
}
|
|
1503
1494
|
return connectedToolsets;
|
|
1504
1495
|
}
|
|
1505
|
-
/**
|
|
1506
|
-
* @deprecated all resource actions have been moved to the this.resources object. Use this.resources.list() instead.
|
|
1507
|
-
*/
|
|
1508
|
-
async getResources() {
|
|
1509
|
-
return this.resources.list();
|
|
1510
|
-
}
|
|
1511
1496
|
/**
|
|
1512
1497
|
* Gets current session IDs for all connected MCP clients using Streamable HTTP transport.
|
|
1513
1498
|
*
|
|
@@ -1594,24 +1579,8 @@ To fix this you have three different options:
|
|
|
1594
1579
|
);
|
|
1595
1580
|
}
|
|
1596
1581
|
};
|
|
1597
|
-
var MCPConfiguration = class extends MCPClient {
|
|
1598
|
-
/**
|
|
1599
|
-
* @deprecated Use MCPClient constructor instead
|
|
1600
|
-
*/
|
|
1601
|
-
constructor(args) {
|
|
1602
|
-
super(args);
|
|
1603
|
-
throw new MastraError(
|
|
1604
|
-
{
|
|
1605
|
-
id: "MCP_CLIENT_CONFIGURATION_DEPRECATED",
|
|
1606
|
-
domain: ErrorDomain.MCP,
|
|
1607
|
-
category: ErrorCategory.USER,
|
|
1608
|
-
text: "[DEPRECATION] MCPConfiguration has been renamed to MCPClient and MCPConfiguration is deprecated. The API is identical but the MCPConfiguration export will be removed in the future. Update your imports now to prevent future errors."
|
|
1609
|
-
}
|
|
1610
|
-
);
|
|
1611
|
-
}
|
|
1612
|
-
};
|
|
1613
1582
|
|
|
1614
|
-
// ../../node_modules/.pnpm/hono@4.10.
|
|
1583
|
+
// ../../node_modules/.pnpm/hono@4.10.3/node_modules/hono/dist/utils/stream.js
|
|
1615
1584
|
var StreamingApi = class {
|
|
1616
1585
|
writer;
|
|
1617
1586
|
encoder;
|
|
@@ -1678,7 +1647,7 @@ var StreamingApi = class {
|
|
|
1678
1647
|
}
|
|
1679
1648
|
};
|
|
1680
1649
|
|
|
1681
|
-
// ../../node_modules/.pnpm/hono@4.10.
|
|
1650
|
+
// ../../node_modules/.pnpm/hono@4.10.3/node_modules/hono/dist/helper/streaming/utils.js
|
|
1682
1651
|
var isOldBunVersion = () => {
|
|
1683
1652
|
const version = typeof Bun !== "undefined" ? Bun.version : void 0;
|
|
1684
1653
|
if (version === void 0) {
|
|
@@ -1689,7 +1658,7 @@ var isOldBunVersion = () => {
|
|
|
1689
1658
|
return result;
|
|
1690
1659
|
};
|
|
1691
1660
|
|
|
1692
|
-
// ../../node_modules/.pnpm/hono@4.10.
|
|
1661
|
+
// ../../node_modules/.pnpm/hono@4.10.3/node_modules/hono/dist/utils/html.js
|
|
1693
1662
|
var HtmlEscapedCallbackPhase = {
|
|
1694
1663
|
Stringify: 1};
|
|
1695
1664
|
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
@@ -1720,7 +1689,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
|
|
|
1720
1689
|
}
|
|
1721
1690
|
};
|
|
1722
1691
|
|
|
1723
|
-
// ../../node_modules/.pnpm/hono@4.10.
|
|
1692
|
+
// ../../node_modules/.pnpm/hono@4.10.3/node_modules/hono/dist/helper/streaming/sse.js
|
|
1724
1693
|
var SSEStreamingApi = class extends StreamingApi {
|
|
1725
1694
|
constructor(writable, readable) {
|
|
1726
1695
|
super(writable, readable);
|
|
@@ -2131,7 +2100,8 @@ var MCPServer = class extends MCPServerBase {
|
|
|
2131
2100
|
* import { z } from 'zod';
|
|
2132
2101
|
*
|
|
2133
2102
|
* const myAgent = new Agent({
|
|
2134
|
-
*
|
|
2103
|
+
* id: 'helper',
|
|
2104
|
+
* name: 'Helper Agent',
|
|
2135
2105
|
* description: 'A helpful assistant',
|
|
2136
2106
|
* instructions: 'You are helpful.',
|
|
2137
2107
|
* model: 'openai/gpt-4o-mini',
|
|
@@ -2145,7 +2115,7 @@ var MCPServer = class extends MCPServerBase {
|
|
|
2145
2115
|
* id: 'getWeather',
|
|
2146
2116
|
* description: 'Gets weather',
|
|
2147
2117
|
* inputSchema: z.object({ location: z.string() }),
|
|
2148
|
-
* execute: async (
|
|
2118
|
+
* execute: async (inputData) => `Sunny in ${inputData.location}`,
|
|
2149
2119
|
* })
|
|
2150
2120
|
* },
|
|
2151
2121
|
* agents: { myAgent },
|
|
@@ -2242,7 +2212,7 @@ var MCPServer = class extends MCPServerBase {
|
|
|
2242
2212
|
return {
|
|
2243
2213
|
tools: Object.values(this.convertedTools).map((tool) => {
|
|
2244
2214
|
const toolSpec = {
|
|
2245
|
-
name: tool.
|
|
2215
|
+
name: tool.id || "unknown",
|
|
2246
2216
|
description: tool.description,
|
|
2247
2217
|
inputSchema: tool.parameters.jsonSchema
|
|
2248
2218
|
};
|
|
@@ -2301,12 +2271,23 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2301
2271
|
return this.handleElicitationRequest(request2, serverInstance);
|
|
2302
2272
|
}
|
|
2303
2273
|
};
|
|
2304
|
-
const
|
|
2274
|
+
const mcpOptions = {
|
|
2305
2275
|
messages: [],
|
|
2306
2276
|
toolCallId: "",
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2277
|
+
// Pass MCP-specific context through the mcp property
|
|
2278
|
+
mcp: {
|
|
2279
|
+
elicitation: sessionElicitation,
|
|
2280
|
+
extra
|
|
2281
|
+
},
|
|
2282
|
+
// @ts-ignore this is to let people know that the elicitation and extra keys are now nested under mcp.elicitation and mcp.extra in tool arguments
|
|
2283
|
+
get elicitation() {
|
|
2284
|
+
throw new Error(`The "elicitation" key is now nested under "mcp.elicitation" in tool arguments`);
|
|
2285
|
+
},
|
|
2286
|
+
get extra() {
|
|
2287
|
+
throw new Error(`The "extra" key is now nested under "mcp.extra" in tool arguments`);
|
|
2288
|
+
}
|
|
2289
|
+
};
|
|
2290
|
+
const result = await tool.execute(validation?.value ?? request.params.arguments ?? {}, mcpOptions);
|
|
2310
2291
|
this.logger.debug(`CallTool: Tool '${request.params.name}' executed successfully with result:`, result);
|
|
2311
2292
|
const duration = Date.now() - startTime;
|
|
2312
2293
|
this.logger.info(`Tool '${request.params.name}' executed successfully in ${duration}ms.`);
|
|
@@ -2582,12 +2563,19 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2582
2563
|
inputSchema: z.object({
|
|
2583
2564
|
message: z.string().describe("The question or input for the agent.")
|
|
2584
2565
|
}),
|
|
2585
|
-
execute: async (
|
|
2566
|
+
execute: async (inputData, context) => {
|
|
2586
2567
|
this.logger.debug(
|
|
2587
|
-
`Executing agent tool '${agentToolName}' for agent '${agent.name}' with message: "${
|
|
2568
|
+
`Executing agent tool '${agentToolName}' for agent '${agent.name}' with message: "${inputData.message}"`
|
|
2588
2569
|
);
|
|
2589
2570
|
try {
|
|
2590
|
-
const
|
|
2571
|
+
const proxiedContext = context?.requestContext || new RequestContext();
|
|
2572
|
+
if (context?.mcp?.extra) {
|
|
2573
|
+
proxiedContext.set("mcp.extra", context.mcp.extra);
|
|
2574
|
+
}
|
|
2575
|
+
const response = await agent.generate(inputData.message, {
|
|
2576
|
+
...context ?? {},
|
|
2577
|
+
requestContext: proxiedContext
|
|
2578
|
+
});
|
|
2591
2579
|
return response;
|
|
2592
2580
|
} catch (error) {
|
|
2593
2581
|
this.logger.error(`Error executing agent tool '${agentToolName}' for agent '${agent.name}':`, error);
|
|
@@ -2599,17 +2587,17 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2599
2587
|
name: agentToolName,
|
|
2600
2588
|
logger: this.logger,
|
|
2601
2589
|
mastra: this.mastra,
|
|
2602
|
-
|
|
2590
|
+
requestContext: new RequestContext(),
|
|
2603
2591
|
tracingContext: {},
|
|
2604
2592
|
description: agentToolDefinition.description
|
|
2605
2593
|
};
|
|
2606
2594
|
const coreTool = makeCoreTool(agentToolDefinition, options);
|
|
2607
2595
|
agentTools[agentToolName] = {
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2596
|
+
...coreTool,
|
|
2597
|
+
id: agentToolName,
|
|
2598
|
+
mcp: {
|
|
2599
|
+
toolType: "agent"
|
|
2600
|
+
}
|
|
2613
2601
|
};
|
|
2614
2602
|
this.logger.info(`Registered agent '${agent.name}' (key: '${agentKey}') as tool: '${agentToolName}'`);
|
|
2615
2603
|
}
|
|
@@ -2645,14 +2633,18 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2645
2633
|
id: workflowToolName,
|
|
2646
2634
|
description: `Run workflow '${workflowKey}'. Workflow description: ${workflowDescription}`,
|
|
2647
2635
|
inputSchema: workflow.inputSchema,
|
|
2648
|
-
execute: async (
|
|
2636
|
+
execute: async (inputData, context) => {
|
|
2649
2637
|
this.logger.debug(
|
|
2650
2638
|
`Executing workflow tool '${workflowToolName}' for workflow '${workflow.id}' with input:`,
|
|
2651
|
-
|
|
2639
|
+
inputData
|
|
2652
2640
|
);
|
|
2653
2641
|
try {
|
|
2654
|
-
const run2 = await workflow.
|
|
2655
|
-
const response = await run2.start({
|
|
2642
|
+
const run2 = await workflow.createRun({ runId: context?.requestContext?.get("runId") });
|
|
2643
|
+
const response = await run2.start({
|
|
2644
|
+
inputData,
|
|
2645
|
+
requestContext: context?.requestContext,
|
|
2646
|
+
tracingContext: context?.tracingContext
|
|
2647
|
+
});
|
|
2656
2648
|
return response;
|
|
2657
2649
|
} catch (error) {
|
|
2658
2650
|
this.logger.error(
|
|
@@ -2667,18 +2659,17 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2667
2659
|
name: workflowToolName,
|
|
2668
2660
|
logger: this.logger,
|
|
2669
2661
|
mastra: this.mastra,
|
|
2670
|
-
|
|
2662
|
+
requestContext: new RequestContext(),
|
|
2671
2663
|
tracingContext: {},
|
|
2672
2664
|
description: workflowToolDefinition.description
|
|
2673
2665
|
};
|
|
2674
2666
|
const coreTool = makeCoreTool(workflowToolDefinition, options);
|
|
2675
2667
|
workflowTools[workflowToolName] = {
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
toolType: "workflow"
|
|
2668
|
+
...coreTool,
|
|
2669
|
+
id: workflowToolName,
|
|
2670
|
+
mcp: {
|
|
2671
|
+
toolType: "workflow"
|
|
2672
|
+
}
|
|
2682
2673
|
};
|
|
2683
2674
|
this.logger.info(`Registered workflow '${workflow.id}' (key: '${workflowKey}') as tool: '${workflowToolName}'`);
|
|
2684
2675
|
}
|
|
@@ -2706,7 +2697,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2706
2697
|
}
|
|
2707
2698
|
const options = {
|
|
2708
2699
|
name: toolName,
|
|
2709
|
-
|
|
2700
|
+
requestContext: new RequestContext(),
|
|
2710
2701
|
tracingContext: {},
|
|
2711
2702
|
mastra: this.mastra,
|
|
2712
2703
|
logger: this.logger,
|
|
@@ -2714,11 +2705,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2714
2705
|
};
|
|
2715
2706
|
const coreTool = makeCoreTool(toolInstance, options);
|
|
2716
2707
|
definedConvertedTools[toolName] = {
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
parameters: coreTool.parameters,
|
|
2720
|
-
outputSchema: coreTool.outputSchema,
|
|
2721
|
-
execute: coreTool.execute
|
|
2708
|
+
...coreTool,
|
|
2709
|
+
id: toolName
|
|
2722
2710
|
};
|
|
2723
2711
|
this.logger.info(`Registered explicit tool: '${toolName}'`);
|
|
2724
2712
|
}
|
|
@@ -2962,6 +2950,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2962
2950
|
* @param options.options.onsessioninitialized - Callback when a new session is initialized
|
|
2963
2951
|
* @param options.options.enableJsonResponse - If true, return JSON instead of SSE streaming
|
|
2964
2952
|
* @param options.options.eventStore - Event store for message resumability
|
|
2953
|
+
* @param options.options.serverless - If true, run in stateless mode without session management (ideal for serverless environments)
|
|
2965
2954
|
*
|
|
2966
2955
|
* @throws {MastraError} If HTTP connection setup fails
|
|
2967
2956
|
*
|
|
@@ -2987,6 +2976,25 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2987
2976
|
*
|
|
2988
2977
|
* httpServer.listen(1234);
|
|
2989
2978
|
* ```
|
|
2979
|
+
*
|
|
2980
|
+
* @example Serverless mode (Cloudflare Workers, Vercel Edge, etc.)
|
|
2981
|
+
* ```typescript
|
|
2982
|
+
* export default {
|
|
2983
|
+
* async fetch(request: Request) {
|
|
2984
|
+
* const url = new URL(request.url);
|
|
2985
|
+
* if (url.pathname === '/mcp') {
|
|
2986
|
+
* await server.startHTTP({
|
|
2987
|
+
* url,
|
|
2988
|
+
* httpPath: '/mcp',
|
|
2989
|
+
* req: request,
|
|
2990
|
+
* res: response,
|
|
2991
|
+
* options: { serverless: true },
|
|
2992
|
+
* });
|
|
2993
|
+
* }
|
|
2994
|
+
* return new Response('Not found', { status: 404 });
|
|
2995
|
+
* },
|
|
2996
|
+
* };
|
|
2997
|
+
* ```
|
|
2990
2998
|
*/
|
|
2991
2999
|
async startHTTP({
|
|
2992
3000
|
url,
|
|
@@ -3002,6 +3010,11 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3002
3010
|
res.end();
|
|
3003
3011
|
return;
|
|
3004
3012
|
}
|
|
3013
|
+
if (options?.serverless) {
|
|
3014
|
+
this.logger.debug("startHTTP: Running in serverless (stateless) mode");
|
|
3015
|
+
await this.handleServerlessRequest(req, res);
|
|
3016
|
+
return;
|
|
3017
|
+
}
|
|
3005
3018
|
const sessionId = req.headers["mcp-session-id"];
|
|
3006
3019
|
let transport;
|
|
3007
3020
|
this.logger.debug(
|
|
@@ -3137,6 +3150,74 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3137
3150
|
}
|
|
3138
3151
|
}
|
|
3139
3152
|
}
|
|
3153
|
+
/**
|
|
3154
|
+
* Handles a stateless, serverless HTTP request without session management.
|
|
3155
|
+
*
|
|
3156
|
+
* This method bypasses all session/transport state and handles each request independently.
|
|
3157
|
+
* For serverless environments (Cloudflare Workers, Vercel Edge, etc.) where
|
|
3158
|
+
* persistent connections and session state cannot be maintained across requests.
|
|
3159
|
+
*
|
|
3160
|
+
* Each request gets a fresh transport and server instance that are discarded after the response.
|
|
3161
|
+
*
|
|
3162
|
+
* @param req - Incoming HTTP request
|
|
3163
|
+
* @param res - HTTP response object
|
|
3164
|
+
* @private
|
|
3165
|
+
*/
|
|
3166
|
+
async handleServerlessRequest(req, res) {
|
|
3167
|
+
try {
|
|
3168
|
+
this.logger.debug(`handleServerlessRequest: Received ${req.method} request`);
|
|
3169
|
+
const body = req.method === "POST" ? await new Promise((resolve, reject) => {
|
|
3170
|
+
let data = "";
|
|
3171
|
+
req.on("data", (chunk) => data += chunk);
|
|
3172
|
+
req.on("end", () => {
|
|
3173
|
+
try {
|
|
3174
|
+
resolve(JSON.parse(data));
|
|
3175
|
+
} catch (e) {
|
|
3176
|
+
reject(new Error(`Invalid JSON in request body: ${e instanceof Error ? e.message : String(e)}`));
|
|
3177
|
+
}
|
|
3178
|
+
});
|
|
3179
|
+
req.on("error", reject);
|
|
3180
|
+
}) : void 0;
|
|
3181
|
+
this.logger.debug(`handleServerlessRequest: Processing ${req.method} request`, {
|
|
3182
|
+
method: body?.method,
|
|
3183
|
+
id: body?.id
|
|
3184
|
+
});
|
|
3185
|
+
const transientServer = this.createServerInstance();
|
|
3186
|
+
const tempTransport = new StreamableHTTPServerTransport({
|
|
3187
|
+
sessionIdGenerator: void 0,
|
|
3188
|
+
enableJsonResponse: true
|
|
3189
|
+
});
|
|
3190
|
+
await transientServer.connect(tempTransport);
|
|
3191
|
+
await tempTransport.handleRequest(req, res, body);
|
|
3192
|
+
this.logger.debug(`handleServerlessRequest: Completed ${body?.method} request`, { id: body?.id });
|
|
3193
|
+
} catch (error) {
|
|
3194
|
+
const mastraError = new MastraError(
|
|
3195
|
+
{
|
|
3196
|
+
id: "MCP_SERVER_SERVERLESS_REQUEST_FAILED",
|
|
3197
|
+
domain: ErrorDomain.MCP,
|
|
3198
|
+
category: ErrorCategory.USER,
|
|
3199
|
+
text: "Failed to handle serverless MCP request"
|
|
3200
|
+
},
|
|
3201
|
+
error
|
|
3202
|
+
);
|
|
3203
|
+
this.logger.trackException(mastraError);
|
|
3204
|
+
this.logger.error("handleServerlessRequest: Error handling request:", { error: mastraError });
|
|
3205
|
+
if (!res.headersSent) {
|
|
3206
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
3207
|
+
res.end(
|
|
3208
|
+
JSON.stringify({
|
|
3209
|
+
jsonrpc: "2.0",
|
|
3210
|
+
error: {
|
|
3211
|
+
code: -32603,
|
|
3212
|
+
message: "Internal server error",
|
|
3213
|
+
data: error instanceof Error ? error.message : String(error)
|
|
3214
|
+
},
|
|
3215
|
+
id: null
|
|
3216
|
+
})
|
|
3217
|
+
);
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3140
3221
|
/**
|
|
3141
3222
|
* Establishes the SSE connection for the MCP server.
|
|
3142
3223
|
*
|
|
@@ -3385,11 +3466,11 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3385
3466
|
return {
|
|
3386
3467
|
tools: Object.entries(this.convertedTools).map(([toolId, tool]) => ({
|
|
3387
3468
|
id: toolId,
|
|
3388
|
-
name: tool.
|
|
3469
|
+
name: tool.id || toolId,
|
|
3389
3470
|
description: tool.description,
|
|
3390
3471
|
inputSchema: tool.parameters?.jsonSchema || tool.parameters,
|
|
3391
3472
|
outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
|
|
3392
|
-
toolType: tool.toolType
|
|
3473
|
+
toolType: tool.mcp?.toolType
|
|
3393
3474
|
}))
|
|
3394
3475
|
};
|
|
3395
3476
|
}
|
|
@@ -3419,11 +3500,11 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3419
3500
|
}
|
|
3420
3501
|
this.logger.debug(`Getting info for tool '${toolId}' on MCPServer '${this.name}'`);
|
|
3421
3502
|
return {
|
|
3422
|
-
name: tool.
|
|
3503
|
+
name: tool.id || toolId,
|
|
3423
3504
|
description: tool.description,
|
|
3424
3505
|
inputSchema: tool.parameters?.jsonSchema || tool.parameters,
|
|
3425
3506
|
outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
|
|
3426
|
-
toolType: tool.toolType
|
|
3507
|
+
toolType: tool.mcp?.toolType
|
|
3427
3508
|
};
|
|
3428
3509
|
}
|
|
3429
3510
|
/**
|
|
@@ -3527,6 +3608,6 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
|
|
|
3527
3608
|
}
|
|
3528
3609
|
};
|
|
3529
3610
|
|
|
3530
|
-
export { MCPClient,
|
|
3611
|
+
export { MCPClient, MCPServer };
|
|
3531
3612
|
//# sourceMappingURL=index.js.map
|
|
3532
3613
|
//# sourceMappingURL=index.js.map
|