@mastra/mcp 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -1,787 +1,22 @@
1
1
  # @mastra/mcp
2
2
 
3
- Model Context Protocol (MCP) client implementation for Mastra, providing seamless integration with MCP-compatible AI models and tools.
3
+ Mastra supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro), an open standard for connecting AI agents to external tools and resources. It serves as a universal plugin system, enabling agents to call tools regardless of language or hosting environment.
4
+
5
+ Mastra can also be used to author MCP servers, exposing agents, tools, and other structured resources via the MCP interface. These can then be accessed by any system or agent that supports the protocol.
4
6
 
5
7
  ## Installation
6
8
 
9
+ To use MCP, install the required dependency:
10
+
7
11
  ```bash
8
12
  npm install @mastra/mcp@latest
9
13
  ```
10
14
 
11
15
  ## Overview
12
16
 
13
- The `@mastra/mcp` package provides a client implementation for the Model Context Protocol (MCP), enabling Mastra to communicate with MCP-compatible AI models and tools. It wraps the official `@modelcontextprotocol/sdk` and provides Mastra-specific functionality.
14
-
15
- The client automatically detects the transport type based on your server configuration:
16
-
17
- - If you provide a `command`, it uses the Stdio transport.
18
- - If you provide a `url`, it first attempts to use the Streamable HTTP transport (protocol version 2025-03-26) and falls back to the legacy SSE transport (protocol version 2024-11-05) if the initial connection fails.
19
-
20
- ## Usage
21
-
22
- ```typescript
23
- import { MCPClient } from '@mastra/mcp';
24
-
25
- // Create a client with a Stdio server
26
- const stdioClient = new MCPClient({
27
- servers: {
28
- myStdioClient: {
29
- command: 'your-mcp-server-command',
30
- args: ['--your', 'args'],
31
- env: { API_KEY: 'your-api-key' }, // optional environment variables
32
- capabilities: {}, // optional ClientCapabilities
33
- timeout: 60000, // optional timeout for tool calls in milliseconds
34
- },
35
- },
36
- });
37
-
38
- // Create a client with an HTTP server (tries Streamable HTTP, falls back to SSE)
39
- const httpClient = new MCPClient({
40
- servers: {
41
- myHttpClient: {
42
- url: new URL('https://your-mcp-server.com/mcp'), // Use the base URL for Streamable HTTP
43
- requestInit: {
44
- // Optional fetch request configuration
45
- headers: { Authorization: 'Bearer your-token' },
46
- },
47
- // eventSourceInit is only needed for custom headers with the legacy SSE fallback
48
- eventSourceInit: {
49
- /* ... */
50
- },
51
- },
52
- },
53
- });
54
-
55
- // Or create a client with SSE server
56
- const sseClient = new MCPClient({
57
- servers: {
58
- mySseClient: {
59
- url: new URL('https://your-mcp-server.com/sse'),
60
- requestInit: {
61
- headers: { Authorization: 'Bearer your-token' },
62
- },
63
- eventSourceInit: {
64
- fetch(input: Request | URL | string, init?: RequestInit) {
65
- const headers = new Headers(init?.headers || {});
66
- headers.set('Authorization', 'Bearer your-token');
67
- return fetch(input, {
68
- ...init,
69
- headers,
70
- });
71
- },
72
- },
73
- timeout: 60000, // optional timeout for tool calls in milliseconds
74
- },
75
- },
76
- });
77
-
78
- // Connect to the MCP server (using one of the clients above)
79
- await httpClient.connect();
80
-
81
- // List available resources
82
- const resources = await httpClient.resources();
83
-
84
- // Get available tools
85
- const tools = await httpClient.tools();
86
-
87
- // Disconnect when done
88
- await httpClient.disconnect();
89
- ```
90
-
91
- ## Managing Multiple MCP Servers
92
-
93
- For applications that need to interact with multiple MCP servers, the `MCPClient` class provides a convenient way to manage multiple server connections and their tools. It also uses the automatic transport detection based on the `server` configuration:
94
-
95
- ```typescript
96
- import { MCPClient } from '@mastra/mcp';
97
-
98
- const mcp = new MCPClient({
99
- servers: {
100
- // Stdio-based server
101
- stockPrice: {
102
- command: 'npx',
103
- args: ['tsx', 'stock-price.ts'],
104
- env: {
105
- API_KEY: 'your-api-key',
106
- },
107
- },
108
- // HTTP-based server (tries Streamable HTTP, falls back to SSE)
109
- weather: {
110
- url: new URL('http://localhost:8080/mcp'), // Use the base URL for Streamable HTTP
111
- requestInit: {
112
- // Optional fetch request configuration
113
- headers: { 'X-Api-Key': 'weather-key' },
114
- },
115
- },
116
- },
117
- });
118
-
119
- // Get all tools from all configured servers namespaced with the server name
120
- const tools = await mcp.listTools();
121
-
122
- // Get tools grouped into a toolset object per-server
123
- const toolsets = await mcp.listToolsets();
124
- ```
125
-
126
- ## Logging
127
-
128
- The MCP client provides per-server logging capabilities, allowing you to monitor interactions with each MCP server separately:
129
-
130
- ```typescript
131
- import { MCPClient, LogMessage, LoggingLevel } from '@mastra/mcp';
132
-
133
- // Define a custom log handler
134
- const weatherLogger = (logMessage: LogMessage) => {
135
- console.log(`[${logMessage.level}] ${logMessage.serverName}: ${logMessage.message}`);
136
-
137
- // Log data contains valuable information
138
- console.log('Details:', logMessage.details);
139
- console.log('Timestamp:', logMessage.timestamp);
140
- };
141
-
142
- // Initialize MCP configuration with server-specific loggers
143
- const mcp = new MCPClient({
144
- servers: {
145
- weatherService: {
146
- command: 'npx',
147
- args: ['tsx', 'weather-mcp.ts'],
148
- // Attach the logger to this specific server
149
- logger: weatherLogger, // Use 'logger' key
150
- },
151
-
152
- stockPriceService: {
153
- command: 'npx',
154
- args: ['tsx', 'stock-mcp.ts'],
155
- // Different logger for this service
156
- logger: logMessage => {
157
- // Use 'logger' key
158
- // Just log errors and critical events for this service
159
- if (['error', 'critical', 'alert', 'emergency'].includes(logMessage.level)) {
160
- console.error(`Stock service ${logMessage.level}: ${logMessage.message}`);
161
- }
162
- },
163
- },
164
- },
165
- });
166
- ```
167
-
168
- ### Log Message Structure
169
-
170
- Each log message contains the following information:
171
-
172
- ```typescript
173
- interface LogMessage {
174
- level: LoggingLevel; // MCP SDK standard log levels
175
- message: string;
176
- timestamp: Date;
177
- serverName: string;
178
- details?: Record<string, any>;
179
- }
180
- ```
181
-
182
- The `LoggingLevel` type is directly imported from the MCP SDK, ensuring compatibility with all standard MCP log levels: `'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency'`.
183
-
184
- ### Creating Reusable Loggers
185
-
186
- You can create reusable logger factories for common patterns:
187
-
188
- ```typescript
189
- import fs from 'node:fs';
190
-
191
- // File logger factory with color coded output for different severity levels
192
- const createFileLogger = (filePath: string) => {
193
- return (logMessage: LogMessage) => {
194
- // Format the message based on level
195
- const prefix =
196
- logMessage.level === 'emergency' ? '!!! EMERGENCY !!! ' : logMessage.level === 'alert' ? '! ALERT ! ' : '';
197
-
198
- // Write to file with timestamp, level, etc.
199
- fs.appendFileSync(
200
- filePath,
201
- `[${logMessage.timestamp.toISOString()}] [${logMessage.level.toUpperCase()}] ${prefix}${logMessage.message}\n`,
202
- );
203
- };
204
- };
205
-
206
- // Use the factory in configuration
207
- const mcp = new MCPClient({
208
- servers: {
209
- weatherService: {
210
- command: 'npx',
211
- args: ['tsx', 'weather-mcp.ts'],
212
- logger: createFileLogger('./logs/weather.log'), // Use 'logger' key
213
- },
214
- },
215
- });
216
- ```
217
-
218
- See the `examples/server-logging.ts` file for comprehensive examples of various logging strategies.
219
-
220
- ### Tools vs Toolsets
221
-
222
- The MCPClient class provides two ways to access MCP tools:
223
-
224
- #### Tools (`listTools()`)
225
-
226
- Use this when:
227
-
228
- - You have a single MCP connection
229
- - The tools are used by a single user/context (CLI tools, automation scripts, etc)
230
- - Tool configuration (API keys, credentials) remains constant
231
- - You want to initialize an Agent with a fixed set of tools
232
-
233
- ```typescript
234
- import { Agent } from '@mastra/core/agent';
235
- import { openai } from '@ai-sdk/openai';
236
-
237
- const agent = new Agent({
238
- id: 'cli-assistant',
239
- name: 'CLI Assistant',
240
- instructions: 'You help users with CLI tasks',
241
- model: openai('gpt-4'),
242
- tools: await mcp.listTools(), // Tools are fixed at agent creation
243
- });
244
- ```
245
-
246
- #### Toolsets (`listToolsets()`)
247
-
248
- Use this when:
249
-
250
- - You need per-request tool configuration
251
- - Tools need different credentials per user
252
- - Running in a multi-user environment (web app, API, etc)
253
- - Tool configuration needs to change dynamically
254
-
255
- ```typescript
256
- import { MCPClient } from '@mastra/mcp';
257
- import { Agent } from '@mastra/core/agent';
258
- import { openai } from '@ai-sdk/openai';
259
-
260
- // Configure MCP servers with user-specific settings before getting toolsets
261
- const mcp = new MCPClient({
262
- servers: {
263
- stockPrice: {
264
- command: 'npx',
265
- args: ['tsx', 'weather-mcp.ts'],
266
- env: {
267
- // These would be different per user
268
- API_KEY: 'user-1-api-key',
269
- },
270
- },
271
- weather: {
272
- url: new URL('http://localhost:8080/mcp'), // Use the base URL for Streamable HTTP
273
- requestInit: {
274
- headers: {
275
- // These would be different per user
276
- Authorization: 'Bearer user-1-token',
277
- },
278
- },
279
- // eventSourceInit is only needed for custom headers with the legacy SSE fallback
280
- eventSourceInit: {
281
- /* ... */
282
- },
283
- },
284
- },
285
- });
286
-
287
- // Get the current toolsets configured for this user
288
- const toolsets = await mcp.listToolsets();
289
-
290
- // Use the agent with user-specific tool configurations
291
- const response = await agent.generate('What is the weather in London?', {
292
- toolsets,
293
- });
294
-
295
- console.log(response.text);
296
- ```
297
-
298
- The `MCPClient` class automatically:
299
-
300
- - Manages connections to multiple MCP servers
301
- - Namespaces tools to prevent naming conflicts
302
- - Handles connection lifecycle and cleanup
303
- - Provides both flat and grouped access to tools
304
-
305
- ## Accessing MCP Resources
306
-
307
- MCP servers can expose resources - data or content that can be retrieved and used in your application. The `MCPClient` class provides methods to access these resources across multiple servers:
308
-
309
- ```typescript
310
- import { MCPClient } from '@mastra/mcp';
311
-
312
- const mcp = new MCPClient({
313
- servers: {
314
- weather: {
315
- url: new URL('http://localhost:8080/mcp'),
316
- },
317
- dataService: {
318
- command: 'npx',
319
- args: ['tsx', 'data-service.ts'],
320
- },
321
- },
322
- });
323
-
324
- // Get resources from all connected MCP servers
325
- const resources = await mcp.resources.get();
326
-
327
- // Resources are grouped by server name
328
- console.log(Object.keys(resources)); // ['weather', 'dataService']
329
-
330
- // Each server entry contains an array of resources
331
- if (resources.weather) {
332
- // Access resources from the weather server
333
- const weatherResources = resources.weather;
334
-
335
- // Each resource has uri, name, description, and mimeType
336
- weatherResources.forEach(resource => {
337
- console.log(`${resource.uri}: ${resource.name} (${resource.mimeType})`);
338
- });
339
-
340
- // Find a specific resource by URI
341
- const forecast = weatherResources.find(r => r.uri === 'weather://forecast');
342
- if (forecast) {
343
- console.log(`Found forecast resource: ${forecast.description}`);
344
- }
345
- }
346
- ```
347
-
348
- The `getResources()` method handles errors gracefully - if a server fails or doesn't support resources, it will be omitted from the results without causing the entire operation to fail.
349
-
350
- ## Prompts
351
-
352
- MCP servers can also expose prompts, which represent structured message templates or conversational context for agents.
353
-
354
- ### Listing Prompts
355
-
356
- ```typescript
357
- const prompts = await mcp.prompts.list();
358
- console.log(prompts.weather); // [ { name: 'current', ... }, ... ]
359
- ```
360
-
361
- ### Getting a Prompt and Messages
362
-
363
- ```typescript
364
- const { prompt, messages } = await mcp.prompts.get({ serverName: 'weather', name: 'current' });
365
- console.log(prompt); // { name: 'current', version: 'v1', ... }
366
- console.log(messages); // [ { role: 'assistant', content: { type: 'text', text: '...' } }, ... ]
367
- ```
368
-
369
- ### Handling Prompt List Change Notifications
370
-
371
- ```typescript
372
- mcp.prompts.onListChanged({
373
- serverName: 'weather',
374
- handler: () => {
375
- // Refresh prompt list or update UI
376
- },
377
- });
378
- ```
379
-
380
- Prompt notifications are delivered via SSE or compatible transports. Register handlers before expecting notifications.
381
-
382
- ## Authentication
383
-
384
- ### OAuth 2.0 Authentication (MCP Auth Spec)
385
-
386
- Mastra provides full support for the [MCP OAuth specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization), including:
387
-
388
- - **Server-side**: Protected Resource Metadata (RFC 9728), token validation middleware
389
- - **Client-side**: OAuth client provider implementation with PKCE, token storage, and automatic refresh
390
-
391
- #### Client-Side: Connecting to OAuth-Protected MCP Servers
392
-
393
- Use `MCPOAuthClientProvider` to connect to MCP servers that require OAuth authentication:
394
-
395
- ```typescript
396
- import { MCPClient, MCPOAuthClientProvider } from '@mastra/mcp';
397
-
398
- // Create an OAuth provider for your client
399
- const oauthProvider = new MCPOAuthClientProvider({
400
- redirectUrl: 'http://localhost:3000/oauth/callback',
401
- clientMetadata: {
402
- redirect_uris: ['http://localhost:3000/oauth/callback'],
403
- client_name: 'My MCP Client',
404
- grant_types: ['authorization_code', 'refresh_token'],
405
- response_types: ['code'],
406
- },
407
- // Handle authorization redirects (for CLI apps, open browser; for web apps, redirect response)
408
- onRedirectToAuthorization: url => {
409
- console.log(`Please visit: ${url}`);
410
- // Or: window.location.href = url.toString();
411
- },
412
- });
413
-
414
- // Create client with OAuth provider
415
- const client = new MCPClient({
416
- servers: {
417
- protectedServer: {
418
- url: new URL('https://mcp.example.com/mcp'),
419
- authProvider: oauthProvider,
420
- },
421
- },
422
- });
423
-
424
- await client.connect();
425
- ```
426
-
427
- For testing or when you already have a valid token, use `createSimpleTokenProvider`:
428
-
429
- ```typescript
430
- import { MCPClient, createSimpleTokenProvider } from '@mastra/mcp';
431
-
432
- const provider = createSimpleTokenProvider('your-access-token', {
433
- redirectUrl: 'http://localhost:3000/callback',
434
- clientMetadata: {
435
- redirect_uris: ['http://localhost:3000/callback'],
436
- client_name: 'Test Client',
437
- },
438
- });
439
-
440
- const client = new MCPClient({
441
- servers: {
442
- testServer: {
443
- url: new URL('https://mcp.example.com/mcp'),
444
- authProvider: provider,
445
- },
446
- },
447
- });
448
- ```
449
-
450
- #### Server-Side: Protecting Your MCP Server with OAuth
451
-
452
- Use `createOAuthMiddleware` to protect your MCP server endpoints:
453
-
454
- ```typescript
455
- import http from 'node:http';
456
- import { MCPServer, createOAuthMiddleware, createStaticTokenValidator } from '@mastra/mcp';
457
-
458
- // Create your MCP server
459
- const mcpServer = new MCPServer({
460
- id: 'protected-mcp-server',
461
- name: 'Protected MCP Server',
462
- version: '1.0.0',
463
- tools: {
464
- /* your tools */
465
- },
466
- });
467
-
468
- // Create OAuth middleware
469
- const oauthMiddleware = createOAuthMiddleware({
470
- oauth: {
471
- resource: 'https://mcp.example.com/mcp',
472
- authorizationServers: ['https://auth.example.com'],
473
- scopesSupported: ['mcp:read', 'mcp:write'],
474
- resourceName: 'My Protected MCP Server',
475
- // For production, use proper token validation (JWT, introspection, etc.)
476
- validateToken: createStaticTokenValidator(['allowed-token-1', 'allowed-token-2']),
477
- },
478
- mcpPath: '/mcp',
479
- });
480
-
481
- // Create HTTP server with OAuth protection
482
- const httpServer = http.createServer(async (req, res) => {
483
- const url = new URL(req.url || '', 'https://mcp.example.com');
484
-
485
- // Apply OAuth middleware first
486
- const result = await oauthMiddleware(req, res, url);
487
- if (!result.proceed) return; // Middleware handled the response (401, metadata, etc.)
488
-
489
- // Token is valid, proceed to MCP handler
490
- await mcpServer.startHTTP({ url, httpPath: '/mcp', req, res });
491
- });
492
-
493
- httpServer.listen(3000);
494
- ```
495
-
496
- The middleware automatically:
497
-
498
- - Serves Protected Resource Metadata at `/.well-known/oauth-protected-resource`
499
- - Returns `401 Unauthorized` with proper `WWW-Authenticate` headers when authentication is required
500
- - Validates bearer tokens using your provided validator
501
-
502
- #### Token Validation Options
503
-
504
- For production use, implement proper token validation:
505
-
506
- ```typescript
507
- import { createOAuthMiddleware, createIntrospectionValidator } from '@mastra/mcp';
508
-
509
- // Option 1: Token introspection (RFC 7662)
510
- const middleware = createOAuthMiddleware({
511
- oauth: {
512
- resource: 'https://mcp.example.com/mcp',
513
- authorizationServers: ['https://auth.example.com'],
514
- validateToken: createIntrospectionValidator('https://auth.example.com/oauth/introspect', {
515
- clientId: 'mcp-server',
516
- clientSecret: 'secret',
517
- }),
518
- },
519
- });
520
-
521
- // Option 2: Custom validation (JWT, database lookup, etc.)
522
- const middlewareCustom = createOAuthMiddleware({
523
- oauth: {
524
- resource: 'https://mcp.example.com/mcp',
525
- authorizationServers: ['https://auth.example.com'],
526
- validateToken: async (token, resource) => {
527
- // Your custom validation logic
528
- const decoded = await verifyJWT(token);
529
- if (!decoded) {
530
- return { valid: false, error: 'invalid_token', errorDescription: 'Token verification failed' };
531
- }
532
- return {
533
- valid: true,
534
- scopes: decoded.scope?.split(' ') || [],
535
- subject: decoded.sub,
536
- expiresAt: decoded.exp,
537
- };
538
- },
539
- },
540
- });
541
- ```
542
-
543
- #### Custom OAuth Storage
544
-
545
- For persistent token storage across sessions, implement the `OAuthStorage` interface:
546
-
547
- ```typescript
548
- import { MCPOAuthClientProvider, OAuthStorage } from '@mastra/mcp';
549
-
550
- // Example: Redis-based storage
551
- class RedisOAuthStorage implements OAuthStorage {
552
- constructor(
553
- private redis: RedisClient,
554
- private prefix: string,
555
- ) {}
556
-
557
- async set(key: string, value: string): Promise<void> {
558
- await this.redis.set(`${this.prefix}:${key}`, value);
559
- }
560
-
561
- async get(key: string): Promise<string | undefined> {
562
- return (await this.redis.get(`${this.prefix}:${key}`)) ?? undefined;
563
- }
564
-
565
- async delete(key: string): Promise<void> {
566
- await this.redis.del(`${this.prefix}:${key}`);
567
- }
568
- }
569
-
570
- const provider = new MCPOAuthClientProvider({
571
- redirectUrl: 'http://localhost:3000/callback',
572
- clientMetadata: {
573
- /* ... */
574
- },
575
- storage: new RedisOAuthStorage(redisClient, 'oauth:user123'),
576
- });
577
- ```
578
-
579
- ### OAuth Token Refresh with AuthProvider
580
-
581
- For simpler OAuth scenarios where you just need token refresh, you can pass an `authProvider` directly:
582
-
583
- ### Custom Fetch for Dynamic Authentication
584
-
585
- For HTTP servers, you can provide a custom `fetch` function to handle dynamic authentication, request interception, or other custom behavior. This is particularly useful when you need to refresh tokens on each request or customize request behavior.
586
-
587
- When `fetch` is provided, `requestInit`, `eventSourceInit`, and `authProvider` become optional, as you can handle these concerns within your custom fetch function.
588
-
589
- ```typescript
590
- const mcpClient = new MCPClient({
591
- servers: {
592
- apiServer: {
593
- url: new URL('https://api.example.com/mcp'),
594
- fetch: async (url, init) => {
595
- // Refresh token on each request
596
- const token = await getAuthToken(); // Your token refresh logic
597
-
598
- return fetch(url, {
599
- ...init,
600
- headers: {
601
- ...init?.headers,
602
- Authorization: `Bearer ${token}`,
603
- },
604
- });
605
- },
606
- },
607
- },
608
- });
609
- ```
610
-
611
- The custom `fetch` function is automatically used for both Streamable HTTP and SSE transports, making it a simpler alternative to configuring `requestInit` and `eventSourceInit` separately.
612
-
613
- ### SSE Authentication and Headers (Legacy Fallback)
614
-
615
- When the client falls back to using the legacy SSE (Server-Sent Events) transport and you need to include authentication or custom headers, you have two options:
616
-
617
- **Option 1: Using custom `fetch` (Recommended)**
618
-
619
- The simplest approach is to provide a custom `fetch` function, which will automatically be used for both POST requests and SSE connections:
620
-
621
- ```typescript
622
- const sseClient = new MCPClient({
623
- servers: {
624
- authenticatedSseClient: {
625
- url: new URL('https://your-mcp-server.com/sse'),
626
- fetch: async (url, init) => {
627
- const headers = new Headers(init?.headers || {});
628
- headers.set('Authorization', 'Bearer your-token');
629
- return fetch(url, {
630
- ...init,
631
- headers,
632
- });
633
- },
634
- },
635
- },
636
- });
637
- ```
638
-
639
- **Option 2: Using `requestInit` and `eventSourceInit`**
640
-
641
- Alternatively, you can use both `requestInit` and `eventSourceInit`. The standard `requestInit` headers won't work alone because SSE connections using the browser's `EventSource` API don't support custom headers directly.
642
-
643
- The `eventSourceInit` configuration allows you to customize the underlying fetch request used for the SSE connection, ensuring your authentication headers are properly included.
644
-
645
- To properly include authentication headers or other custom headers in SSE connections when using the legacy fallback, you need to use both `requestInit` and `eventSourceInit`:
646
-
647
- ```typescript
648
- const sseClient = new MCPClient({
649
- servers: {
650
- authenticatedSseClient: {
651
- url: new URL('https://your-mcp-server.com/sse'), // Note the typical /sse path for legacy servers
652
- // requestInit alone isn't enough for SSE connections
653
- requestInit: {
654
- headers: { Authorization: 'Bearer your-token' },
655
- },
656
- // eventSourceInit is required to include headers in the SSE connection
657
- eventSourceInit: {
658
- fetch(input: Request | URL | string, init?: RequestInit) {
659
- const headers = new Headers(init?.headers || {});
660
- headers.set('Authorization', 'Bearer your-token');
661
- return fetch(input, {
662
- ...init,
663
- headers,
664
- });
665
- },
666
- },
667
- },
668
- },
669
- });
670
- ```
671
-
672
- This configuration ensures that:
673
-
674
- 1. The authentication headers are properly included in the SSE connection request
675
- 2. The connection can be established with the required credentials
676
- 3. Subsequent messages can be received through the authenticated connection
677
-
678
- ```typescript
679
- const sseClient = new MastraMCPClient({
680
- name: 'authenticated-sse-client',
681
- server: {
682
- url: new URL('https://your-mcp-server.com/sse'), // Note the typical /sse path for legacy servers
683
- // requestInit alone isn't enough for SSE connections
684
- requestInit: {
685
- headers: { Authorization: 'Bearer your-token' },
686
- },
687
- // eventSourceInit is required to include headers in the SSE connection
688
- eventSourceInit: {
689
- fetch(input: Request | URL | string, init?: RequestInit) {
690
- const headers = new Headers(init?.headers || {});
691
- headers.set('Authorization', 'Bearer your-token');
692
- return fetch(input, {
693
- ...init,
694
- headers,
695
- });
696
- },
697
- },
698
- },
699
- });
700
- ```
701
-
702
- ## Configuration (`MastraMCPServerDefinition`)
703
-
704
- The `server` parameter for both `MastraMCPClient` and `MCPConfiguration` uses the `MastraMCPServerDefinition` type. The client automatically detects the transport type based on the provided parameters:
705
-
706
- - If `command` is provided, it uses the Stdio transport.
707
- - If `url` is provided, it first attempts to use the Streamable HTTP transport and falls back to the legacy SSE transport if the initial connection fails.
708
-
709
- Here are the available options within `MastraMCPServerDefinition`:
710
-
711
- - **`command`**: (Optional, string) For Stdio servers: The command to execute.
712
- - **`args`**: (Optional, string[]) For Stdio servers: Arguments to pass to the command.
713
- - **`env`**: (Optional, Record<string, string>) For Stdio servers: Environment variables to set for the command.
714
- - **`url`**: (Optional, URL) For HTTP servers (Streamable HTTP or SSE): The URL of the server.
715
- - **`fetch`**: (Optional, FetchLike) For HTTP servers: Custom fetch implementation used for all network requests. When provided, this function will be used for all HTTP requests, allowing you to add dynamic authentication headers (e.g., refreshing bearer tokens), customize request behavior per-request, or intercept and modify requests/responses. When `fetch` is provided, `requestInit`, `eventSourceInit`, and `authProvider` become optional, as you can handle these concerns within your custom fetch function.
716
- - **`requestInit`**: (Optional, RequestInit) For HTTP servers: Request configuration for the fetch API. Used for the initial Streamable HTTP connection attempt and subsequent POST requests. Also used for the initial SSE connection attempt. Optional when `fetch` is provided.
717
- - **`eventSourceInit`**: (Optional, EventSourceInit) **Only** for the legacy SSE fallback: Custom fetch configuration for SSE connections. Required when using custom headers with SSE. Optional when `fetch` is provided.
718
- - **`authProvider`**: (Optional, OAuthClientProvider) For HTTP servers: OAuth authentication provider for automatic token refresh. Automatically passed to both Streamable HTTP and SSE transports. Optional when `fetch` is provided.
719
- - **`logger`**: (Optional, LogHandler) Optional additional handler for logging.
720
- - **`timeout`**: (Optional, number) Server-specific timeout in milliseconds, overriding the global client/configuration timeout.
721
- - **`capabilities`**: (Optional, ClientCapabilities) Server-specific capabilities configuration.
722
- - **`enableServerLogs`**: (Optional, boolean, default: `true`) Whether to enable logging for this server.
723
-
724
- ## Features
725
-
726
- - Standard MCP client implementation
727
- - Automatic tool conversion to Mastra format
728
- - Resource discovery and management
729
- - Multiple transport layers with automatic detection:
730
- - Stdio-based for local servers (`command`)
731
- - HTTP-based for remote servers (`url`): Tries Streamable HTTP first, falls back to legacy SSE.
732
- - OAuth authentication with automatic token refresh (`authProvider`)
733
- - Manual authentication headers for static tokens (`requestInit`, `eventSourceInit`)
734
- - Per-server logging capability using all standard MCP log levels
735
- - Automatic error handling and logging
736
- - Tool execution with context
737
-
738
- ## Methods
739
-
740
- ### `connect()`
741
-
742
- Establishes connection with the MCP server.
743
-
744
- ### `disconnect()`
745
-
746
- Closes the connection with the MCP server.
747
-
748
- ### `resources()`
749
-
750
- Lists available resources from the MCP server.
751
-
752
- ### `tools()`
753
-
754
- Retrieves and converts MCP tools to Mastra-compatible format.
755
-
756
- ## Tool Conversion
757
-
758
- The package automatically converts MCP tools to Mastra's format:
759
-
760
- ```typescript
761
- const tools = await client.tools();
762
- // Returns: { [toolName: string]: MastraTool }
763
-
764
- // Each tool includes:
765
- // - Converted JSON schema
766
- // - Mastra-compatible execution wrapper
767
- // - Error handling
768
- // - Automatic context passing
769
- ```
770
-
771
- ## Error Handling
772
-
773
- The client includes comprehensive error handling:
774
-
775
- - Connection errors
776
- - Tool execution errors
777
- - Resource listing errors
778
- - Schema conversion errors
17
+ Mastra currently supports two MCP classes:
779
18
 
780
- ## Related Links
19
+ - `MCPClient`: Connects to one or many MCP servers to access their tools, resources, prompts, and handle elicitation requests.
20
+ - `MCPServer`: Exposes Mastra tools, agents, workflows, prompts, and resources to MCP-compatible clients.
781
21
 
782
- - [Model Context Protocol Specification](https://modelcontextprotocol.io/specification)
783
- - [MCP Authorization Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization)
784
- - [RFC 9728 - OAuth 2.0 Protected Resource Metadata](https://www.rfc-editor.org/rfc/rfc9728.html)
785
- - [@modelcontextprotocol/sdk Documentation](https://github.com/modelcontextprotocol/typescript-sdk)
786
- - [Mastra Docs: Using MCP With Mastra](/docs/agents/mcp-guide)
787
- - [Mastra Docs: MastraMCPClient Reference](/reference/tools/client)
22
+ Read the [official MCP documentation](https://mastra.ai/docs/mcp/overview) to learn more.