@mastra/mcp 0.10.5-alpha.0 → 0.10.5-alpha.2

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.
@@ -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@3.2.3_@edge-runtime+vm@3.2.0_@types+debug@4.1.12_@types+node@20.19.0_@vitest+ui@_3e45f0297eeb1f6a4ee30770ed0f557b/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.3_@edge-runtime+vm@3.2.0_@types+debug@4.1.12_@types+node@20.19.0_@vitest+ui@_3e45f0297eeb1f6a4ee30770ed0f557b/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.4_@types+debug@4.1.12_@types+node@20.19.1_@vitest+ui@3.2.3_jiti@2.4.2_jsdom@_9ed2428c73777463a3d92e2c0ddae976/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.4_@types+debug@4.1.12_@types+node@20.19.1_@vitest+ui@3.2.3_jiti@2.4.2_jsdom@_9ed2428c73777463a3d92e2c0ddae976/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@3.2.3_@edge-runtime+vm@3.2.0_@types+debug@4.1.12_@types+node@20.19.0_@vitest+ui@_3e45f0297eeb1f6a4ee30770ed0f557b/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.3_@edge-runtime+vm@3.2.0_@types+debug@4.1.12_@types+node@20.19.0_@vitest+ui@_3e45f0297eeb1f6a4ee30770ed0f557b/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.4_@types+debug@4.1.12_@types+node@20.19.1_@vitest+ui@3.2.3_jiti@2.4.2_jsdom@_9ed2428c73777463a3d92e2c0ddae976/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.4_@types+debug@4.1.12_@types+node@20.19.1_@vitest+ui@3.2.3_jiti@2.4.2_jsdom@_9ed2428c73777463a3d92e2c0ddae976/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,11 +12,11 @@
12
12
  "@mastra/client-js": "workspace:*",
13
13
  "@mastra/mcp": "workspace:*",
14
14
  "dotenv": "^16.5.0",
15
- "zod": "^3.25.56"
15
+ "zod": "^3.25.67"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@mastra/core": "workspace:*",
19
- "@testing-library/react": "^16.2.0",
19
+ "@testing-library/react": "^16.3.0",
20
20
  "@types/node": "^20.17.57",
21
21
  "get-port": "^7.1.0",
22
22
  "mastra": "workspace:*",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/mcp",
3
- "version": "0.10.5-alpha.0",
3
+ "version": "0.10.5-alpha.2",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,11 +22,10 @@
22
22
  "author": "",
23
23
  "license": "Elastic-2.0",
24
24
  "dependencies": {
25
- "@modelcontextprotocol/sdk": "^1.12.1",
25
+ "@modelcontextprotocol/sdk": "^1.13.0",
26
26
  "date-fns": "^4.1.0",
27
27
  "exit-hook": "^4.0.0",
28
28
  "fast-deep-equal": "^3.1.3",
29
- "hono": "^4.7.11",
30
29
  "uuid": "^11.1.0",
31
30
  "zod-from-json-schema": "^0.0.5"
32
31
  },
@@ -42,16 +41,17 @@
42
41
  "@microsoft/api-extractor": "^7.52.8",
43
42
  "@types/node": "^20.19.0",
44
43
  "ai": "4.3.16",
45
- "eslint": "^9.28.0",
46
- "hono-mcp-server-sse-transport": "0.0.6",
44
+ "eslint": "^9.29.0",
45
+ "hono-mcp-server-sse-transport": "0.0.7",
46
+ "hono": "^4.7.11",
47
47
  "tsup": "^8.5.0",
48
48
  "tsx": "^4.19.4",
49
49
  "typescript": "^5.8.3",
50
50
  "vitest": "^3.2.3",
51
- "zod": "^3.25.57",
51
+ "zod": "^3.25.67",
52
52
  "zod-to-json-schema": "^3.24.5",
53
53
  "@internal/lint": "0.0.13",
54
- "@mastra/core": "0.10.7-alpha.1"
54
+ "@mastra/core": "0.10.7-alpha.4"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",
@@ -26,15 +26,6 @@ export const weatherTool = createTool({
26
26
  inputSchema: z.object({
27
27
  location: z.string().describe('City name'),
28
28
  }),
29
- outputSchema: z.object({
30
- temperature: z.number(),
31
- feelsLike: z.number(),
32
- humidity: z.number(),
33
- windSpeed: z.number(),
34
- windGust: z.number(),
35
- conditions: z.string(),
36
- location: z.string(),
37
- }),
38
29
  execute: async ({ context }) => {
39
30
  console.log('weather tool', context);
40
31
  return await getWeather(context.location);
@@ -5,7 +5,7 @@ import type { AddressInfo } from 'node:net';
5
5
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
6
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
7
7
  import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
8
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
9
9
  import { z } from 'zod';
10
10
 
11
11
  import { InternalMastraMCPClient } from './client.js';
@@ -208,3 +208,312 @@ describe('MastraMCPClient with Streamable HTTP', () => {
208
208
  });
209
209
  });
210
210
  });
211
+
212
+ describe('MastraMCPClient - Elicitation Tests', () => {
213
+ let testServer: {
214
+ httpServer: HttpServer;
215
+ mcpServer: McpServer;
216
+ serverTransport: StreamableHTTPServerTransport;
217
+ baseUrl: URL;
218
+ };
219
+ let client: InternalMastraMCPClient;
220
+
221
+ beforeEach(async () => {
222
+ testServer = await setupTestServer(false);
223
+
224
+ // Add elicitation-enabled tools to the test server
225
+ testServer.mcpServer.tool(
226
+ 'collectUserInfo',
227
+ 'Collects user information through elicitation',
228
+ {
229
+ message: z.string().describe('Message to show to user').default('Please provide your information'),
230
+ },
231
+ async ({ message }): Promise<CallToolResult> => {
232
+ const result = await testServer.mcpServer.server.elicitInput({
233
+ message: message,
234
+ requestedSchema: {
235
+ type: 'object',
236
+ properties: {
237
+ name: { type: 'string', title: 'Name' },
238
+ email: { type: 'string', title: 'Email', format: 'email' },
239
+ },
240
+ required: ['name'],
241
+ },
242
+ });
243
+
244
+ return {
245
+ content: [{ type: 'text', text: JSON.stringify(result) }],
246
+ };
247
+ },
248
+ );
249
+
250
+ testServer.mcpServer.tool(
251
+ 'collectSensitiveInfo',
252
+ 'Collects sensitive information that might be rejected',
253
+ {
254
+ message: z.string().describe('Message to show to user').default('Please provide sensitive information'),
255
+ },
256
+ async ({ message }): Promise<CallToolResult> => {
257
+ const result = await testServer.mcpServer.server.elicitInput({
258
+ message: message,
259
+ requestedSchema: {
260
+ type: 'object',
261
+ properties: {
262
+ ssn: { type: 'string', title: 'Social Security Number' },
263
+ creditCard: { type: 'string', title: 'Credit Card Number' },
264
+ },
265
+ required: ['ssn'],
266
+ },
267
+ });
268
+
269
+ return {
270
+ content: [{ type: 'text', text: JSON.stringify(result) }],
271
+ };
272
+ },
273
+ );
274
+
275
+ testServer.mcpServer.tool(
276
+ 'collectOptionalInfo',
277
+ 'Collects optional information that might be cancelled',
278
+ {
279
+ message: z.string().describe('Message to show to user').default('Optional information request'),
280
+ },
281
+ async ({ message }): Promise<CallToolResult> => {
282
+ const result = await testServer.mcpServer.server.elicitInput({
283
+ message: message,
284
+ requestedSchema: {
285
+ type: 'object',
286
+ properties: {
287
+ feedback: { type: 'string', title: 'Feedback' },
288
+ rating: { type: 'number', title: 'Rating', minimum: 1, maximum: 5 },
289
+ },
290
+ },
291
+ });
292
+
293
+ return {
294
+ content: [{ type: 'text', text: JSON.stringify(result) }],
295
+ };
296
+ },
297
+ );
298
+ });
299
+
300
+ afterEach(async () => {
301
+ await client?.disconnect().catch(() => {});
302
+ await testServer?.mcpServer.close().catch(() => {});
303
+ await testServer?.serverTransport.close().catch(() => {});
304
+ testServer?.httpServer.close();
305
+ });
306
+
307
+ it('should handle elicitation request with accept response', async () => {
308
+ const mockHandler = vi.fn(async (request) => {
309
+ expect(request.message).toBe('Please provide your information');
310
+ expect(request.requestedSchema).toBeDefined();
311
+ expect(request.requestedSchema.properties.name).toBeDefined();
312
+ expect(request.requestedSchema.properties.email).toBeDefined();
313
+
314
+ return {
315
+ action: 'accept' as const,
316
+ content: {
317
+ name: 'John Doe',
318
+ email: 'john@example.com',
319
+ },
320
+ };
321
+ });
322
+
323
+ client = new InternalMastraMCPClient({
324
+ name: 'elicitation-accept-client',
325
+ server: {
326
+ url: testServer.baseUrl,
327
+ },
328
+ });
329
+ client.elicitation.onRequest(mockHandler);
330
+ await client.connect();
331
+
332
+ // Get the tools and call the elicitation tool
333
+ const tools = await client.tools();
334
+ const collectUserInfoTool = tools['collectUserInfo'];
335
+ expect(collectUserInfoTool).toBeDefined();
336
+
337
+ // Call the tool which will trigger elicitation
338
+ const result = await collectUserInfoTool.execute({
339
+ context: { message: 'Please provide your information' }
340
+ });
341
+
342
+ console.log('result', result);
343
+
344
+ expect(mockHandler).toHaveBeenCalledTimes(1);
345
+ expect(result.content).toBeDefined();
346
+ expect(result.content[0].type).toBe('text');
347
+
348
+ const elicitationResult = JSON.parse(result.content[0].text);
349
+ expect(elicitationResult.action).toBe('accept');
350
+ expect(elicitationResult.content).toEqual({
351
+ name: 'John Doe',
352
+ email: 'john@example.com',
353
+ });
354
+ });
355
+
356
+ it('should handle elicitation request with reject response', async () => {
357
+ const mockHandler = vi.fn(async (request) => {
358
+ expect(request.message).toBe('Please provide sensitive information');
359
+ return { action: 'reject' as const };
360
+ });
361
+
362
+ client = new InternalMastraMCPClient({
363
+ name: 'elicitation-reject-client',
364
+ server: {
365
+ url: testServer.baseUrl,
366
+ },
367
+ });
368
+ client.elicitation.onRequest(mockHandler);
369
+ await client.connect();
370
+
371
+ // Get the tools and call the sensitive info tool
372
+ const tools = await client.tools();
373
+ const collectSensitiveInfoTool = tools['collectSensitiveInfo'];
374
+ expect(collectSensitiveInfoTool).toBeDefined();
375
+
376
+ // Call the tool which will trigger elicitation
377
+ const result = await collectSensitiveInfoTool.execute({
378
+ context: { message: 'Please provide sensitive information' }
379
+ });
380
+
381
+ expect(mockHandler).toHaveBeenCalledTimes(1);
382
+ expect(result.content).toBeDefined();
383
+ expect(result.content[0].type).toBe('text');
384
+
385
+ const elicitationResult = JSON.parse(result.content[0].text);
386
+ expect(elicitationResult.action).toBe('reject');
387
+ });
388
+
389
+ it('should handle elicitation request with cancel response', async () => {
390
+ const mockHandler = vi.fn(async (_request) => {
391
+ return { action: 'cancel' as const };
392
+ });
393
+
394
+ client = new InternalMastraMCPClient({
395
+ name: 'elicitation-cancel-client',
396
+ server: {
397
+ url: testServer.baseUrl,
398
+ },
399
+ });
400
+ client.elicitation.onRequest(mockHandler);
401
+ await client.connect();
402
+
403
+ // Get the tools and call the optional info tool
404
+ const tools = await client.tools();
405
+ const collectOptionalInfoTool = tools['collectOptionalInfo'];
406
+ expect(collectOptionalInfoTool).toBeDefined();
407
+
408
+ // Call the tool which will trigger elicitation
409
+ const result = await collectOptionalInfoTool.execute({
410
+ context: { message: 'Optional information request' }
411
+ });
412
+
413
+ expect(mockHandler).toHaveBeenCalledTimes(1);
414
+ expect(result.content).toBeDefined();
415
+ expect(result.content[0].type).toBe('text');
416
+
417
+ const elicitationResult = JSON.parse(result.content[0].text);
418
+ expect(elicitationResult.action).toBe('cancel');
419
+ });
420
+
421
+ it('should return an error when elicitation handler throws error', async () => {
422
+ const mockHandler = vi.fn(async (_request) => {
423
+ throw new Error('Handler failed');
424
+ });
425
+
426
+ client = new InternalMastraMCPClient({
427
+ name: 'elicitation-error-client',
428
+ server: {
429
+ url: testServer.baseUrl,
430
+ },
431
+ });
432
+ client.elicitation.onRequest(mockHandler);
433
+ await client.connect();
434
+
435
+ // Get the tools and call a tool that will trigger elicitation
436
+ const tools = await client.tools();
437
+ const collectUserInfoTool = tools['collectUserInfo'];
438
+ expect(collectUserInfoTool).toBeDefined();
439
+
440
+ // Call the tool which will trigger elicitation, handler will throw error
441
+ const result = await collectUserInfoTool.execute({
442
+ context: { message: 'This will cause handler to throw' }
443
+ });
444
+
445
+ expect(mockHandler).toHaveBeenCalledTimes(1);
446
+ expect(result.content).toBeDefined();
447
+
448
+ expect(result.isError).toBe(true);
449
+ });
450
+
451
+ it('should return an error when client has no elicitation handler', async () => {
452
+ client = new InternalMastraMCPClient({
453
+ name: 'no-elicitation-client',
454
+ server: {
455
+ url: testServer.baseUrl,
456
+ // No elicitationHandler provided
457
+ },
458
+ });
459
+ await client.connect();
460
+
461
+ // Get the tools and call a tool that will trigger elicitation
462
+ const tools = await client.tools();
463
+ const collectUserInfoTool = tools['collectUserInfo'];
464
+ expect(collectUserInfoTool).toBeDefined();
465
+
466
+ // Call the tool which will trigger elicitation, should fail gracefully
467
+ const result = await collectUserInfoTool.execute({
468
+ context: { message: 'This should fail gracefully' }
469
+ });
470
+
471
+ expect(result.content).toBeDefined();
472
+ expect(result.isError).toBe(true);
473
+ });
474
+
475
+ it('should validate elicitation request schema structure', async () => {
476
+ const mockHandler = vi.fn(async (request) => {
477
+ // Verify the request has the expected structure
478
+ expect(request).toHaveProperty('message');
479
+ expect(request).toHaveProperty('requestedSchema');
480
+ expect(typeof request.message).toBe('string');
481
+ expect(typeof request.requestedSchema).toBe('object');
482
+ expect(request.requestedSchema).toHaveProperty('type', 'object');
483
+ expect(request.requestedSchema).toHaveProperty('properties');
484
+
485
+ return {
486
+ action: 'accept' as const,
487
+ content: { validated: true },
488
+ };
489
+ });
490
+
491
+ client = new InternalMastraMCPClient({
492
+ name: 'schema-validation-client',
493
+ server: {
494
+ url: testServer.baseUrl,
495
+ },
496
+ });
497
+ client.elicitation.onRequest(mockHandler);
498
+ await client.connect();
499
+
500
+ // Get the tools and call a tool that will trigger elicitation
501
+ const tools = await client.tools();
502
+ const collectUserInfoTool = tools['collectUserInfo'];
503
+ expect(collectUserInfoTool).toBeDefined();
504
+
505
+ // Call the tool which will trigger elicitation with schema validation
506
+ const result = await collectUserInfoTool.execute({
507
+ context: { message: 'Schema validation test' }
508
+ });
509
+
510
+ console.log('result', result);
511
+
512
+ expect(mockHandler).toHaveBeenCalledTimes(1);
513
+ expect(result.content).toBeDefined();
514
+ expect(result.content[0].type).toBe('text');
515
+
516
+ const elicitationResultText = result.content[0].text;
517
+ expect(elicitationResultText).toContain('Elicitation response content does not match requested schema');
518
+ });
519
+ });
@@ -1,6 +1,7 @@
1
1
  import { MastraBase } from '@mastra/core/base';
2
2
 
3
3
  import type { RuntimeContext } from '@mastra/core/di';
4
+ import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
4
5
  import { createTool } from '@mastra/core/tools';
5
6
  import { isZodType } from '@mastra/core/utils';
6
7
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
@@ -13,6 +14,8 @@ import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/p
13
14
  import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
14
15
  import type {
15
16
  ClientCapabilities,
17
+ ElicitRequest,
18
+ ElicitResult,
16
19
  GetPromptResult,
17
20
  ListPromptsResult,
18
21
  LoggingLevel,
@@ -27,12 +30,14 @@ import {
27
30
  ListPromptsResultSchema,
28
31
  GetPromptResultSchema,
29
32
  PromptListChangedNotificationSchema,
33
+ ElicitRequestSchema,
30
34
  } from '@modelcontextprotocol/sdk/types.js';
31
35
 
32
36
  import { asyncExitHook, gracefulExit } from 'exit-hook';
33
37
  import { z } from 'zod';
34
38
  import { convertJsonSchemaToZod } from 'zod-from-json-schema';
35
39
  import type { JSONSchema } from 'zod-from-json-schema';
40
+ import { ElicitationClientActions } from './elicitationActions';
36
41
  import { PromptClientActions } from './promptActions';
37
42
  import { ResourceClientActions } from './resourceActions';
38
43
 
@@ -50,6 +55,9 @@ export interface LogMessage {
50
55
 
51
56
  export type LogHandler = (logMessage: LogMessage) => void;
52
57
 
58
+ // Elicitation handler type
59
+ export type ElicitationHandler = (request: ElicitRequest['params']) => Promise<ElicitResult>;
60
+
53
61
  // Base options common to all server definitions
54
62
  type BaseServerOptions = {
55
63
  logger?: LogHandler;
@@ -129,7 +137,7 @@ export class InternalMastraMCPClient extends MastraBase {
129
137
  private currentOperationContext: RuntimeContext | null = null;
130
138
  public readonly resources: ResourceClientActions;
131
139
  public readonly prompts: PromptClientActions;
132
-
140
+ public readonly elicitation: ElicitationClientActions;
133
141
  constructor({
134
142
  name,
135
143
  version = '1.0.0',
@@ -144,21 +152,25 @@ export class InternalMastraMCPClient extends MastraBase {
144
152
  this.enableServerLogs = server.enableServerLogs ?? true;
145
153
  this.serverConfig = server;
146
154
 
155
+ const clientCapabilities = { ...capabilities, elicitation: {} };
156
+
147
157
  this.client = new Client(
148
158
  {
149
159
  name,
150
160
  version,
151
161
  },
152
162
  {
153
- capabilities,
163
+ capabilities: clientCapabilities,
154
164
  },
155
165
  );
156
166
 
157
167
  // Set up log message capturing
158
168
  this.setupLogging();
159
169
 
170
+
160
171
  this.resources = new ResourceClientActions({ client: this, logger: this.logger });
161
172
  this.prompts = new PromptClientActions({ client: this, logger: this.logger });
173
+ this.elicitation = new ElicitationClientActions({ client: this, logger: this.logger });
162
174
  }
163
175
 
164
176
  /**
@@ -449,6 +461,14 @@ export class InternalMastraMCPClient extends MastraBase {
449
461
  });
450
462
  }
451
463
 
464
+ setElicitationRequestHandler(handler: ElicitationHandler): void {
465
+ this.log('debug', 'Setting elicitation request handler');
466
+ this.client.setRequestHandler(ElicitRequestSchema, async (request) => {
467
+ this.log('debug', `Received elicitation request: ${request.params.message}`);
468
+ return handler(request.params);
469
+ });
470
+ }
471
+
452
472
  private convertInputSchema(
453
473
  inputSchema: Awaited<ReturnType<Client['listTools']>>['tools'][0]['inputSchema'] | JSONSchema,
454
474
  ): z.ZodType {
@@ -475,7 +495,48 @@ export class InternalMastraMCPClient extends MastraBase {
475
495
  originalJsonSchema: inputSchema,
476
496
  });
477
497
 
478
- throw new Error(errorDetails);
498
+ throw new MastraError({
499
+ id: 'MCP_TOOL_INPUT_SCHEMA_CONVERSION_FAILED',
500
+ domain: ErrorDomain.MCP,
501
+ category: ErrorCategory.USER,
502
+ details: { error: errorDetails ?? 'Unknown error' },
503
+ });
504
+ }
505
+ }
506
+
507
+ private convertOutputSchema(
508
+ outputSchema: Awaited<ReturnType<Client['listTools']>>['tools'][0]['outputSchema'] | JSONSchema,
509
+ ): z.ZodType | undefined {
510
+ if (!outputSchema) return
511
+ if (isZodType(outputSchema)) {
512
+ return outputSchema;
513
+ }
514
+
515
+ try {
516
+ return convertJsonSchemaToZod(outputSchema as JSONSchema);
517
+ } catch (error: unknown) {
518
+ let errorDetails: string | undefined;
519
+ if (error instanceof Error) {
520
+ errorDetails = error.stack;
521
+ } else {
522
+ // Attempt to stringify, fallback to String()
523
+ try {
524
+ errorDetails = JSON.stringify(error);
525
+ } catch {
526
+ errorDetails = String(error);
527
+ }
528
+ }
529
+ this.log('error', 'Failed to convert JSON schema to Zod schema using zodFromJsonSchema', {
530
+ error: errorDetails,
531
+ originalJsonSchema: outputSchema,
532
+ });
533
+
534
+ throw new MastraError({
535
+ id: 'MCP_TOOL_OUTPUT_SCHEMA_CONVERSION_FAILED',
536
+ domain: ErrorDomain.MCP,
537
+ category: ErrorCategory.USER,
538
+ details: { error: errorDetails ?? 'Unknown error' },
539
+ });
479
540
  }
480
541
  }
481
542
 
@@ -490,6 +551,7 @@ export class InternalMastraMCPClient extends MastraBase {
490
551
  id: `${this.name}_${tool.name}`,
491
552
  description: tool.description || '',
492
553
  inputSchema: this.convertInputSchema(tool.inputSchema),
554
+ outputSchema: this.convertOutputSchema(tool.outputSchema),
493
555
  execute: async ({ context, runtimeContext }: { context: any; runtimeContext?: RuntimeContext | null }) => {
494
556
  const previousContext = this.currentOperationContext;
495
557
  this.currentOperationContext = runtimeContext || null; // Set current context
@@ -505,6 +567,7 @@ export class InternalMastraMCPClient extends MastraBase {
505
567
  timeout: this.timeout,
506
568
  },
507
569
  );
570
+
508
571
  this.log('debug', `Tool executed successfully: ${tool.name}`);
509
572
  return res;
510
573
  } catch (e) {
@@ -1,7 +1,7 @@
1
1
  import { MastraBase } from '@mastra/core/base';
2
2
  import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
3
3
  import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
4
- import type { Prompt, Resource, ResourceTemplate } from '@modelcontextprotocol/sdk/types.js';
4
+ import type { ElicitRequest, ElicitResult, Prompt, Resource, ResourceTemplate } from '@modelcontextprotocol/sdk/types.js';
5
5
  import equal from 'fast-deep-equal';
6
6
  import { v5 as uuidv5 } from 'uuid';
7
7
  import { InternalMastraMCPClient } from './client';
@@ -64,6 +64,26 @@ To fix this you have three different options:
64
64
  this.addToInstanceCache();
65
65
  return this;
66
66
  }
67
+ public get elicitation() {
68
+ this.addToInstanceCache();
69
+ return {
70
+ onRequest: async (serverName: string, handler: (request: ElicitRequest['params']) => Promise<ElicitResult>) => {
71
+ try {
72
+ const internalClient = await this.getConnectedClientForServer(serverName);
73
+ return internalClient.elicitation.onRequest(handler);
74
+ } catch (err) {
75
+ throw new MastraError({
76
+ id: 'MCP_CLIENT_ON_REQUEST_ELICITATION_FAILED',
77
+ domain: ErrorDomain.MCP,
78
+ category: ErrorCategory.THIRD_PARTY,
79
+ details: {
80
+ serverName,
81
+ }
82
+ }, err);
83
+ }
84
+ }
85
+ }
86
+ }
67
87
 
68
88
  public get resources() {
69
89
  this.addToInstanceCache();
@@ -356,7 +376,7 @@ To fix this you have three different options:
356
376
  const existingClient = this.mcpClientsById.get(name);
357
377
 
358
378
  this.logger.debug(`getConnectedClient ${name} exists: ${exists}`);
359
-
379
+
360
380
  if (exists) {
361
381
  // This is just to satisfy Typescript since technically you could have this.mcpClientsById.set('someKey', undefined);
362
382
  // Should never reach this point basically we always create a new MastraMCPClient instance when we add to the Map.
@@ -0,0 +1,26 @@
1
+ import type { IMastraLogger } from "@mastra/core/logger";
2
+ import type { ElicitRequest, ElicitResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import type { InternalMastraMCPClient } from "./client";
4
+
5
+ interface ElicitationClientActionsConfig {
6
+ client: InternalMastraMCPClient;
7
+ logger: IMastraLogger;
8
+ }
9
+
10
+ export class ElicitationClientActions {
11
+ private readonly client: InternalMastraMCPClient;
12
+ private readonly logger: IMastraLogger;
13
+
14
+ constructor({ client, logger }: ElicitationClientActionsConfig) {
15
+ this.client = client;
16
+ this.logger = logger;
17
+ }
18
+
19
+ /**
20
+ * Set a handler for elicitation requests.
21
+ * @param handler The callback function to handle the elicitation request.
22
+ */
23
+ public onRequest(handler: (request: ElicitRequest['params']) => Promise<ElicitResult>): void {
24
+ this.client.setElicitationRequestHandler(handler);
25
+ }
26
+ }
@@ -1,3 +1,3 @@
1
- export type { LoggingLevel, LogMessage, LogHandler, MastraMCPServerDefinition } from './client';
1
+ export type { LoggingLevel, LogMessage, LogHandler, MastraMCPServerDefinition, ElicitationHandler } from './client';
2
2
  export { MastraMCPClient } from './client';
3
3
  export * from './configuration';