@mastra/mcp 0.10.2 → 0.10.3

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.d.cts CHANGED
@@ -7,9 +7,11 @@ export { MCPClientOptions } from './_tsup-dts-rollup.cjs';
7
7
  export { MCPClient } from './_tsup-dts-rollup.cjs';
8
8
  export { MCPConfigurationOptions } from './_tsup-dts-rollup.cjs';
9
9
  export { MCPConfiguration } from './_tsup-dts-rollup.cjs';
10
+ export { MCPServer } from './_tsup-dts-rollup.cjs';
10
11
  export { MCPServerResourceContentCallback } from './_tsup-dts-rollup.cjs';
11
12
  export { MCPServerResourceContent } from './_tsup-dts-rollup.cjs';
12
13
  export { MCPServerResources } from './_tsup-dts-rollup.cjs';
14
+ export { MCPServerPromptMessagesCallback } from './_tsup-dts-rollup.cjs';
15
+ export { MCPServerPrompts } from './_tsup-dts-rollup.cjs';
13
16
  export { Resource } from './_tsup-dts-rollup.cjs';
14
17
  export { ResourceTemplate } from './_tsup-dts-rollup.cjs';
15
- export { MCPServer } from './_tsup-dts-rollup.cjs';
package/dist/index.d.ts CHANGED
@@ -7,9 +7,11 @@ export { MCPClientOptions } from './_tsup-dts-rollup.js';
7
7
  export { MCPClient } from './_tsup-dts-rollup.js';
8
8
  export { MCPConfigurationOptions } from './_tsup-dts-rollup.js';
9
9
  export { MCPConfiguration } from './_tsup-dts-rollup.js';
10
+ export { MCPServer } from './_tsup-dts-rollup.js';
10
11
  export { MCPServerResourceContentCallback } from './_tsup-dts-rollup.js';
11
12
  export { MCPServerResourceContent } from './_tsup-dts-rollup.js';
12
13
  export { MCPServerResources } from './_tsup-dts-rollup.js';
14
+ export { MCPServerPromptMessagesCallback } from './_tsup-dts-rollup.js';
15
+ export { MCPServerPrompts } from './_tsup-dts-rollup.js';
13
16
  export { Resource } from './_tsup-dts-rollup.js';
14
17
  export { ResourceTemplate } from './_tsup-dts-rollup.js';
15
- export { MCPServer } from './_tsup-dts-rollup.js';
package/dist/index.js CHANGED
@@ -6,13 +6,13 @@ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
6
6
  import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
7
7
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
8
8
  import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
9
- import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, ListResourcesResultSchema, ReadResourceResultSchema, ListResourceTemplatesResultSchema, ResourceUpdatedNotificationSchema, ResourceListChangedNotificationSchema, CallToolResultSchema, JSONRPCMessageSchema, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
9
+ 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
10
  import { asyncExitHook, gracefulExit } from 'exit-hook';
11
11
  import { z } from 'zod';
12
12
  import { convertJsonSchemaToZod } from 'zod-from-json-schema';
13
13
  import equal from 'fast-deep-equal';
14
14
  import { v5 } from 'uuid';
15
- import { randomUUID } from 'node:crypto';
15
+ import { randomUUID } from 'crypto';
16
16
  import { createTool, makeCoreTool } from '@mastra/core';
17
17
  import { Agent } from '@mastra/core/agent';
18
18
  import { MCPServerBase } from '@mastra/core/mcp';
@@ -24,6 +24,58 @@ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/
24
24
  import { streamSSE } from 'hono/streaming';
25
25
 
26
26
  // src/client/client.ts
27
+ var PromptClientActions = class {
28
+ client;
29
+ logger;
30
+ constructor({ client, logger }) {
31
+ this.client = client;
32
+ this.logger = logger;
33
+ }
34
+ /**
35
+ * Get all prompts from the connected MCP server.
36
+ * @returns A list of prompts with their versions.
37
+ */
38
+ async list() {
39
+ try {
40
+ const response = await this.client.listPrompts();
41
+ if (response && response.prompts && Array.isArray(response.prompts)) {
42
+ return response.prompts.map((prompt) => ({ ...prompt, version: prompt.version || "" }));
43
+ } else {
44
+ this.logger.warn(`Prompts response from server ${this.client.name} did not have expected structure.`, {
45
+ response
46
+ });
47
+ return [];
48
+ }
49
+ } catch (e) {
50
+ if (e.code === ErrorCode.MethodNotFound) {
51
+ return [];
52
+ }
53
+ this.logger.error(`Error getting prompts from server ${this.client.name}`, {
54
+ error: e instanceof Error ? e.message : String(e)
55
+ });
56
+ throw new Error(
57
+ `Failed to fetch prompts from server ${this.client.name}: ${e instanceof Error ? e.stack || e.message : String(e)}`
58
+ );
59
+ }
60
+ }
61
+ /**
62
+ * Get a specific prompt.
63
+ * @param name The name of the prompt to get.
64
+ * @param args Optional arguments for the prompt.
65
+ * @param version Optional version of the prompt to get.
66
+ * @returns The prompt content.
67
+ */
68
+ async get({ name, args, version }) {
69
+ return this.client.getPrompt({ name, args, version });
70
+ }
71
+ /**
72
+ * Set a notification handler for when the list of available prompts changes.
73
+ * @param handler The callback function to handle the notification.
74
+ */
75
+ async onListChanged(handler) {
76
+ this.client.setPromptListChangedNotificationHandler(handler);
77
+ }
78
+ };
27
79
  var ResourceClientActions = class {
28
80
  client;
29
81
  logger;
@@ -53,7 +105,6 @@ var ResourceClientActions = class {
53
105
  this.logger.error(`Error getting resources from server ${this.client.name}`, {
54
106
  error: e instanceof Error ? e.message : String(e)
55
107
  });
56
- console.log("errorheere", e);
57
108
  throw new Error(
58
109
  `Failed to fetch resources from server ${this.client.name}: ${e instanceof Error ? e.stack || e.message : String(e)}`
59
110
  );
@@ -76,7 +127,6 @@ var ResourceClientActions = class {
76
127
  return [];
77
128
  }
78
129
  } catch (e) {
79
- console.log({ errorcooode: e.code });
80
130
  if (e.code === ErrorCode.MethodNotFound) {
81
131
  return [];
82
132
  }
@@ -155,6 +205,7 @@ var InternalMastraMCPClient = class extends MastraBase {
155
205
  transport;
156
206
  currentOperationContext = null;
157
207
  resources;
208
+ prompts;
158
209
  constructor({
159
210
  name,
160
211
  version = "1.0.0",
@@ -179,6 +230,7 @@ var InternalMastraMCPClient = class extends MastraBase {
179
230
  );
180
231
  this.setupLogging();
181
232
  this.resources = new ResourceClientActions({ client: this, logger: this.logger });
233
+ this.prompts = new PromptClientActions({ client: this, logger: this.logger });
182
234
  }
183
235
  /**
184
236
  * Log a message at the specified level
@@ -362,6 +414,39 @@ var InternalMastraMCPClient = class extends MastraBase {
362
414
  timeout: this.timeout
363
415
  });
364
416
  }
417
+ /**
418
+ * Fetch the list of available prompts from the MCP server.
419
+ */
420
+ async listPrompts() {
421
+ this.log("debug", `Requesting prompts from MCP server`);
422
+ return await this.client.request({ method: "prompts/list" }, ListPromptsResultSchema, {
423
+ timeout: this.timeout
424
+ });
425
+ }
426
+ /**
427
+ * Get a prompt and its dynamic messages from the server.
428
+ * @param name The prompt name
429
+ * @param args Arguments for the prompt
430
+ * @param version (optional) The prompt version to retrieve
431
+ */
432
+ async getPrompt({ name, args, version }) {
433
+ this.log("debug", `Requesting prompt from MCP server: ${name}`);
434
+ return await this.client.request(
435
+ { method: "prompts/get", params: { name, arguments: args, version } },
436
+ GetPromptResultSchema,
437
+ { timeout: this.timeout }
438
+ );
439
+ }
440
+ /**
441
+ * Register a handler to be called when the prompt list changes on the server.
442
+ * Use this to refresh cached prompt lists in the client/UI if needed.
443
+ */
444
+ setPromptListChangedNotificationHandler(handler) {
445
+ this.log("debug", "Setting prompt list changed notification handler");
446
+ this.client.setNotificationHandler(PromptListChangedNotificationSchema, () => {
447
+ handler();
448
+ });
449
+ }
365
450
  setResourceUpdatedNotificationHandler(handler) {
366
451
  this.log("debug", "Setting resource updated notification handler");
367
452
  this.client.setNotificationHandler(ResourceUpdatedNotificationSchema, (notification) => {
@@ -551,6 +636,31 @@ To fix this you have three different options:
551
636
  }
552
637
  };
553
638
  }
639
+ get prompts() {
640
+ this.addToInstanceCache();
641
+ return {
642
+ list: async () => {
643
+ const allPrompts = {};
644
+ for (const serverName of Object.keys(this.serverConfigs)) {
645
+ try {
646
+ const internalClient = await this.getConnectedClientForServer(serverName);
647
+ allPrompts[serverName] = await internalClient.prompts.list();
648
+ } catch (error) {
649
+ this.logger.error(`Failed to list prompts from server ${serverName}`, { error });
650
+ }
651
+ }
652
+ return allPrompts;
653
+ },
654
+ get: async ({ serverName, name, args, version }) => {
655
+ const internalClient = await this.getConnectedClientForServer(serverName);
656
+ return internalClient.prompts.get({ name, args, version });
657
+ },
658
+ onListChanged: async (serverName, handler) => {
659
+ const internalClient = await this.getConnectedClientForServer(serverName);
660
+ return internalClient.prompts.onListChanged(handler);
661
+ }
662
+ };
663
+ }
554
664
  addToInstanceCache() {
555
665
  if (!mcpClientInstances.has(this.id)) {
556
666
  mcpClientInstances.set(this.id, this);
@@ -759,6 +869,34 @@ var SSETransport = class {
759
869
  }
760
870
  };
761
871
 
872
+ // src/server/promptActions.ts
873
+ var ServerPromptActions = class {
874
+ getLogger;
875
+ getSdkServer;
876
+ clearDefinedPrompts;
877
+ constructor(dependencies) {
878
+ this.getLogger = dependencies.getLogger;
879
+ this.getSdkServer = dependencies.getSdkServer;
880
+ this.clearDefinedPrompts = dependencies.clearDefinedPrompts;
881
+ }
882
+ /**
883
+ * Notifies the server that the overall list of available prompts has changed.
884
+ * This will clear the internal cache of defined prompts and send a list_changed notification to clients.
885
+ */
886
+ async notifyListChanged() {
887
+ this.getLogger().info("Prompt list change externally notified. Clearing definedPrompts and sending notification.");
888
+ this.clearDefinedPrompts();
889
+ try {
890
+ await this.getSdkServer().sendPromptListChanged();
891
+ } catch (error) {
892
+ this.getLogger().error("Failed to send prompt list changed notification:", {
893
+ error: error instanceof Error ? error.message : String(error)
894
+ });
895
+ throw error;
896
+ }
897
+ }
898
+ };
899
+
762
900
  // src/server/resourceActions.ts
763
901
  var ServerResourceActions = class {
764
902
  getSubscriptions;
@@ -823,11 +961,16 @@ var MCPServer = class extends MCPServerBase {
823
961
  listResourceTemplatesHandlerIsRegistered = false;
824
962
  subscribeResourceHandlerIsRegistered = false;
825
963
  unsubscribeResourceHandlerIsRegistered = false;
964
+ listPromptsHandlerIsRegistered = false;
965
+ getPromptHandlerIsRegistered = false;
826
966
  definedResources;
827
967
  definedResourceTemplates;
828
968
  resourceOptions;
969
+ definedPrompts;
970
+ promptOptions;
829
971
  subscriptions = /* @__PURE__ */ new Set();
830
972
  resources;
973
+ prompts;
831
974
  /**
832
975
  * Get the current stdio transport.
833
976
  */
@@ -865,6 +1008,7 @@ var MCPServer = class extends MCPServerBase {
865
1008
  constructor(opts) {
866
1009
  super(opts);
867
1010
  this.resourceOptions = opts.resources;
1011
+ this.promptOptions = opts.prompts;
868
1012
  const capabilities = {
869
1013
  tools: {},
870
1014
  logging: { enabled: true }
@@ -872,6 +1016,9 @@ var MCPServer = class extends MCPServerBase {
872
1016
  if (opts.resources) {
873
1017
  capabilities.resources = { subscribe: true, listChanged: true };
874
1018
  }
1019
+ if (opts.prompts) {
1020
+ capabilities.prompts = { listChanged: true };
1021
+ }
875
1022
  this.server = new Server({ name: this.name, version: this.version }, { capabilities });
876
1023
  this.logger.info(
877
1024
  `Initialized MCPServer '${this.name}' v${this.version} (ID: ${this.id}) with tools: ${Object.keys(this.convertedTools).join(", ")} and resources. Capabilities: ${JSON.stringify(capabilities)}`
@@ -888,6 +1035,12 @@ var MCPServer = class extends MCPServerBase {
888
1035
  this.registerListResourceTemplatesHandler();
889
1036
  }
890
1037
  }
1038
+ if (opts.prompts) {
1039
+ this.registerListPromptsHandler();
1040
+ this.registerGetPromptHandler({
1041
+ getPromptMessagesCallback: opts.prompts.getPromptMessages
1042
+ });
1043
+ }
891
1044
  this.resources = new ServerResourceActions({
892
1045
  getSubscriptions: () => this.subscriptions,
893
1046
  getLogger: () => this.logger,
@@ -899,6 +1052,13 @@ var MCPServer = class extends MCPServerBase {
899
1052
  this.definedResourceTemplates = void 0;
900
1053
  }
901
1054
  });
1055
+ this.prompts = new ServerPromptActions({
1056
+ getLogger: () => this.logger,
1057
+ getSdkServer: () => this.server,
1058
+ clearDefinedPrompts: () => {
1059
+ this.definedPrompts = void 0;
1060
+ }
1061
+ });
902
1062
  }
903
1063
  convertAgentsToTools(agentsConfig, definedConvertedTools) {
904
1064
  const agentTools = {};
@@ -1325,6 +1485,95 @@ var MCPServer = class extends MCPServerBase {
1325
1485
  return {};
1326
1486
  });
1327
1487
  }
1488
+ /**
1489
+ * Register the ListPrompts handler.
1490
+ */
1491
+ registerListPromptsHandler() {
1492
+ if (this.listPromptsHandlerIsRegistered) {
1493
+ return;
1494
+ }
1495
+ this.listPromptsHandlerIsRegistered = true;
1496
+ const capturedPromptOptions = this.promptOptions;
1497
+ if (!capturedPromptOptions?.listPrompts) {
1498
+ this.logger.warn("ListPrompts capability not supported by server configuration.");
1499
+ return;
1500
+ }
1501
+ this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
1502
+ this.logger.debug("Handling ListPrompts request");
1503
+ if (this.definedPrompts) {
1504
+ return {
1505
+ prompts: this.definedPrompts?.map((p) => ({ ...p, version: p.version ?? void 0 }))
1506
+ };
1507
+ } else {
1508
+ try {
1509
+ const prompts = await capturedPromptOptions.listPrompts();
1510
+ for (const prompt of prompts) {
1511
+ PromptSchema.parse(prompt);
1512
+ }
1513
+ this.definedPrompts = prompts;
1514
+ this.logger.debug(`Fetched and cached ${this.definedPrompts.length} prompts.`);
1515
+ return {
1516
+ prompts: this.definedPrompts?.map((p) => ({ ...p, version: p.version ?? void 0 }))
1517
+ };
1518
+ } catch (error) {
1519
+ this.logger.error("Error fetching prompts via listPrompts():", {
1520
+ error: error instanceof Error ? error.message : String(error)
1521
+ });
1522
+ throw error;
1523
+ }
1524
+ }
1525
+ });
1526
+ }
1527
+ /**
1528
+ * Register the GetPrompt handler.
1529
+ */
1530
+ registerGetPromptHandler({
1531
+ getPromptMessagesCallback
1532
+ }) {
1533
+ if (this.getPromptHandlerIsRegistered) return;
1534
+ this.getPromptHandlerIsRegistered = true;
1535
+ this.server.setRequestHandler(
1536
+ GetPromptRequestSchema,
1537
+ async (request) => {
1538
+ const startTime = Date.now();
1539
+ const { name, version, arguments: args } = request.params;
1540
+ if (!this.definedPrompts) {
1541
+ const prompts = await this.promptOptions?.listPrompts?.();
1542
+ if (!prompts) throw new Error("Failed to load prompts");
1543
+ this.definedPrompts = prompts;
1544
+ }
1545
+ let prompt;
1546
+ if (version) {
1547
+ prompt = this.definedPrompts?.find((p) => p.name === name && p.version === version);
1548
+ } else {
1549
+ prompt = this.definedPrompts?.find((p) => p.name === name);
1550
+ }
1551
+ if (!prompt) throw new Error(`Prompt "${name}"${version ? ` (version ${version})` : ""} not found`);
1552
+ if (prompt.arguments) {
1553
+ for (const arg of prompt.arguments) {
1554
+ if (arg.required && (args?.[arg.name] === void 0 || args?.[arg.name] === null)) {
1555
+ throw new Error(`Missing required argument: ${arg.name}`);
1556
+ }
1557
+ }
1558
+ }
1559
+ try {
1560
+ let messages = [];
1561
+ if (getPromptMessagesCallback) {
1562
+ messages = await getPromptMessagesCallback({ name, version, args });
1563
+ }
1564
+ const duration = Date.now() - startTime;
1565
+ this.logger.info(
1566
+ `Prompt '${name}'${version ? ` (version ${version})` : ""} retrieved successfully in ${duration}ms.`
1567
+ );
1568
+ return { prompt, messages };
1569
+ } catch (error) {
1570
+ const duration = Date.now() - startTime;
1571
+ this.logger.error(`Failed to get content for prompt '${name}' in ${duration}ms`, { error });
1572
+ throw error;
1573
+ }
1574
+ }
1575
+ );
1576
+ }
1328
1577
  /**
1329
1578
  * Start the MCP server using stdio transport (for Windsurf integration).
1330
1579
  */
@@ -10,9 +10,9 @@ case `uname` in
10
10
  esac
11
11
 
12
12
  if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@1.6.1_@edge-runtime+vm@3.2.0_@types+node@20.17.32_jsdom@26.0.0_bufferutil@4.0.9__b7b40f6481a5fb1015de024b8d25deb4/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@1.6.1_@edge-runtime+vm@3.2.0_@types+node@20.17.32_jsdom@26.0.0_bufferutil@4.0.9__b7b40f6481a5fb1015de024b8d25deb4/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules"
13
+ export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.2_@edge-runtime+vm@3.2.0_@types+debug@4.1.12_@types+node@20.19.0_@vitest+ui@_eb265836689cb09b255052147598b424/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.2_@edge-runtime+vm@3.2.0_@types+debug@4.1.12_@types+node@20.19.0_@vitest+ui@_eb265836689cb09b255052147598b424/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules"
14
14
  else
15
- export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@1.6.1_@edge-runtime+vm@3.2.0_@types+node@20.17.32_jsdom@26.0.0_bufferutil@4.0.9__b7b40f6481a5fb1015de024b8d25deb4/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@1.6.1_@edge-runtime+vm@3.2.0_@types+node@20.17.32_jsdom@26.0.0_bufferutil@4.0.9__b7b40f6481a5fb1015de024b8d25deb4/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules:$NODE_PATH"
15
+ export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.2_@edge-runtime+vm@3.2.0_@types+debug@4.1.12_@types+node@20.19.0_@vitest+ui@_eb265836689cb09b255052147598b424/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.2_@edge-runtime+vm@3.2.0_@types+debug@4.1.12_@types+node@20.19.0_@vitest+ui@_eb265836689cb09b255052147598b424/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules:$NODE_PATH"
16
16
  fi
17
17
  if [ -x "$basedir/node" ]; then
18
18
  exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
@@ -12,14 +12,14 @@
12
12
  "@mastra/client-js": "workspace:*",
13
13
  "@mastra/mcp": "workspace:*",
14
14
  "dotenv": "^16.5.0",
15
- "zod": "^3.24.3"
15
+ "zod": "^3.25.56"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@testing-library/react": "^16.2.0",
19
- "@types/node": "^20.17.27",
19
+ "@types/node": "^20.17.57",
20
20
  "mastra": "workspace:*",
21
21
  "typescript": "^5.8.2",
22
- "vitest": "^1.6.1",
22
+ "vitest": "^3.2.2",
23
23
  "@mastra/core": "workspace:*"
24
24
  },
25
25
  "peerDependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/mcp",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -40,18 +40,18 @@
40
40
  "ai": "4.3.16",
41
41
  "@hono/node-server": "^1.13.8",
42
42
  "@mendable/firecrawl-js": "^1.24.0",
43
- "@microsoft/api-extractor": "^7.52.5",
44
- "@types/node": "^20.17.27",
45
- "eslint": "^9.23.0",
43
+ "@microsoft/api-extractor": "^7.52.8",
44
+ "@types/node": "^20.17.57",
45
+ "eslint": "^9.28.0",
46
46
  "hono-mcp-server-sse-transport": "0.0.6",
47
- "tsup": "^8.4.0",
47
+ "tsup": "^8.5.0",
48
48
  "tsx": "^4.19.3",
49
49
  "typescript": "^5.8.2",
50
- "vitest": "^3.1.2",
51
- "zod": "^3.24.3",
50
+ "vitest": "^3.2.2",
51
+ "zod": "^3.25.56",
52
52
  "zod-to-json-schema": "^3.24.5",
53
- "@internal/lint": "0.0.8",
54
- "@mastra/core": "0.10.2"
53
+ "@internal/lint": "0.0.11",
54
+ "@mastra/core": "0.10.4"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",
@@ -1,10 +1,10 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'http';
2
2
  import { createServer } from 'http';
3
3
  import { createTool } from '@mastra/core';
4
- import type { Resource, ResourceTemplate } from '@modelcontextprotocol/sdk/types.js';
4
+ import type { Prompt, PromptMessage, Resource, ResourceTemplate } from '@modelcontextprotocol/sdk/types.js';
5
5
  import { z } from 'zod';
6
6
  import { MCPServer } from '../server/server';
7
- import type { MCPServerResources, MCPServerResourceContent } from '../server/server';
7
+ import type { MCPServerResources, MCPServerResourceContent, MCPServerPrompts } from '../server/types';
8
8
 
9
9
  const getWeather = async (location: string) => {
10
10
  // Return mock data for testing
@@ -119,6 +119,36 @@ const weatherResourceContents: Record<string, MCPServerResourceContent> = {
119
119
  },
120
120
  };
121
121
 
122
+ const weatherPrompts: Prompt[] = [
123
+ {
124
+ name: 'current',
125
+ version: 'v1',
126
+ description: 'Get current weather for a location',
127
+ mimeType: 'application/json',
128
+ content: JSON.stringify({
129
+ location: 'Current weather for San Francisco',
130
+ }),
131
+ },
132
+ {
133
+ name: 'forecast',
134
+ version: 'v1',
135
+ description: 'Get weather forecast for a location',
136
+ mimeType: 'application/json',
137
+ content: JSON.stringify({
138
+ location: 'Forecast for San Francisco',
139
+ }),
140
+ },
141
+ {
142
+ name: 'historical',
143
+ version: 'v1',
144
+ description: 'Get historical weather data for a location',
145
+ mimeType: 'application/json',
146
+ content: JSON.stringify({
147
+ location: 'Historical weather for San Francisco',
148
+ }),
149
+ },
150
+ ];
151
+
122
152
  const mcpServerResources: MCPServerResources = {
123
153
  listResources: async () => weatherResourceDefinitions,
124
154
  getResourceContent: async ({ uri }: { uri: string }) => {
@@ -130,6 +160,25 @@ const mcpServerResources: MCPServerResources = {
130
160
  resourceTemplates: async () => weatherResourceTemplatesDefinitions,
131
161
  };
132
162
 
163
+ const mcpServerPrompts: MCPServerPrompts = {
164
+ listPrompts: async () => weatherPrompts,
165
+ getPromptMessages: async ({ name }: { name: string }): Promise<PromptMessage[]> => {
166
+ const prompt = weatherPrompts.find(p => p.name === name);
167
+ if (!prompt) {
168
+ throw new Error(`Mock prompt not found for ${name}`);
169
+ }
170
+ return [
171
+ {
172
+ role: 'user',
173
+ content: {
174
+ type: 'text',
175
+ text: prompt.content as string,
176
+ },
177
+ },
178
+ ];
179
+ },
180
+ };
181
+
133
182
  const mcpServer = new MCPServer({
134
183
  name: serverId,
135
184
  version: '1.0.0',
@@ -137,6 +186,7 @@ const mcpServer = new MCPServer({
137
186
  getWeather: weatherToolDefinition,
138
187
  },
139
188
  resources: mcpServerResources,
189
+ prompts: mcpServerPrompts,
140
190
  });
141
191
 
142
192
  const httpServer = createServer(async (req: IncomingMessage, res: ServerResponse) => {
@@ -193,12 +243,22 @@ const notificationInterval = setInterval(async () => {
193
243
  }
194
244
  }
195
245
  }, NOTIFICATION_INTERVAL_MS);
246
+
247
+ const promptNotificationInterval = setInterval(async () => {
248
+ const listChangePrefix = `[${serverId}] IntervalListChange`;
249
+ try {
250
+ await mcpServer.prompts.notifyListChanged();
251
+ } catch (e: any) {
252
+ console.error(`${listChangePrefix} - Error sending promptListChanged via MCPServer: ${e.message}`);
253
+ }
254
+ }, NOTIFICATION_INTERVAL_MS);
196
255
  // --- End Interval-based Notifications ---
197
256
 
198
257
  // Handle graceful shutdown
199
258
  process.on('SIGINT', async () => {
200
259
  console.log('Shutting down weather server...');
201
260
  clearInterval(notificationInterval); // Clear the interval
261
+ clearInterval(promptNotificationInterval); // Clear the interval
202
262
  await mcpServer.close();
203
263
  httpServer.close(() => {
204
264
  console.log('Weather server shut down complete');
@@ -19,6 +19,7 @@ async function setupTestServer(withSessionManagement: boolean) {
19
19
  logging: {},
20
20
  tools: {},
21
21
  resources: {},
22
+ prompts: {},
22
23
  },
23
24
  },
24
25
  );
@@ -47,6 +48,27 @@ async function setupTestServer(withSessionManagement: boolean) {
47
48
  };
48
49
  });
49
50
 
51
+ mcpServer.prompt(
52
+ 'greet',
53
+ 'A simple greeting prompt',
54
+ () => {
55
+ return {
56
+ prompt: {
57
+ name: 'greet',
58
+ version: 'v1',
59
+ description: 'A simple greeting prompt',
60
+ mimeType: 'application/json',
61
+ },
62
+ messages: [
63
+ {
64
+ role: 'assistant',
65
+ content: { type: 'text', text: `Hello, World!` }
66
+ }
67
+ ]
68
+ };
69
+ },
70
+ );
71
+
50
72
  const serverTransport = new StreamableHTTPServerTransport({
51
73
  sessionIdGenerator: withSessionManagement ? () => randomUUID() : undefined,
52
74
  });
@@ -121,6 +143,30 @@ describe('MastraMCPClient with Streamable HTTP', () => {
121
143
  expect(readResult.contents.length).toBe(1);
122
144
  expect(readResult.contents[0].text).toBe('Hello, world!');
123
145
  });
146
+
147
+ it('should list prompts', async () => {
148
+ const {prompts} = await client.listPrompts();
149
+ expect(prompts).toBeInstanceOf(Array);
150
+ expect(prompts).toHaveLength(1);
151
+ expect(prompts[0]).toHaveProperty('name');
152
+ expect(prompts[0]).toHaveProperty('description');
153
+ expect(prompts[0].description).toBe('A simple greeting prompt');
154
+ });
155
+
156
+ it('should get a specific prompt', async () => {
157
+ const result = await client.getPrompt({name: 'greet'});
158
+ const {prompt, messages} = result;
159
+ expect(prompt).toBeDefined();
160
+ expect(prompt).toMatchObject({
161
+ name: 'greet',
162
+ version: 'v1',
163
+ description: expect.any(String),
164
+ mimeType: 'application/json',
165
+ });
166
+ expect(messages).toBeDefined();
167
+ const messageItem = messages[0];
168
+ expect(messageItem.content.text).toBe('Hello, World!');
169
+ });
124
170
  });
125
171
 
126
172
  describe('Stateful Mode', () => {