@mastra/mcp 1.0.1 → 1.0.2-alpha.0

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.
@@ -60,7 +60,7 @@ Each server in the `servers` map is configured using the `MastraMCPServerDefinit
60
60
  Retrieves all tools from all configured servers, with tool names namespaced by their server name (in the format `serverName_toolName`) to prevent conflicts. Intended to be passed onto an Agent definition.
61
61
 
62
62
  ```ts
63
- new Agent({ id: "agent", tools: await mcp.listTools() });
63
+ new Agent({ id: 'agent', tools: await mcp.listTools() })
64
64
  ```
65
65
 
66
66
  ### listToolsets()
@@ -70,7 +70,7 @@ Returns an object mapping namespaced tool names (in the format `serverName.toolN
70
70
  ```typescript
71
71
  const res = await agent.stream(prompt, {
72
72
  toolsets: await mcp.listToolsets(),
73
- });
73
+ })
74
74
  ```
75
75
 
76
76
  ### disconnect()
@@ -88,11 +88,11 @@ The `MCPClient` instance has a `resources` property that provides access to reso
88
88
  ```typescript
89
89
  const mcpClient = new MCPClient({
90
90
  /* ...servers configuration... */
91
- });
91
+ })
92
92
 
93
93
  // Access resource methods via mcpClient.resources
94
- const allResourcesByServer = await mcpClient.resources.list();
95
- const templatesByServer = await mcpClient.resources.templates();
94
+ const allResourcesByServer = await mcpClient.resources.list()
95
+ const templatesByServer = await mcpClient.resources.templates()
96
96
  // ... and so on for other resource methods.
97
97
  ```
98
98
 
@@ -107,9 +107,9 @@ async list(): Promise<Record<string, Resource[]>>
107
107
  Example:
108
108
 
109
109
  ```typescript
110
- const resourcesByServer = await mcpClient.resources.list();
110
+ const resourcesByServer = await mcpClient.resources.list()
111
111
  for (const serverName in resourcesByServer) {
112
- console.log(`Resources from ${serverName}:`, resourcesByServer[serverName]);
112
+ console.log(`Resources from ${serverName}:`, resourcesByServer[serverName])
113
113
  }
114
114
  ```
115
115
 
@@ -124,9 +124,9 @@ async templates(): Promise<Record<string, ResourceTemplate[]>>
124
124
  Example:
125
125
 
126
126
  ```typescript
127
- const templatesByServer = await mcpClient.resources.templates();
127
+ const templatesByServer = await mcpClient.resources.templates()
128
128
  for (const serverName in templatesByServer) {
129
- console.log(`Templates from ${serverName}:`, templatesByServer[serverName]);
129
+ console.log(`Templates from ${serverName}:`, templatesByServer[serverName])
130
130
  }
131
131
  ```
132
132
 
@@ -144,11 +144,8 @@ async read(serverName: string, uri: string): Promise<ReadResourceResult>
144
144
  Example:
145
145
 
146
146
  ```typescript
147
- const content = await mcpClient.resources.read(
148
- "myWeatherServer",
149
- "weather://current",
150
- );
151
- console.log("Current weather:", content.contents[0].text);
147
+ const content = await mcpClient.resources.read('myWeatherServer', 'weather://current')
148
+ console.log('Current weather:', content.contents[0].text)
152
149
  ```
153
150
 
154
151
  #### `resources.subscribe(serverName: string, uri: string)`
@@ -162,7 +159,7 @@ async subscribe(serverName: string, uri: string): Promise<object>
162
159
  Example:
163
160
 
164
161
  ```typescript
165
- await mcpClient.resources.subscribe("myWeatherServer", "weather://current");
162
+ await mcpClient.resources.subscribe('myWeatherServer', 'weather://current')
166
163
  ```
167
164
 
168
165
  #### `resources.unsubscribe(serverName: string, uri: string)`
@@ -176,7 +173,7 @@ async unsubscribe(serverName: string, uri: string): Promise<object>
176
173
  Example:
177
174
 
178
175
  ```typescript
179
- await mcpClient.resources.unsubscribe("myWeatherServer", "weather://current");
176
+ await mcpClient.resources.unsubscribe('myWeatherServer', 'weather://current')
180
177
  ```
181
178
 
182
179
  #### `resources.onUpdated(serverName: string, handler: (params: { uri: string }) => void)`
@@ -190,11 +187,11 @@ async onUpdated(serverName: string, handler: (params: { uri: string }) => void):
190
187
  Example:
191
188
 
192
189
  ```typescript
193
- mcpClient.resources.onUpdated("myWeatherServer", (params) => {
194
- console.log(`Resource updated on myWeatherServer: ${params.uri}`);
190
+ mcpClient.resources.onUpdated('myWeatherServer', params => {
191
+ console.log(`Resource updated on myWeatherServer: ${params.uri}`)
195
192
  // You might want to re-fetch the resource content here
196
193
  // await mcpClient.resources.read("myWeatherServer", params.uri);
197
- });
194
+ })
198
195
  ```
199
196
 
200
197
  #### `resources.onListChanged(serverName: string, handler: () => void)`
@@ -208,11 +205,11 @@ async onListChanged(serverName: string, handler: () => void): Promise<void>
208
205
  Example:
209
206
 
210
207
  ```typescript
211
- mcpClient.resources.onListChanged("myWeatherServer", () => {
212
- console.log("Resource list changed on myWeatherServer.");
208
+ mcpClient.resources.onListChanged('myWeatherServer', () => {
209
+ console.log('Resource list changed on myWeatherServer.')
213
210
  // You should re-fetch the list of resources
214
211
  // await mcpClient.resources.list();
215
- });
212
+ })
216
213
  ```
217
214
 
218
215
  ### `elicitation` Property
@@ -222,27 +219,27 @@ The `MCPClient` instance has an `elicitation` property that provides access to e
222
219
  ```typescript
223
220
  const mcpClient = new MCPClient({
224
221
  /* ...servers configuration... */
225
- });
222
+ })
226
223
 
227
224
  // Set up elicitation handler
228
- mcpClient.elicitation.onRequest("serverName", async (request) => {
225
+ mcpClient.elicitation.onRequest('serverName', async request => {
229
226
  // Handle elicitation request from server
230
- console.log("Server requests:", request.message);
231
- console.log("Schema:", request.requestedSchema);
227
+ console.log('Server requests:', request.message)
228
+ console.log('Schema:', request.requestedSchema)
232
229
 
233
230
  // Return user response
234
231
  return {
235
- action: "accept",
236
- content: { name: "John Doe", email: "john@example.com" },
237
- };
238
- });
232
+ action: 'accept',
233
+ content: { name: 'John Doe', email: 'john@example.com' },
234
+ }
235
+ })
239
236
  ```
240
237
 
241
238
  #### `elicitation.onRequest(serverName: string, handler: ElicitationHandler)`
242
239
 
243
240
  Sets up a handler function that will be called when any connected MCP server sends an elicitation request. The handler receives the request and must return a response.
244
241
 
245
- **ElicitationHandler Function:**
242
+ ##### ElicitationHandler Function
246
243
 
247
244
  The handler function receives a request object with:
248
245
 
@@ -257,105 +254,103 @@ The handler must return an `ElicitResult` with:
257
254
  **Example:**
258
255
 
259
256
  ```typescript
260
- mcpClient.elicitation.onRequest("serverName", async (request) => {
261
- console.log(`Server requests: ${request.message}`);
257
+ mcpClient.elicitation.onRequest('serverName', async request => {
258
+ console.log(`Server requests: ${request.message}`)
262
259
 
263
260
  // Example: Simple user input collection
264
261
  if (request.requestedSchema.properties.name) {
265
262
  // Simulate user accepting and providing data
266
263
  return {
267
- action: "accept",
264
+ action: 'accept',
268
265
  content: {
269
- name: "Alice Smith",
270
- email: "alice@example.com",
266
+ name: 'Alice Smith',
267
+ email: 'alice@example.com',
271
268
  },
272
- };
269
+ }
273
270
  }
274
271
 
275
272
  // Simulate user declining the request
276
- return { action: "decline" };
277
- });
273
+ return { action: 'decline' }
274
+ })
278
275
  ```
279
276
 
280
277
  **Complete Interactive Example:**
281
278
 
282
279
  ```typescript
283
- import { MCPClient } from "@mastra/mcp";
284
- import { createInterface } from "readline";
280
+ import { MCPClient } from '@mastra/mcp'
281
+ import { createInterface } from 'readline'
285
282
 
286
283
  const readline = createInterface({
287
284
  input: process.stdin,
288
285
  output: process.stdout,
289
- });
286
+ })
290
287
 
291
288
  function askQuestion(question: string): Promise<string> {
292
- return new Promise((resolve) => {
293
- readline.question(question, (answer) => resolve(answer.trim()));
294
- });
289
+ return new Promise(resolve => {
290
+ readline.question(question, answer => resolve(answer.trim()))
291
+ })
295
292
  }
296
293
 
297
294
  const mcpClient = new MCPClient({
298
295
  servers: {
299
296
  interactiveServer: {
300
- url: new URL("http://localhost:3000/mcp"),
297
+ url: new URL('http://localhost:3000/mcp'),
301
298
  },
302
299
  },
303
- });
300
+ })
304
301
 
305
302
  // Set up interactive elicitation handler
306
- await mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
307
- console.log(`\n📋 Server Request: ${request.message}`);
308
- console.log("Required information:");
303
+ await mcpClient.elicitation.onRequest('interactiveServer', async request => {
304
+ console.log(`\n📋 Server Request: ${request.message}`)
305
+ console.log('Required information:')
309
306
 
310
- const schema = request.requestedSchema;
311
- const properties = schema.properties || {};
312
- const required = schema.required || [];
313
- const content: Record<string, any> = {};
307
+ const schema = request.requestedSchema
308
+ const properties = schema.properties || {}
309
+ const required = schema.required || []
310
+ const content: Record<string, any> = {}
314
311
 
315
312
  // Collect input for each field
316
313
  for (const [fieldName, fieldSchema] of Object.entries(properties)) {
317
- const field = fieldSchema as any;
318
- const isRequired = required.includes(fieldName);
314
+ const field = fieldSchema as any
315
+ const isRequired = required.includes(fieldName)
319
316
 
320
- let prompt = `${field.title || fieldName}`;
321
- if (field.description) prompt += ` (${field.description})`;
322
- if (isRequired) prompt += " *required*";
323
- prompt += ": ";
317
+ let prompt = `${field.title || fieldName}`
318
+ if (field.description) prompt += ` (${field.description})`
319
+ if (isRequired) prompt += ' *required*'
320
+ prompt += ': '
324
321
 
325
- const answer = await askQuestion(prompt);
322
+ const answer = await askQuestion(prompt)
326
323
 
327
324
  // Handle cancellation
328
- if (answer.toLowerCase() === "cancel") {
329
- return { action: "cancel" };
325
+ if (answer.toLowerCase() === 'cancel') {
326
+ return { action: 'cancel' }
330
327
  }
331
328
 
332
329
  // Validate required fields
333
- if (answer === "" && isRequired) {
334
- console.log(`❌ ${fieldName} is required`);
335
- return { action: "decline" };
330
+ if (answer === '' && isRequired) {
331
+ console.log(`❌ ${fieldName} is required`)
332
+ return { action: 'decline' }
336
333
  }
337
334
 
338
- if (answer !== "") {
339
- content[fieldName] = answer;
335
+ if (answer !== '') {
336
+ content[fieldName] = answer
340
337
  }
341
338
  }
342
339
 
343
340
  // Confirm submission
344
- console.log("\n📝 You provided:");
345
- console.log(JSON.stringify(content, null, 2));
341
+ console.log('\n📝 You provided:')
342
+ console.log(JSON.stringify(content, null, 2))
346
343
 
347
- const confirm = await askQuestion(
348
- "\nSubmit this information? (yes/no/cancel): ",
349
- );
344
+ const confirm = await askQuestion('\nSubmit this information? (yes/no/cancel): ')
350
345
 
351
- if (confirm.toLowerCase() === "yes" || confirm.toLowerCase() === "y") {
352
- return { action: "accept", content };
353
- } else if (confirm.toLowerCase() === "cancel") {
354
- return { action: "cancel" };
346
+ if (confirm.toLowerCase() === 'yes' || confirm.toLowerCase() === 'y') {
347
+ return { action: 'accept', content }
348
+ } else if (confirm.toLowerCase() === 'cancel') {
349
+ return { action: 'cancel' }
355
350
  } else {
356
- return { action: "decline" };
351
+ return { action: 'decline' }
357
352
  }
358
- });
353
+ })
359
354
  ```
360
355
 
361
356
  ### `prompts` Property
@@ -365,14 +360,14 @@ The `MCPClient` instance has a `prompts` property that provides access to prompt
365
360
  ```typescript
366
361
  const mcpClient = new MCPClient({
367
362
  /* ...servers configuration... */
368
- });
363
+ })
369
364
 
370
365
  // Access prompt methods via mcpClient.prompts
371
- const allPromptsByServer = await mcpClient.prompts.list();
366
+ const allPromptsByServer = await mcpClient.prompts.list()
372
367
  const { prompt, messages } = await mcpClient.prompts.get({
373
- serverName: "myWeatherServer",
374
- name: "current",
375
- });
368
+ serverName: 'myWeatherServer',
369
+ name: 'current',
370
+ })
376
371
  ```
377
372
 
378
373
  #### `prompts.list()`
@@ -386,9 +381,9 @@ async list(): Promise<Record<string, Prompt[]>>
386
381
  Example:
387
382
 
388
383
  ```typescript
389
- const promptsByServer = await mcpClient.prompts.list();
384
+ const promptsByServer = await mcpClient.prompts.list()
390
385
  for (const serverName in promptsByServer) {
391
- console.log(`Prompts from ${serverName}:`, promptsByServer[serverName]);
386
+ console.log(`Prompts from ${serverName}:`, promptsByServer[serverName])
392
387
  }
393
388
  ```
394
389
 
@@ -414,12 +409,12 @@ Example:
414
409
 
415
410
  ```typescript
416
411
  const { prompt, messages } = await mcpClient.prompts.get({
417
- serverName: "myWeatherServer",
418
- name: "current",
419
- args: { location: "London" },
420
- });
421
- console.log(prompt);
422
- console.log(messages);
412
+ serverName: 'myWeatherServer',
413
+ name: 'current',
414
+ args: { location: 'London' },
415
+ })
416
+ console.log(prompt)
417
+ console.log(messages)
423
418
  ```
424
419
 
425
420
  #### `prompts.onListChanged(serverName: string, handler: () => void)`
@@ -433,11 +428,11 @@ async onListChanged(serverName: string, handler: () => void): Promise<void>
433
428
  Example:
434
429
 
435
430
  ```typescript
436
- mcpClient.prompts.onListChanged("myWeatherServer", () => {
437
- console.log("Prompt list changed on myWeatherServer.");
431
+ mcpClient.prompts.onListChanged('myWeatherServer', () => {
432
+ console.log('Prompt list changed on myWeatherServer.')
438
433
  // You should re-fetch the list of prompts
439
434
  // await mcpClient.prompts.list();
440
- });
435
+ })
441
436
  ```
442
437
 
443
438
  ### `progress` Property
@@ -453,14 +448,14 @@ const mcpClient = new MCPClient({
453
448
  enableProgressTracking: true,
454
449
  },
455
450
  },
456
- });
451
+ })
457
452
 
458
453
  // Subscribe to progress updates for a specific server
459
- await mcpClient.progress.onUpdate('myServer', (params) => {
460
- console.log('📊 Progress:', params.progress, '/', params.total);
461
- if (params.message) console.log('Message:', params.message);
462
- if (params.progressToken) console.log('Token:', params.progressToken);
463
- });
454
+ await mcpClient.progress.onUpdate('myServer', params => {
455
+ console.log('📊 Progress:', params.progress, '/', params.total)
456
+ if (params.message) console.log('Message:', params.message)
457
+ if (params.progressToken) console.log('Token:', params.progressToken)
458
+ })
464
459
  ```
465
460
 
466
461
  #### `progress.onUpdate(serverName: string, handler)`
@@ -494,7 +489,7 @@ const mcpClient = new MCPClient({
494
489
  enableProgressTracking: false,
495
490
  },
496
491
  },
497
- });
492
+ })
498
493
  ```
499
494
 
500
495
  ## Elicitation
@@ -514,29 +509,29 @@ Elicitation is a feature that allows MCP servers to request structured informati
514
509
  You must set up an elicitation handler before tools that use elicitation are called:
515
510
 
516
511
  ```typescript
517
- import { MCPClient } from "@mastra/mcp";
512
+ import { MCPClient } from '@mastra/mcp'
518
513
 
519
514
  const mcpClient = new MCPClient({
520
515
  servers: {
521
516
  interactiveServer: {
522
- url: new URL("http://localhost:3000/mcp"),
517
+ url: new URL('http://localhost:3000/mcp'),
523
518
  },
524
519
  },
525
- });
520
+ })
526
521
 
527
522
  // Set up elicitation handler
528
- mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
523
+ mcpClient.elicitation.onRequest('interactiveServer', async request => {
529
524
  // Handle the server's request for user input
530
- console.log(`Server needs: ${request.message}`);
525
+ console.log(`Server needs: ${request.message}`)
531
526
 
532
527
  // Your logic to collect user input
533
- const userData = await collectUserInput(request.requestedSchema);
528
+ const userData = await collectUserInput(request.requestedSchema)
534
529
 
535
530
  return {
536
- action: "accept",
531
+ action: 'accept',
537
532
  content: userData,
538
- };
539
- });
533
+ }
534
+ })
540
535
  ```
541
536
 
542
537
  ### Response Types
@@ -547,21 +542,21 @@ Your elicitation handler must return one of three response types:
547
542
 
548
543
  ```typescript
549
544
  return {
550
- action: "accept",
551
- content: { name: "John Doe", email: "john@example.com" },
552
- };
545
+ action: 'accept',
546
+ content: { name: 'John Doe', email: 'john@example.com' },
547
+ }
553
548
  ```
554
549
 
555
550
  - **Decline**: User explicitly declined to provide the information
556
551
 
557
552
  ```typescript
558
- return { action: "decline" };
553
+ return { action: 'decline' }
559
554
  ```
560
555
 
561
556
  - **Cancel**: User dismissed or cancelled the request
562
557
 
563
558
  ```typescript
564
- return { action: "cancel" };
559
+ return { action: 'cancel' }
565
560
  ```
566
561
 
567
562
  ### Schema-Based Input Collection
@@ -569,13 +564,13 @@ Your elicitation handler must return one of three response types:
569
564
  The `requestedSchema` provides structure for the data the server needs:
570
565
 
571
566
  ```typescript
572
- await mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
573
- const { properties, required = [] } = request.requestedSchema;
574
- const content: Record<string, any> = {};
567
+ await mcpClient.elicitation.onRequest('interactiveServer', async request => {
568
+ const { properties, required = [] } = request.requestedSchema
569
+ const content: Record<string, any> = {}
575
570
 
576
571
  for (const [fieldName, fieldSchema] of Object.entries(properties || {})) {
577
- const field = fieldSchema as any;
578
- const isRequired = required.includes(fieldName);
572
+ const field = fieldSchema as any
573
+ const isRequired = required.includes(fieldName)
579
574
 
580
575
  // Collect input based on field type and requirements
581
576
  const value = await promptUser({
@@ -586,15 +581,15 @@ await mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
586
581
  required: isRequired,
587
582
  format: field.format,
588
583
  enum: field.enum,
589
- });
584
+ })
590
585
 
591
586
  if (value !== null) {
592
- content[fieldName] = value;
587
+ content[fieldName] = value
593
588
  }
594
589
  }
595
590
 
596
- return { action: "accept", content };
597
- });
591
+ return { action: 'accept', content }
592
+ })
598
593
  ```
599
594
 
600
595
  ### Best Practices
@@ -610,32 +605,32 @@ await mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
610
605
  For connecting to MCP servers that require OAuth authentication per the [MCP Auth Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization), use the `MCPOAuthClientProvider`:
611
606
 
612
607
  ```typescript
613
- import { MCPClient, MCPOAuthClientProvider } from "@mastra/mcp";
608
+ import { MCPClient, MCPOAuthClientProvider } from '@mastra/mcp'
614
609
 
615
610
  // Create an OAuth provider
616
611
  const oauthProvider = new MCPOAuthClientProvider({
617
- redirectUrl: "http://localhost:3000/oauth/callback",
612
+ redirectUrl: 'http://localhost:3000/oauth/callback',
618
613
  clientMetadata: {
619
- redirect_uris: ["http://localhost:3000/oauth/callback"],
620
- client_name: "My MCP Client",
621
- grant_types: ["authorization_code", "refresh_token"],
622
- response_types: ["code"],
614
+ redirect_uris: ['http://localhost:3000/oauth/callback'],
615
+ client_name: 'My MCP Client',
616
+ grant_types: ['authorization_code', 'refresh_token'],
617
+ response_types: ['code'],
623
618
  },
624
- onRedirectToAuthorization: (url) => {
619
+ onRedirectToAuthorization: url => {
625
620
  // Handle authorization redirect (open browser, redirect response, etc.)
626
- console.log(`Please visit: ${url}`);
621
+ console.log(`Please visit: ${url}`)
627
622
  },
628
- });
623
+ })
629
624
 
630
625
  // Use the provider with MCPClient
631
626
  const client = new MCPClient({
632
627
  servers: {
633
628
  protectedServer: {
634
- url: new URL("https://mcp.example.com/mcp"),
629
+ url: new URL('https://mcp.example.com/mcp'),
635
630
  authProvider: oauthProvider,
636
631
  },
637
632
  },
638
- });
633
+ })
639
634
  ```
640
635
 
641
636
  ### Quick Token Provider
@@ -643,24 +638,24 @@ const client = new MCPClient({
643
638
  For testing or when you already have a valid access token:
644
639
 
645
640
  ```typescript
646
- import { MCPClient, createSimpleTokenProvider } from "@mastra/mcp";
641
+ import { MCPClient, createSimpleTokenProvider } from '@mastra/mcp'
647
642
 
648
- const provider = createSimpleTokenProvider("your-access-token", {
649
- redirectUrl: "http://localhost:3000/callback",
643
+ const provider = createSimpleTokenProvider('your-access-token', {
644
+ redirectUrl: 'http://localhost:3000/callback',
650
645
  clientMetadata: {
651
- redirect_uris: ["http://localhost:3000/callback"],
652
- client_name: "Test Client",
646
+ redirect_uris: ['http://localhost:3000/callback'],
647
+ client_name: 'Test Client',
653
648
  },
654
- });
649
+ })
655
650
 
656
651
  const client = new MCPClient({
657
652
  servers: {
658
653
  testServer: {
659
- url: new URL("https://mcp.example.com/mcp"),
654
+ url: new URL('https://mcp.example.com/mcp'),
660
655
  authProvider: provider,
661
656
  },
662
657
  },
663
- });
658
+ })
664
659
  ```
665
660
 
666
661
  ### Custom Token Storage
@@ -668,39 +663,44 @@ const client = new MCPClient({
668
663
  For persistent token storage across sessions, implement the `OAuthStorage` interface:
669
664
 
670
665
  ```typescript
671
- import { MCPOAuthClientProvider, OAuthStorage } from "@mastra/mcp";
666
+ import { MCPOAuthClientProvider, OAuthStorage } from '@mastra/mcp'
672
667
 
673
668
  class DatabaseOAuthStorage implements OAuthStorage {
674
- constructor(private db: Database, private userId: string) {}
669
+ constructor(
670
+ private db: Database,
671
+ private userId: string,
672
+ ) {}
675
673
 
676
674
  async set(key: string, value: string): Promise<void> {
677
675
  await this.db.query(
678
- "INSERT INTO oauth_tokens (user_id, key, value) VALUES (?, ?, ?) ON CONFLICT DO UPDATE SET value = ?",
679
- [this.userId, key, value, value]
680
- );
676
+ 'INSERT INTO oauth_tokens (user_id, key, value) VALUES (?, ?, ?) ON CONFLICT DO UPDATE SET value = ?',
677
+ [this.userId, key, value, value],
678
+ )
681
679
  }
682
680
 
683
681
  async get(key: string): Promise<string | undefined> {
684
682
  const result = await this.db.query(
685
- "SELECT value FROM oauth_tokens WHERE user_id = ? AND key = ?",
686
- [this.userId, key]
687
- );
688
- return result?.[0]?.value;
683
+ 'SELECT value FROM oauth_tokens WHERE user_id = ? AND key = ?',
684
+ [this.userId, key],
685
+ )
686
+ return result?.[0]?.value
689
687
  }
690
688
 
691
689
  async delete(key: string): Promise<void> {
692
- await this.db.query(
693
- "DELETE FROM oauth_tokens WHERE user_id = ? AND key = ?",
694
- [this.userId, key]
695
- );
690
+ await this.db.query('DELETE FROM oauth_tokens WHERE user_id = ? AND key = ?', [
691
+ this.userId,
692
+ key,
693
+ ])
696
694
  }
697
695
  }
698
696
 
699
697
  const provider = new MCPOAuthClientProvider({
700
- redirectUrl: "http://localhost:3000/callback",
701
- clientMetadata: { /* ... */ },
702
- storage: new DatabaseOAuthStorage(db, "user-123"),
703
- });
698
+ redirectUrl: 'http://localhost:3000/callback',
699
+ clientMetadata: {
700
+ /* ... */
701
+ },
702
+ storage: new DatabaseOAuthStorage(db, 'user-123'),
703
+ })
704
704
  ```
705
705
 
706
706
  ## Examples
@@ -710,74 +710,69 @@ const provider = new MCPOAuthClientProvider({
710
710
  For tools where you have a single connection to the MCP server for you entire app, use `listTools()` and pass the tools to your agent:
711
711
 
712
712
  ```typescript
713
- import { MCPClient } from "@mastra/mcp";
714
- import { Agent } from "@mastra/core/agent";
713
+ import { MCPClient } from '@mastra/mcp'
714
+ import { Agent } from '@mastra/core/agent'
715
715
 
716
716
  const mcp = new MCPClient({
717
717
  servers: {
718
718
  stockPrice: {
719
- command: "npx",
720
- args: ["tsx", "stock-price.ts"],
719
+ command: 'npx',
720
+ args: ['tsx', 'stock-price.ts'],
721
721
  env: {
722
- API_KEY: "your-api-key",
722
+ API_KEY: 'your-api-key',
723
723
  },
724
- log: (logMessage) => {
725
- console.log(`[${logMessage.level}] ${logMessage.message}`);
724
+ log: logMessage => {
725
+ console.log(`[${logMessage.level}] ${logMessage.message}`)
726
726
  },
727
727
  },
728
728
  weather: {
729
- url: new URL("http://localhost:8080/sse"),
729
+ url: new URL('http://localhost:8080/sse'),
730
730
  },
731
731
  },
732
732
  timeout: 30000, // Global 30s timeout
733
- });
733
+ })
734
734
 
735
735
  // Create an agent with access to all tools
736
736
  const agent = new Agent({
737
- id: "multi-tool-agent",
738
- name: "Multi-tool Agent",
739
- instructions: "You have access to multiple tool servers.",
740
- model: "openai/gpt-5.1",
737
+ id: 'multi-tool-agent',
738
+ name: 'Multi-tool Agent',
739
+ instructions: 'You have access to multiple tool servers.',
740
+ model: 'openai/gpt-5.1',
741
741
  tools: await mcp.listTools(),
742
- });
742
+ })
743
743
 
744
744
  // Example of using resource methods
745
745
  async function checkWeatherResource() {
746
746
  try {
747
- const weatherResources = await mcp.resources.list();
747
+ const weatherResources = await mcp.resources.list()
748
748
  if (weatherResources.weather && weatherResources.weather.length > 0) {
749
- const currentWeatherURI = weatherResources.weather[0].uri;
750
- const weatherData = await mcp.resources.read(
751
- "weather",
752
- currentWeatherURI,
753
- );
754
- console.log("Weather data:", weatherData.contents[0].text);
749
+ const currentWeatherURI = weatherResources.weather[0].uri
750
+ const weatherData = await mcp.resources.read('weather', currentWeatherURI)
751
+ console.log('Weather data:', weatherData.contents[0].text)
755
752
  }
756
753
  } catch (error) {
757
- console.error("Error fetching weather resource:", error);
754
+ console.error('Error fetching weather resource:', error)
758
755
  }
759
756
  }
760
- checkWeatherResource();
757
+ checkWeatherResource()
761
758
 
762
759
  // Example of using prompt methods
763
760
  async function checkWeatherPrompt() {
764
761
  try {
765
- const weatherPrompts = await mcp.prompts.list();
762
+ const weatherPrompts = await mcp.prompts.list()
766
763
  if (weatherPrompts.weather && weatherPrompts.weather.length > 0) {
767
- const currentWeatherPrompt = weatherPrompts.weather.find(
768
- (p) => p.name === "current",
769
- );
764
+ const currentWeatherPrompt = weatherPrompts.weather.find(p => p.name === 'current')
770
765
  if (currentWeatherPrompt) {
771
- console.log("Weather prompt:", currentWeatherPrompt);
766
+ console.log('Weather prompt:', currentWeatherPrompt)
772
767
  } else {
773
- console.log("Current weather prompt not found");
768
+ console.log('Current weather prompt not found')
774
769
  }
775
770
  }
776
771
  } catch (error) {
777
- console.error("Error fetching weather prompt:", error);
772
+ console.error('Error fetching weather prompt:', error)
778
773
  }
779
774
  }
780
- checkWeatherPrompt();
775
+ checkWeatherPrompt()
781
776
  ```
782
777
 
783
778
  ### Dynamic toolsets
@@ -785,30 +780,30 @@ checkWeatherPrompt();
785
780
  When you need a new MCP connection for each user, use `listToolsets()` and add the tools when calling stream or generate:
786
781
 
787
782
  ```typescript
788
- import { Agent } from "@mastra/core/agent";
789
- import { MCPClient } from "@mastra/mcp";
783
+ import { Agent } from '@mastra/core/agent'
784
+ import { MCPClient } from '@mastra/mcp'
790
785
 
791
786
  // Create the agent first, without any tools
792
787
  const agent = new Agent({
793
- id: "multi-tool-agent",
794
- name: "Multi-tool Agent",
795
- instructions: "You help users check stocks and weather.",
796
- model: "openai/gpt-5.1",
797
- });
788
+ id: 'multi-tool-agent',
789
+ name: 'Multi-tool Agent',
790
+ instructions: 'You help users check stocks and weather.',
791
+ model: 'openai/gpt-5.1',
792
+ })
798
793
 
799
794
  // Later, configure MCP with user-specific settings
800
795
  const mcp = new MCPClient({
801
796
  servers: {
802
797
  stockPrice: {
803
- command: "npx",
804
- args: ["tsx", "stock-price.ts"],
798
+ command: 'npx',
799
+ args: ['tsx', 'stock-price.ts'],
805
800
  env: {
806
- API_KEY: "user-123-api-key",
801
+ API_KEY: 'user-123-api-key',
807
802
  },
808
803
  timeout: 20000, // Server-specific timeout
809
804
  },
810
805
  weather: {
811
- url: new URL("http://localhost:8080/sse"),
806
+ url: new URL('http://localhost:8080/sse'),
812
807
  requestInit: {
813
808
  headers: {
814
809
  Authorization: `Bearer user-123-token`,
@@ -816,15 +811,12 @@ const mcp = new MCPClient({
816
811
  },
817
812
  },
818
813
  },
819
- });
814
+ })
820
815
 
821
816
  // Pass all toolsets to stream() or generate()
822
- const response = await agent.stream(
823
- "How is AAPL doing and what is the weather?",
824
- {
825
- toolsets: await mcp.listToolsets(),
826
- },
827
- );
817
+ const response = await agent.stream('How is AAPL doing and what is the weather?', {
818
+ toolsets: await mcp.listToolsets(),
819
+ })
828
820
  ```
829
821
 
830
822
  ## Instance Management
@@ -844,31 +836,31 @@ const mcp1 = new MCPClient({
844
836
  servers: {
845
837
  /* ... */
846
838
  },
847
- });
839
+ })
848
840
 
849
841
  // Second instance with same config - Will throw an error
850
842
  const mcp2 = new MCPClient({
851
843
  servers: {
852
844
  /* ... */
853
845
  },
854
- });
846
+ })
855
847
 
856
848
  // To fix, either:
857
849
  // 1. Add unique IDs
858
850
  const mcp3 = new MCPClient({
859
- id: "instance-1",
851
+ id: 'instance-1',
860
852
  servers: {
861
853
  /* ... */
862
854
  },
863
- });
855
+ })
864
856
 
865
857
  // 2. Or disconnect before recreating
866
- await mcp1.disconnect();
858
+ await mcp1.disconnect()
867
859
  const mcp4 = new MCPClient({
868
860
  servers: {
869
861
  /* ... */
870
862
  },
871
- });
863
+ })
872
864
  ```
873
865
 
874
866
  ## Server Lifecycle
@@ -889,10 +881,10 @@ When `fetch` is provided, `requestInit`, `eventSourceInit`, and `authProvider` b
889
881
  const mcpClient = new MCPClient({
890
882
  servers: {
891
883
  apiServer: {
892
- url: new URL("https://api.example.com/mcp"),
884
+ url: new URL('https://api.example.com/mcp'),
893
885
  fetch: async (url, init) => {
894
886
  // Refresh token on each request
895
- const token = await getAuthToken(); // Your token refresh logic
887
+ const token = await getAuthToken() // Your token refresh logic
896
888
 
897
889
  return fetch(url, {
898
890
  ...init,
@@ -900,11 +892,11 @@ const mcpClient = new MCPClient({
900
892
  ...init?.headers,
901
893
  Authorization: `Bearer ${token}`,
902
894
  },
903
- });
895
+ })
904
896
  },
905
897
  },
906
898
  },
907
- });
899
+ })
908
900
  ```
909
901
 
910
902
  ## Using SSE Request Headers
@@ -916,44 +908,44 @@ When using the legacy SSE MCP transport, you must configure both `requestInit` a
916
908
  const sseClient = new MCPClient({
917
909
  servers: {
918
910
  exampleServer: {
919
- url: new URL("https://your-mcp-server.com/sse"),
911
+ url: new URL('https://your-mcp-server.com/sse'),
920
912
  // Note: requestInit alone isn't enough for SSE
921
913
  requestInit: {
922
914
  headers: {
923
- Authorization: "Bearer your-token",
915
+ Authorization: 'Bearer your-token',
924
916
  },
925
917
  },
926
918
  // This is also required for SSE connections with custom headers
927
919
  eventSourceInit: {
928
920
  fetch(input: Request | URL | string, init?: RequestInit) {
929
- const headers = new Headers(init?.headers || {});
930
- headers.set("Authorization", "Bearer your-token");
921
+ const headers = new Headers(init?.headers || {})
922
+ headers.set('Authorization', 'Bearer your-token')
931
923
  return fetch(input, {
932
924
  ...init,
933
925
  headers,
934
- });
926
+ })
935
927
  },
936
928
  },
937
929
  },
938
930
  },
939
- });
931
+ })
940
932
 
941
933
  // Option 2: Using custom fetch (simpler, works for both Streamable HTTP and SSE)
942
934
  const sseClientWithFetch = new MCPClient({
943
935
  servers: {
944
936
  exampleServer: {
945
- url: new URL("https://your-mcp-server.com/sse"),
937
+ url: new URL('https://your-mcp-server.com/sse'),
946
938
  fetch: async (url, init) => {
947
- const headers = new Headers(init?.headers || {});
948
- headers.set("Authorization", "Bearer your-token");
939
+ const headers = new Headers(init?.headers || {})
940
+ headers.set('Authorization', 'Bearer your-token')
949
941
  return fetch(url, {
950
942
  ...init,
951
943
  headers,
952
- });
944
+ })
953
945
  },
954
946
  },
955
947
  },
956
- });
948
+ })
957
949
  ```
958
950
 
959
951
  ## Related Information