@mastra/mcp 0.10.5-alpha.1 → 0.10.5

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/index.js CHANGED
@@ -7,7 +7,7 @@ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
7
7
  import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
8
8
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
9
9
  import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
10
- import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, ListPromptsRequestSchema, PromptSchema, GetPromptRequestSchema, ListResourcesResultSchema, ReadResourceResultSchema, ListResourceTemplatesResultSchema, ListPromptsResultSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ResourceUpdatedNotificationSchema, ResourceListChangedNotificationSchema, CallToolResultSchema, JSONRPCMessageSchema, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
10
+ import { ListToolsRequestSchema, CallToolRequestSchema, 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';
11
11
  import { asyncExitHook, gracefulExit } from 'exit-hook';
12
12
  import { z } from 'zod';
13
13
  import { convertJsonSchemaToZod } from 'zod-from-json-schema';
@@ -23,6 +23,23 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
23
23
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
24
24
 
25
25
  // src/client/client.ts
26
+
27
+ // src/client/elicitationActions.ts
28
+ var ElicitationClientActions = class {
29
+ client;
30
+ logger;
31
+ constructor({ client, logger }) {
32
+ this.client = client;
33
+ this.logger = logger;
34
+ }
35
+ /**
36
+ * Set a handler for elicitation requests.
37
+ * @param handler The callback function to handle the elicitation request.
38
+ */
39
+ onRequest(handler) {
40
+ this.client.setElicitationRequestHandler(handler);
41
+ }
42
+ };
26
43
  var PromptClientActions = class {
27
44
  client;
28
45
  logger;
@@ -205,6 +222,7 @@ var InternalMastraMCPClient = class extends MastraBase {
205
222
  currentOperationContext = null;
206
223
  resources;
207
224
  prompts;
225
+ elicitation;
208
226
  constructor({
209
227
  name,
210
228
  version = "1.0.0",
@@ -218,18 +236,20 @@ var InternalMastraMCPClient = class extends MastraBase {
218
236
  this.logHandler = server.logger;
219
237
  this.enableServerLogs = server.enableServerLogs ?? true;
220
238
  this.serverConfig = server;
239
+ const clientCapabilities = { ...capabilities, elicitation: {} };
221
240
  this.client = new Client(
222
241
  {
223
242
  name,
224
243
  version
225
244
  },
226
245
  {
227
- capabilities
246
+ capabilities: clientCapabilities
228
247
  }
229
248
  );
230
249
  this.setupLogging();
231
250
  this.resources = new ResourceClientActions({ client: this, logger: this.logger });
232
251
  this.prompts = new PromptClientActions({ client: this, logger: this.logger });
252
+ this.elicitation = new ElicitationClientActions({ client: this, logger: this.logger });
233
253
  }
234
254
  /**
235
255
  * Log a message at the specified level
@@ -471,6 +491,13 @@ var InternalMastraMCPClient = class extends MastraBase {
471
491
  handler();
472
492
  });
473
493
  }
494
+ setElicitationRequestHandler(handler) {
495
+ this.log("debug", "Setting elicitation request handler");
496
+ this.client.setRequestHandler(ElicitRequestSchema, async (request) => {
497
+ this.log("debug", `Received elicitation request: ${request.params.message}`);
498
+ return handler(request.params);
499
+ });
500
+ }
474
501
  convertInputSchema(inputSchema) {
475
502
  if (isZodType(inputSchema)) {
476
503
  return inputSchema;
@@ -635,6 +662,26 @@ To fix this you have three different options:
635
662
  this.addToInstanceCache();
636
663
  return this;
637
664
  }
665
+ get elicitation() {
666
+ this.addToInstanceCache();
667
+ return {
668
+ onRequest: async (serverName, handler) => {
669
+ try {
670
+ const internalClient = await this.getConnectedClientForServer(serverName);
671
+ return internalClient.elicitation.onRequest(handler);
672
+ } catch (err) {
673
+ throw new MastraError({
674
+ id: "MCP_CLIENT_ON_REQUEST_ELICITATION_FAILED",
675
+ domain: ErrorDomain.MCP,
676
+ category: ErrorCategory.THIRD_PARTY,
677
+ details: {
678
+ serverName
679
+ }
680
+ }, err);
681
+ }
682
+ }
683
+ };
684
+ }
638
685
  get resources() {
639
686
  this.addToInstanceCache();
640
687
  return {
@@ -1330,15 +1377,8 @@ var MCPServer = class extends MCPServerBase {
1330
1377
  sseTransport;
1331
1378
  sseHonoTransports;
1332
1379
  streamableHTTPTransports = /* @__PURE__ */ new Map();
1333
- listToolsHandlerIsRegistered = false;
1334
- callToolHandlerIsRegistered = false;
1335
- listResourcesHandlerIsRegistered = false;
1336
- readResourceHandlerIsRegistered = false;
1337
- listResourceTemplatesHandlerIsRegistered = false;
1338
- subscribeResourceHandlerIsRegistered = false;
1339
- unsubscribeResourceHandlerIsRegistered = false;
1340
- listPromptsHandlerIsRegistered = false;
1341
- getPromptHandlerIsRegistered = false;
1380
+ // Track server instances for each HTTP session
1381
+ httpServerInstances = /* @__PURE__ */ new Map();
1342
1382
  definedResources;
1343
1383
  definedResourceTemplates;
1344
1384
  resourceOptions;
@@ -1347,6 +1387,7 @@ var MCPServer = class extends MCPServerBase {
1347
1387
  subscriptions = /* @__PURE__ */ new Set();
1348
1388
  resources;
1349
1389
  prompts;
1390
+ elicitation;
1350
1391
  /**
1351
1392
  * Get the current stdio transport.
1352
1393
  */
@@ -1381,7 +1422,8 @@ var MCPServer = class extends MCPServerBase {
1381
1422
  this.promptOptions = opts.prompts;
1382
1423
  const capabilities = {
1383
1424
  tools: {},
1384
- logging: { enabled: true }
1425
+ logging: { enabled: true },
1426
+ elicitation: {}
1385
1427
  };
1386
1428
  if (opts.resources) {
1387
1429
  capabilities.resources = { subscribe: true, listChanged: true };
@@ -1394,23 +1436,7 @@ var MCPServer = class extends MCPServerBase {
1394
1436
  `Initialized MCPServer '${this.name}' v${this.version} (ID: ${this.id}) with tools: ${Object.keys(this.convertedTools).join(", ")} and resources. Capabilities: ${JSON.stringify(capabilities)}`
1395
1437
  );
1396
1438
  this.sseHonoTransports = /* @__PURE__ */ new Map();
1397
- this.registerListToolsHandler();
1398
- this.registerCallToolHandler();
1399
- if (opts.resources) {
1400
- this.registerListResourcesHandler();
1401
- this.registerReadResourceHandler({ getResourcesCallback: opts.resources.getResourceContent });
1402
- this.registerSubscribeResourceHandler();
1403
- this.registerUnsubscribeResourceHandler();
1404
- if (opts.resources.resourceTemplates) {
1405
- this.registerListResourceTemplatesHandler();
1406
- }
1407
- }
1408
- if (opts.prompts) {
1409
- this.registerListPromptsHandler();
1410
- this.registerGetPromptHandler({
1411
- getPromptMessagesCallback: opts.prompts.getPromptMessages
1412
- });
1413
- }
1439
+ this.registerHandlersOnServer(this.server);
1414
1440
  this.resources = new ServerResourceActions({
1415
1441
  getSubscriptions: () => this.subscriptions,
1416
1442
  getLogger: () => this.logger,
@@ -1429,6 +1455,342 @@ var MCPServer = class extends MCPServerBase {
1429
1455
  this.definedPrompts = void 0;
1430
1456
  }
1431
1457
  });
1458
+ this.elicitation = {
1459
+ sendRequest: async (request) => {
1460
+ return this.handleElicitationRequest(request);
1461
+ }
1462
+ };
1463
+ }
1464
+ /**
1465
+ * Handle an elicitation request by sending it to the connected client.
1466
+ * This method sends an elicitation/create request to the client and waits for the response.
1467
+ *
1468
+ * @param request - The elicitation request containing message and schema
1469
+ * @param serverInstance - Optional server instance to use; defaults to main server for backward compatibility
1470
+ * @returns Promise that resolves to the client's response
1471
+ */
1472
+ async handleElicitationRequest(request, serverInstance) {
1473
+ this.logger.debug(`Sending elicitation request: ${request.message}`);
1474
+ const server = serverInstance || this.server;
1475
+ const response = await server.elicitInput(request);
1476
+ this.logger.debug(`Received elicitation response: ${JSON.stringify(response)}`);
1477
+ return response;
1478
+ }
1479
+ /**
1480
+ * Creates a new Server instance configured with all handlers for HTTP sessions.
1481
+ * Each HTTP client connection gets its own Server instance to avoid routing conflicts.
1482
+ */
1483
+ createServerInstance() {
1484
+ const capabilities = {
1485
+ tools: {},
1486
+ logging: { enabled: true },
1487
+ elicitation: {}
1488
+ };
1489
+ if (this.resourceOptions) {
1490
+ capabilities.resources = { subscribe: true, listChanged: true };
1491
+ }
1492
+ if (this.promptOptions) {
1493
+ capabilities.prompts = { listChanged: true };
1494
+ }
1495
+ const serverInstance = new Server({ name: this.name, version: this.version }, { capabilities });
1496
+ this.registerHandlersOnServer(serverInstance);
1497
+ return serverInstance;
1498
+ }
1499
+ /**
1500
+ * Registers all MCP handlers on a given server instance.
1501
+ * This allows us to create multiple server instances with identical functionality.
1502
+ */
1503
+ registerHandlersOnServer(serverInstance) {
1504
+ serverInstance.setRequestHandler(ListToolsRequestSchema, async () => {
1505
+ this.logger.debug("Handling ListTools request");
1506
+ return {
1507
+ tools: Object.values(this.convertedTools).map((tool) => {
1508
+ const toolSpec = {
1509
+ name: tool.name,
1510
+ description: tool.description,
1511
+ inputSchema: tool.parameters.jsonSchema
1512
+ };
1513
+ if (tool.outputSchema) {
1514
+ toolSpec.outputSchema = tool.outputSchema.jsonSchema;
1515
+ }
1516
+ return toolSpec;
1517
+ })
1518
+ };
1519
+ });
1520
+ serverInstance.setRequestHandler(CallToolRequestSchema, async (request) => {
1521
+ const startTime = Date.now();
1522
+ try {
1523
+ const tool = this.convertedTools[request.params.name];
1524
+ if (!tool) {
1525
+ this.logger.warn(`CallTool: Unknown tool '${request.params.name}' requested.`);
1526
+ return {
1527
+ content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }],
1528
+ isError: true
1529
+ };
1530
+ }
1531
+ const validation = tool.parameters.validate?.(request.params.arguments ?? {});
1532
+ if (validation && !validation.success) {
1533
+ this.logger.warn(`CallTool: Invalid tool arguments for '${request.params.name}'`, {
1534
+ errors: validation.error
1535
+ });
1536
+ return {
1537
+ content: [{ type: "text", text: `Invalid tool arguments: ${JSON.stringify(validation.error)}` }],
1538
+ isError: true
1539
+ };
1540
+ }
1541
+ if (!tool.execute) {
1542
+ this.logger.warn(`CallTool: Tool '${request.params.name}' does not have an execute function.`);
1543
+ return {
1544
+ content: [{ type: "text", text: `Tool '${request.params.name}' does not have an execute function.` }],
1545
+ isError: true
1546
+ };
1547
+ }
1548
+ const sessionElicitation = {
1549
+ sendRequest: async (request2) => {
1550
+ return this.handleElicitationRequest(request2, serverInstance);
1551
+ }
1552
+ };
1553
+ const result = await tool.execute(validation?.value, {
1554
+ messages: [],
1555
+ toolCallId: "",
1556
+ elicitation: sessionElicitation
1557
+ });
1558
+ this.logger.debug(`CallTool: Tool '${request.params.name}' executed successfully with result:`, result);
1559
+ const duration = Date.now() - startTime;
1560
+ this.logger.info(`Tool '${request.params.name}' executed successfully in ${duration}ms.`);
1561
+ const response = { isError: false, content: [] };
1562
+ if (tool.outputSchema) {
1563
+ if (!result.structuredContent) {
1564
+ throw new Error(`Tool ${request.params.name} has an output schema but no structured content was provided.`);
1565
+ }
1566
+ const outputValidation = tool.outputSchema.validate?.(result.structuredContent ?? {});
1567
+ if (outputValidation && !outputValidation.success) {
1568
+ this.logger.warn(`CallTool: Invalid structured content for '${request.params.name}'`, {
1569
+ errors: outputValidation.error
1570
+ });
1571
+ throw new Error(
1572
+ `Invalid structured content for tool ${request.params.name}: ${JSON.stringify(outputValidation.error)}`
1573
+ );
1574
+ }
1575
+ response.structuredContent = result.structuredContent;
1576
+ }
1577
+ if (response.structuredContent) {
1578
+ response.content = [{ type: "text", text: JSON.stringify(response.structuredContent) }];
1579
+ } else {
1580
+ response.content = [
1581
+ {
1582
+ type: "text",
1583
+ text: typeof result === "string" ? result : JSON.stringify(result)
1584
+ }
1585
+ ];
1586
+ }
1587
+ return response;
1588
+ } catch (error) {
1589
+ const duration = Date.now() - startTime;
1590
+ if (error instanceof z.ZodError) {
1591
+ this.logger.warn("Invalid tool arguments", {
1592
+ tool: request.params.name,
1593
+ errors: error.errors,
1594
+ duration: `${duration}ms`
1595
+ });
1596
+ return {
1597
+ content: [
1598
+ {
1599
+ type: "text",
1600
+ text: `Invalid arguments: ${error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`
1601
+ }
1602
+ ],
1603
+ isError: true
1604
+ };
1605
+ }
1606
+ this.logger.error(`Tool execution failed: ${request.params.name}`, { error });
1607
+ return {
1608
+ content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
1609
+ isError: true
1610
+ };
1611
+ }
1612
+ });
1613
+ if (this.resourceOptions) {
1614
+ this.registerResourceHandlersOnServer(serverInstance);
1615
+ }
1616
+ if (this.promptOptions) {
1617
+ this.registerPromptHandlersOnServer(serverInstance);
1618
+ }
1619
+ }
1620
+ /**
1621
+ * Registers resource-related handlers on a server instance.
1622
+ */
1623
+ registerResourceHandlersOnServer(serverInstance) {
1624
+ const capturedResourceOptions = this.resourceOptions;
1625
+ if (!capturedResourceOptions) return;
1626
+ if (capturedResourceOptions.listResources) {
1627
+ serverInstance.setRequestHandler(ListResourcesRequestSchema, async () => {
1628
+ this.logger.debug("Handling ListResources request");
1629
+ if (this.definedResources) {
1630
+ return { resources: this.definedResources };
1631
+ } else {
1632
+ try {
1633
+ const resources = await capturedResourceOptions.listResources();
1634
+ this.definedResources = resources;
1635
+ this.logger.debug(`Fetched and cached ${this.definedResources.length} resources.`);
1636
+ return { resources: this.definedResources };
1637
+ } catch (error) {
1638
+ this.logger.error("Error fetching resources via listResources():", { error });
1639
+ throw error;
1640
+ }
1641
+ }
1642
+ });
1643
+ }
1644
+ if (capturedResourceOptions.getResourceContent) {
1645
+ serverInstance.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1646
+ const startTime = Date.now();
1647
+ const uri = request.params.uri;
1648
+ this.logger.debug(`Handling ReadResource request for URI: ${uri}`);
1649
+ if (!this.definedResources) {
1650
+ const resources = await this.resourceOptions?.listResources?.();
1651
+ if (!resources) throw new Error("Failed to load resources");
1652
+ this.definedResources = resources;
1653
+ }
1654
+ const resource = this.definedResources?.find((r) => r.uri === uri);
1655
+ if (!resource) {
1656
+ this.logger.warn(`ReadResource: Unknown resource URI '${uri}' requested.`);
1657
+ throw new Error(`Resource not found: ${uri}`);
1658
+ }
1659
+ try {
1660
+ const resourcesOrResourceContent = await capturedResourceOptions.getResourceContent({ uri });
1661
+ const resourcesContent = Array.isArray(resourcesOrResourceContent) ? resourcesOrResourceContent : [resourcesOrResourceContent];
1662
+ const contents = resourcesContent.map((resourceContent) => {
1663
+ const contentItem = {
1664
+ uri: resource.uri,
1665
+ mimeType: resource.mimeType
1666
+ };
1667
+ if ("text" in resourceContent) {
1668
+ contentItem.text = resourceContent.text;
1669
+ }
1670
+ if ("blob" in resourceContent) {
1671
+ contentItem.blob = resourceContent.blob;
1672
+ }
1673
+ return contentItem;
1674
+ });
1675
+ const duration = Date.now() - startTime;
1676
+ this.logger.info(`Resource '${uri}' read successfully in ${duration}ms.`);
1677
+ return {
1678
+ contents
1679
+ };
1680
+ } catch (error) {
1681
+ const duration = Date.now() - startTime;
1682
+ this.logger.error(`Failed to get content for resource URI '${uri}' in ${duration}ms`, { error });
1683
+ throw error;
1684
+ }
1685
+ });
1686
+ }
1687
+ if (capturedResourceOptions.resourceTemplates) {
1688
+ serverInstance.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
1689
+ this.logger.debug("Handling ListResourceTemplates request");
1690
+ if (this.definedResourceTemplates) {
1691
+ return { resourceTemplates: this.definedResourceTemplates };
1692
+ } else {
1693
+ try {
1694
+ const templates = await capturedResourceOptions.resourceTemplates();
1695
+ this.definedResourceTemplates = templates;
1696
+ this.logger.debug(`Fetched and cached ${this.definedResourceTemplates.length} resource templates.`);
1697
+ return { resourceTemplates: this.definedResourceTemplates };
1698
+ } catch (error) {
1699
+ this.logger.error("Error fetching resource templates via resourceTemplates():", { error });
1700
+ throw error;
1701
+ }
1702
+ }
1703
+ });
1704
+ }
1705
+ serverInstance.setRequestHandler(SubscribeRequestSchema, async (request) => {
1706
+ const uri = request.params.uri;
1707
+ this.logger.info(`Received resources/subscribe request for URI: ${uri}`);
1708
+ this.subscriptions.add(uri);
1709
+ return {};
1710
+ });
1711
+ serverInstance.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
1712
+ const uri = request.params.uri;
1713
+ this.logger.info(`Received resources/unsubscribe request for URI: ${uri}`);
1714
+ this.subscriptions.delete(uri);
1715
+ return {};
1716
+ });
1717
+ }
1718
+ /**
1719
+ * Registers prompt-related handlers on a server instance.
1720
+ */
1721
+ registerPromptHandlersOnServer(serverInstance) {
1722
+ const capturedPromptOptions = this.promptOptions;
1723
+ if (!capturedPromptOptions) return;
1724
+ if (capturedPromptOptions.listPrompts) {
1725
+ serverInstance.setRequestHandler(ListPromptsRequestSchema, async () => {
1726
+ this.logger.debug("Handling ListPrompts request");
1727
+ if (this.definedPrompts) {
1728
+ return {
1729
+ prompts: this.definedPrompts?.map((p) => ({ ...p, version: p.version ?? void 0 }))
1730
+ };
1731
+ } else {
1732
+ try {
1733
+ const prompts = await capturedPromptOptions.listPrompts();
1734
+ for (const prompt of prompts) {
1735
+ PromptSchema.parse(prompt);
1736
+ }
1737
+ this.definedPrompts = prompts;
1738
+ this.logger.debug(`Fetched and cached ${this.definedPrompts.length} prompts.`);
1739
+ return {
1740
+ prompts: this.definedPrompts?.map((p) => ({ ...p, version: p.version ?? void 0 }))
1741
+ };
1742
+ } catch (error) {
1743
+ this.logger.error("Error fetching prompts via listPrompts():", {
1744
+ error: error instanceof Error ? error.message : String(error)
1745
+ });
1746
+ throw error;
1747
+ }
1748
+ }
1749
+ });
1750
+ }
1751
+ if (capturedPromptOptions.getPromptMessages) {
1752
+ serverInstance.setRequestHandler(
1753
+ GetPromptRequestSchema,
1754
+ async (request) => {
1755
+ const startTime = Date.now();
1756
+ const { name, version, arguments: args } = request.params;
1757
+ if (!this.definedPrompts) {
1758
+ const prompts = await this.promptOptions?.listPrompts?.();
1759
+ if (!prompts) throw new Error("Failed to load prompts");
1760
+ this.definedPrompts = prompts;
1761
+ }
1762
+ let prompt;
1763
+ if (version) {
1764
+ prompt = this.definedPrompts?.find((p) => p.name === name && p.version === version);
1765
+ } else {
1766
+ prompt = this.definedPrompts?.find((p) => p.name === name);
1767
+ }
1768
+ if (!prompt) throw new Error(`Prompt "${name}"${version ? ` (version ${version})` : ""} not found`);
1769
+ if (prompt.arguments) {
1770
+ for (const arg of prompt.arguments) {
1771
+ if (arg.required && (args?.[arg.name] === void 0 || args?.[arg.name] === null)) {
1772
+ throw new Error(`Missing required argument: ${arg.name}`);
1773
+ }
1774
+ }
1775
+ }
1776
+ try {
1777
+ let messages = [];
1778
+ if (capturedPromptOptions.getPromptMessages) {
1779
+ messages = await capturedPromptOptions.getPromptMessages({ name, version, args });
1780
+ }
1781
+ const duration = Date.now() - startTime;
1782
+ this.logger.info(
1783
+ `Prompt '${name}'${version ? ` (version ${version})` : ""} retrieved successfully in ${duration}ms.`
1784
+ );
1785
+ return { prompt, messages };
1786
+ } catch (error) {
1787
+ const duration = Date.now() - startTime;
1788
+ this.logger.error(`Failed to get content for prompt '${name}' in ${duration}ms`, { error });
1789
+ throw error;
1790
+ }
1791
+ }
1792
+ );
1793
+ }
1432
1794
  }
1433
1795
  convertAgentsToTools(agentsConfig, definedConvertedTools) {
1434
1796
  const agentTools = {};
@@ -1628,368 +1990,6 @@ var MCPServer = class extends MCPServerBase {
1628
1990
  );
1629
1991
  return allConvertedTools;
1630
1992
  }
1631
- /**
1632
- * Register the ListTools handler for listing all available tools.
1633
- */
1634
- registerListToolsHandler() {
1635
- if (this.listToolsHandlerIsRegistered) {
1636
- return;
1637
- }
1638
- this.listToolsHandlerIsRegistered = true;
1639
- this.server.setRequestHandler(ListToolsRequestSchema, async () => {
1640
- this.logger.debug("Handling ListTools request");
1641
- return {
1642
- tools: Object.values(this.convertedTools).map((tool) => {
1643
- const toolSpec = {
1644
- name: tool.name,
1645
- description: tool.description,
1646
- inputSchema: tool.parameters.jsonSchema
1647
- };
1648
- if (tool.outputSchema) {
1649
- toolSpec.outputSchema = tool.outputSchema.jsonSchema;
1650
- }
1651
- return toolSpec;
1652
- })
1653
- };
1654
- });
1655
- }
1656
- /**
1657
- * Register the CallTool handler for executing a tool by name.
1658
- */
1659
- registerCallToolHandler() {
1660
- if (this.callToolHandlerIsRegistered) {
1661
- return;
1662
- }
1663
- this.callToolHandlerIsRegistered = true;
1664
- this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
1665
- const startTime = Date.now();
1666
- try {
1667
- const tool = this.convertedTools[request.params.name];
1668
- if (!tool) {
1669
- this.logger.warn(`CallTool: Unknown tool '${request.params.name}' requested.`);
1670
- return {
1671
- content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }],
1672
- isError: true
1673
- };
1674
- }
1675
- const validation = tool.parameters.validate?.(request.params.arguments ?? {});
1676
- if (validation && !validation.success) {
1677
- this.logger.warn(`CallTool: Invalid tool arguments for '${request.params.name}'`, {
1678
- errors: validation.error
1679
- });
1680
- return {
1681
- content: [{ type: "text", text: `Invalid tool arguments: ${JSON.stringify(validation.error)}` }],
1682
- isError: true
1683
- };
1684
- }
1685
- if (!tool.execute) {
1686
- this.logger.warn(`CallTool: Tool '${request.params.name}' does not have an execute function.`);
1687
- return {
1688
- content: [{ type: "text", text: `Tool '${request.params.name}' does not have an execute function.` }],
1689
- isError: true
1690
- };
1691
- }
1692
- const result = await tool.execute(validation?.value, { messages: [], toolCallId: "" });
1693
- this.logger.debug(`CallTool: Tool '${request.params.name}' executed successfully with result:`, result);
1694
- const duration = Date.now() - startTime;
1695
- this.logger.info(`Tool '${request.params.name}' executed successfully in ${duration}ms.`);
1696
- const response = { isError: false, content: [] };
1697
- if (tool.outputSchema) {
1698
- if (!result.structuredContent) {
1699
- throw new Error(`Tool ${request.params.name} has an output schema but no structured content was provided.`);
1700
- }
1701
- const outputValidation = tool.outputSchema.validate?.(result.structuredContent ?? {});
1702
- if (outputValidation && !outputValidation.success) {
1703
- this.logger.warn(`CallTool: Invalid structured content for '${request.params.name}'`, {
1704
- errors: outputValidation.error
1705
- });
1706
- throw new Error(
1707
- `Invalid structured content for tool ${request.params.name}: ${JSON.stringify(outputValidation.error)}`
1708
- );
1709
- }
1710
- response.structuredContent = result.structuredContent;
1711
- }
1712
- if (result.content) {
1713
- response.content = result.content;
1714
- } else if (response.structuredContent) {
1715
- response.content = [{ type: "text", text: JSON.stringify(response.structuredContent) }];
1716
- } else {
1717
- response.content = [
1718
- {
1719
- type: "text",
1720
- text: typeof result === "string" ? result : JSON.stringify(result)
1721
- }
1722
- ];
1723
- }
1724
- return response;
1725
- } catch (error) {
1726
- const duration = Date.now() - startTime;
1727
- if (error instanceof z.ZodError) {
1728
- this.logger.warn("Invalid tool arguments", {
1729
- tool: request.params.name,
1730
- errors: error.errors,
1731
- duration: `${duration}ms`
1732
- });
1733
- return {
1734
- content: [
1735
- {
1736
- type: "text",
1737
- text: `Invalid arguments: ${error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`
1738
- }
1739
- ],
1740
- isError: true
1741
- };
1742
- }
1743
- this.logger.error(`Tool execution failed: ${request.params.name}`, { error });
1744
- return {
1745
- content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
1746
- isError: true
1747
- };
1748
- }
1749
- });
1750
- }
1751
- /**
1752
- * Register the ListResources handler for listing all available resources.
1753
- */
1754
- registerListResourcesHandler() {
1755
- if (this.listResourcesHandlerIsRegistered) {
1756
- return;
1757
- }
1758
- this.listResourcesHandlerIsRegistered = true;
1759
- const capturedResourceOptions = this.resourceOptions;
1760
- if (!capturedResourceOptions?.listResources) {
1761
- this.logger.warn("ListResources capability not supported by server configuration.");
1762
- return;
1763
- }
1764
- this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
1765
- this.logger.debug("Handling ListResources request");
1766
- if (this.definedResources) {
1767
- return { resources: this.definedResources };
1768
- } else {
1769
- try {
1770
- const resources = await capturedResourceOptions.listResources();
1771
- this.definedResources = resources;
1772
- this.logger.debug(`Fetched and cached ${this.definedResources.length} resources.`);
1773
- return { resources: this.definedResources };
1774
- } catch (error) {
1775
- this.logger.error("Error fetching resources via listResources():", { error });
1776
- throw error;
1777
- }
1778
- }
1779
- });
1780
- }
1781
- /**
1782
- * Register the ReadResource handler for reading a resource by URI.
1783
- */
1784
- registerReadResourceHandler({
1785
- getResourcesCallback
1786
- }) {
1787
- if (this.readResourceHandlerIsRegistered) {
1788
- return;
1789
- }
1790
- this.readResourceHandlerIsRegistered = true;
1791
- this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1792
- const startTime = Date.now();
1793
- const uri = request.params.uri;
1794
- this.logger.debug(`Handling ReadResource request for URI: ${uri}`);
1795
- if (!this.definedResources) {
1796
- const resources = await this.resourceOptions?.listResources?.();
1797
- if (!resources) throw new Error("Failed to load resources");
1798
- this.definedResources = resources;
1799
- }
1800
- const resource = this.definedResources?.find((r) => r.uri === uri);
1801
- if (!resource) {
1802
- this.logger.warn(`ReadResource: Unknown resource URI '${uri}' requested.`);
1803
- throw new Error(`Resource not found: ${uri}`);
1804
- }
1805
- try {
1806
- const resourcesOrResourceContent = await getResourcesCallback({ uri });
1807
- const resourcesContent = Array.isArray(resourcesOrResourceContent) ? resourcesOrResourceContent : [resourcesOrResourceContent];
1808
- const contents = resourcesContent.map((resourceContent) => {
1809
- const contentItem = {
1810
- uri: resource.uri,
1811
- mimeType: resource.mimeType
1812
- };
1813
- if ("text" in resourceContent) {
1814
- contentItem.text = resourceContent.text;
1815
- }
1816
- if ("blob" in resourceContent) {
1817
- contentItem.blob = resourceContent.blob;
1818
- }
1819
- return contentItem;
1820
- });
1821
- const duration = Date.now() - startTime;
1822
- this.logger.info(`Resource '${uri}' read successfully in ${duration}ms.`);
1823
- return {
1824
- contents
1825
- };
1826
- } catch (error) {
1827
- const duration = Date.now() - startTime;
1828
- this.logger.error(`Failed to get content for resource URI '${uri}' in ${duration}ms`, { error });
1829
- throw error;
1830
- }
1831
- });
1832
- }
1833
- /**
1834
- * Register the ListResourceTemplates handler.
1835
- */
1836
- registerListResourceTemplatesHandler() {
1837
- if (this.listResourceTemplatesHandlerIsRegistered) {
1838
- return;
1839
- }
1840
- if (!this.resourceOptions || typeof this.resourceOptions.resourceTemplates !== "function") {
1841
- this.logger.warn(
1842
- "ListResourceTemplates handler called, but resourceTemplates function is not available on resourceOptions or not a function."
1843
- );
1844
- this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
1845
- this.logger.debug("Handling ListResourceTemplates request (no templates configured or resourceOptions issue)");
1846
- return { resourceTemplates: [] };
1847
- });
1848
- this.listResourceTemplatesHandlerIsRegistered = true;
1849
- return;
1850
- }
1851
- const resourceTemplatesFn = this.resourceOptions.resourceTemplates;
1852
- this.listResourceTemplatesHandlerIsRegistered = true;
1853
- this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
1854
- this.logger.debug("Handling ListResourceTemplates request");
1855
- if (this.definedResourceTemplates) {
1856
- return { resourceTemplates: this.definedResourceTemplates };
1857
- } else {
1858
- try {
1859
- const templates = await resourceTemplatesFn();
1860
- this.definedResourceTemplates = templates;
1861
- this.logger.debug(`Fetched and cached ${this.definedResourceTemplates.length} resource templates.`);
1862
- return { resourceTemplates: this.definedResourceTemplates };
1863
- } catch (error) {
1864
- this.logger.error("Error fetching resource templates via resourceTemplates():", { error });
1865
- throw error;
1866
- }
1867
- }
1868
- });
1869
- }
1870
- /**
1871
- * Register the SubscribeResource handler.
1872
- */
1873
- registerSubscribeResourceHandler() {
1874
- if (this.subscribeResourceHandlerIsRegistered) {
1875
- return;
1876
- }
1877
- if (!SubscribeRequestSchema) {
1878
- this.logger.warn("SubscribeRequestSchema not available, cannot register SubscribeResource handler.");
1879
- return;
1880
- }
1881
- this.subscribeResourceHandlerIsRegistered = true;
1882
- this.server.setRequestHandler(SubscribeRequestSchema, async (request) => {
1883
- const uri = request.params.uri;
1884
- this.logger.info(`Received resources/subscribe request for URI: ${uri}`);
1885
- this.subscriptions.add(uri);
1886
- return {};
1887
- });
1888
- }
1889
- /**
1890
- * Register the UnsubscribeResource handler.
1891
- */
1892
- registerUnsubscribeResourceHandler() {
1893
- if (this.unsubscribeResourceHandlerIsRegistered) {
1894
- return;
1895
- }
1896
- this.unsubscribeResourceHandlerIsRegistered = true;
1897
- this.server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
1898
- const uri = request.params.uri;
1899
- this.logger.info(`Received resources/unsubscribe request for URI: ${uri}`);
1900
- this.subscriptions.delete(uri);
1901
- return {};
1902
- });
1903
- }
1904
- /**
1905
- * Register the ListPrompts handler.
1906
- */
1907
- registerListPromptsHandler() {
1908
- if (this.listPromptsHandlerIsRegistered) {
1909
- return;
1910
- }
1911
- this.listPromptsHandlerIsRegistered = true;
1912
- const capturedPromptOptions = this.promptOptions;
1913
- if (!capturedPromptOptions?.listPrompts) {
1914
- this.logger.warn("ListPrompts capability not supported by server configuration.");
1915
- return;
1916
- }
1917
- this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
1918
- this.logger.debug("Handling ListPrompts request");
1919
- if (this.definedPrompts) {
1920
- return {
1921
- prompts: this.definedPrompts?.map((p) => ({ ...p, version: p.version ?? void 0 }))
1922
- };
1923
- } else {
1924
- try {
1925
- const prompts = await capturedPromptOptions.listPrompts();
1926
- for (const prompt of prompts) {
1927
- PromptSchema.parse(prompt);
1928
- }
1929
- this.definedPrompts = prompts;
1930
- this.logger.debug(`Fetched and cached ${this.definedPrompts.length} prompts.`);
1931
- return {
1932
- prompts: this.definedPrompts?.map((p) => ({ ...p, version: p.version ?? void 0 }))
1933
- };
1934
- } catch (error) {
1935
- this.logger.error("Error fetching prompts via listPrompts():", {
1936
- error: error instanceof Error ? error.message : String(error)
1937
- });
1938
- throw error;
1939
- }
1940
- }
1941
- });
1942
- }
1943
- /**
1944
- * Register the GetPrompt handler.
1945
- */
1946
- registerGetPromptHandler({
1947
- getPromptMessagesCallback
1948
- }) {
1949
- if (this.getPromptHandlerIsRegistered) return;
1950
- this.getPromptHandlerIsRegistered = true;
1951
- this.server.setRequestHandler(
1952
- GetPromptRequestSchema,
1953
- async (request) => {
1954
- const startTime = Date.now();
1955
- const { name, version, arguments: args } = request.params;
1956
- if (!this.definedPrompts) {
1957
- const prompts = await this.promptOptions?.listPrompts?.();
1958
- if (!prompts) throw new Error("Failed to load prompts");
1959
- this.definedPrompts = prompts;
1960
- }
1961
- let prompt;
1962
- if (version) {
1963
- prompt = this.definedPrompts?.find((p) => p.name === name && p.version === version);
1964
- } else {
1965
- prompt = this.definedPrompts?.find((p) => p.name === name);
1966
- }
1967
- if (!prompt) throw new Error(`Prompt "${name}"${version ? ` (version ${version})` : ""} not found`);
1968
- if (prompt.arguments) {
1969
- for (const arg of prompt.arguments) {
1970
- if (arg.required && (args?.[arg.name] === void 0 || args?.[arg.name] === null)) {
1971
- throw new Error(`Missing required argument: ${arg.name}`);
1972
- }
1973
- }
1974
- }
1975
- try {
1976
- let messages = [];
1977
- if (getPromptMessagesCallback) {
1978
- messages = await getPromptMessagesCallback({ name, version, args });
1979
- }
1980
- const duration = Date.now() - startTime;
1981
- this.logger.info(
1982
- `Prompt '${name}'${version ? ` (version ${version})` : ""} retrieved successfully in ${duration}ms.`
1983
- );
1984
- return { prompt, messages };
1985
- } catch (error) {
1986
- const duration = Date.now() - startTime;
1987
- this.logger.error(`Failed to get content for prompt '${name}' in ${duration}ms`, { error });
1988
- throw error;
1989
- }
1990
- }
1991
- );
1992
- }
1993
1993
  /**
1994
1994
  * Start the MCP server using stdio transport (for Windsurf integration).
1995
1995
  */
@@ -2202,11 +2202,17 @@ var MCPServer = class extends MCPServerBase {
2202
2202
  `startHTTP: Streamable HTTP transport closed for session ${closedSessionId}, removing from map.`
2203
2203
  );
2204
2204
  this.streamableHTTPTransports.delete(closedSessionId);
2205
+ if (this.httpServerInstances.has(closedSessionId)) {
2206
+ this.httpServerInstances.delete(closedSessionId);
2207
+ this.logger.debug(`startHTTP: Cleaned up server instance for closed session ${closedSessionId}`);
2208
+ }
2205
2209
  }
2206
2210
  };
2207
- await this.server.connect(transport);
2211
+ const sessionServerInstance = this.createServerInstance();
2212
+ await sessionServerInstance.connect(transport);
2208
2213
  if (transport.sessionId) {
2209
2214
  this.streamableHTTPTransports.set(transport.sessionId, transport);
2215
+ this.httpServerInstances.set(transport.sessionId, sessionServerInstance);
2210
2216
  this.logger.debug(
2211
2217
  `startHTTP: Streamable HTTP session initialized and stored with ID: ${transport.sessionId}`
2212
2218
  );
@@ -2348,13 +2354,6 @@ var MCPServer = class extends MCPServerBase {
2348
2354
  * Close the MCP server and all its connections
2349
2355
  */
2350
2356
  async close() {
2351
- this.callToolHandlerIsRegistered = false;
2352
- this.listToolsHandlerIsRegistered = false;
2353
- this.listResourcesHandlerIsRegistered = false;
2354
- this.readResourceHandlerIsRegistered = false;
2355
- this.listResourceTemplatesHandlerIsRegistered = false;
2356
- this.subscribeResourceHandlerIsRegistered = false;
2357
- this.unsubscribeResourceHandlerIsRegistered = false;
2358
2357
  try {
2359
2358
  if (this.stdioTransport) {
2360
2359
  await this.stdioTransport.close?.();
@@ -2376,6 +2375,12 @@ var MCPServer = class extends MCPServerBase {
2376
2375
  }
2377
2376
  this.streamableHTTPTransports.clear();
2378
2377
  }
2378
+ if (this.httpServerInstances) {
2379
+ for (const serverInstance of this.httpServerInstances.values()) {
2380
+ await serverInstance.close?.();
2381
+ }
2382
+ this.httpServerInstances.clear();
2383
+ }
2379
2384
  await this.server.close();
2380
2385
  this.logger.info("MCP server closed.");
2381
2386
  } catch (error) {