@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/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +38 -0
- package/dist/_tsup-dts-rollup.d.cts +84 -51
- package/dist/_tsup-dts-rollup.d.ts +84 -51
- package/dist/index.cjs +403 -398
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +404 -399
- package/integration-tests/node_modules/.bin/mastra +21 -0
- package/package.json +3 -3
- package/src/client/client.test.ts +310 -1
- package/src/client/client.ts +21 -2
- package/src/client/configuration.ts +22 -2
- package/src/client/elicitationActions.ts +26 -0
- package/src/client/index.ts +1 -1
- package/src/server/server.test.ts +349 -0
- package/src/server/server.ts +424 -457
- package/src/server/types.ts +25 -1
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
|
-
|
|
1334
|
-
|
|
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.
|
|
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
|
-
|
|
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) {
|