@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.
@@ -11,39 +11,40 @@ It supports both [stdio (subprocess) and SSE (HTTP) MCP transports](https://mode
11
11
  To create a new `MCPServer`, you need to provide some basic information about your server, the tools it will offer, and optionally, any agents you want to expose as tools.
12
12
 
13
13
  ```typescript
14
- import { Agent } from "@mastra/core/agent";
15
- import { createTool } from "@mastra/core/tools";
16
- import { MCPServer } from "@mastra/mcp";
17
- import { z } from "zod";
18
- import { dataProcessingWorkflow } from "../workflows/dataProcessingWorkflow";
14
+ import { Agent } from '@mastra/core/agent'
15
+ import { createTool } from '@mastra/core/tools'
16
+ import { MCPServer } from '@mastra/mcp'
17
+ import { z } from 'zod'
18
+ import { dataProcessingWorkflow } from '../workflows/dataProcessingWorkflow'
19
19
 
20
20
  const myAgent = new Agent({
21
- id: "my-example-agent",
22
- name: "MyExampleAgent",
23
- description: "A generalist to help with basic questions."
24
- instructions: "You are a helpful assistant.",
25
- model: "openai/gpt-5.1",
26
- });
21
+ id: 'my-example-agent',
22
+ name: 'MyExampleAgent',
23
+ description: 'A generalist to help with basic questions.',
24
+ instructions: 'You are a helpful assistant.',
25
+ model: 'openai/gpt-5.1',
26
+ })
27
27
 
28
28
  const weatherTool = createTool({
29
- id: "getWeather",
30
- description: "Gets the current weather for a location.",
29
+ id: 'getWeather',
30
+ description: 'Gets the current weather for a location.',
31
31
  inputSchema: z.object({ location: z.string() }),
32
- execute: async (inputData) => `Weather in ${inputData.location} is sunny.`,
33
- });
32
+ execute: async inputData => `Weather in ${inputData.location} is sunny.`,
33
+ })
34
34
 
35
35
  const server = new MCPServer({
36
- id: "my-custom-server",
37
- name: "My Custom Server",
38
- version: "1.0.0",
39
- description: "A server that provides weather data and agent capabilities",
40
- instructions: "Use the available tools to help users with weather information and data processing tasks.",
36
+ id: 'my-custom-server',
37
+ name: 'My Custom Server',
38
+ version: '1.0.0',
39
+ description: 'A server that provides weather data and agent capabilities',
40
+ instructions:
41
+ 'Use the available tools to help users with weather information and data processing tasks.',
41
42
  tools: { weatherTool },
42
43
  agents: { myAgent }, // this agent will become tool "ask_myAgent"
43
44
  workflows: {
44
45
  dataProcessingWorkflow, // this workflow will become tool "run_dataProcessingWorkflow"
45
- }
46
- });
46
+ },
47
+ })
47
48
  ```
48
49
 
49
50
  ### Configuration Properties
@@ -121,42 +122,42 @@ Tools exposed through `MCPServer` can access MCP request context (authentication
121
122
  **Universal pattern** (works in both contexts):
122
123
 
123
124
  ```typescript
124
- const mcpExtra = context?.mcp?.extra ?? context?.requestContext?.get("mcp.extra");
125
- const authInfo = mcpExtra?.authInfo;
125
+ const mcpExtra = context?.mcp?.extra ?? context?.requestContext?.get('mcp.extra')
126
+ const authInfo = mcpExtra?.authInfo
126
127
  ```
127
128
 
128
129
  #### Example: Tool that works in both contexts
129
130
 
130
131
  ```typescript
131
- import { createTool } from "@mastra/core/tools";
132
- import { z } from "zod";
132
+ import { createTool } from '@mastra/core/tools'
133
+ import { z } from 'zod'
133
134
 
134
135
  const fetchUserData = createTool({
135
- id: "fetchUserData",
136
- description: "Fetches user data using authentication from MCP context",
136
+ id: 'fetchUserData',
137
+ description: 'Fetches user data using authentication from MCP context',
137
138
  inputSchema: z.object({
138
- userId: z.string().describe("The ID of the user to fetch"),
139
+ userId: z.string().describe('The ID of the user to fetch'),
139
140
  }),
140
141
  execute: async (inputData, context) => {
141
142
  // Access MCP authentication context
142
143
  // When called directly via MCP: context.mcp.extra
143
144
  // When called via agent: context.requestContext.get('mcp.extra')
144
- const mcpExtra = context?.mcp?.extra || context?.requestContext?.get("mcp.extra");
145
- const authInfo = mcpExtra?.authInfo;
145
+ const mcpExtra = context?.mcp?.extra || context?.requestContext?.get('mcp.extra')
146
+ const authInfo = mcpExtra?.authInfo
146
147
 
147
148
  if (!authInfo?.token) {
148
- throw new Error("Authentication required");
149
+ throw new Error('Authentication required')
149
150
  }
150
151
 
151
152
  const response = await fetch(`https://api.example.com/users/${inputData.userId}`, {
152
153
  headers: {
153
154
  Authorization: `Bearer ${authInfo.token}`,
154
155
  },
155
- });
156
+ })
156
157
 
157
- return response.json();
158
+ return response.json()
158
159
  },
159
- });
160
+ })
160
161
  ```
161
162
 
162
163
  ## Methods
@@ -175,12 +176,14 @@ Here's how you would start the server using stdio:
175
176
 
176
177
  ```typescript
177
178
  const server = new MCPServer({
178
- id: "my-server",
179
- name: "My Server",
180
- version: "1.0.0",
181
- tools: { /* ... */ },
182
- });
183
- await server.startStdio();
179
+ id: 'my-server',
180
+ name: 'My Server',
181
+ version: '1.0.0',
182
+ tools: {
183
+ /* ... */
184
+ },
185
+ })
186
+ await server.startStdio()
184
187
  ```
185
188
 
186
189
  ### startSSE()
@@ -206,21 +209,21 @@ async startSSE({
206
209
  Here's an example of how you might use `startSSE` within an HTTP server request handler. In this example an MCP client could connect to your MCP server at `http://localhost:1234/sse`:
207
210
 
208
211
  ```typescript
209
- import http from "http";
212
+ import http from 'http'
210
213
 
211
214
  const httpServer = http.createServer(async (req, res) => {
212
215
  await server.startSSE({
213
- url: new URL(req.url || "", `http://localhost:1234`),
214
- ssePath: "/sse",
215
- messagePath: "/message",
216
+ url: new URL(req.url || '', `http://localhost:1234`),
217
+ ssePath: '/sse',
218
+ messagePath: '/message',
216
219
  req,
217
220
  res,
218
- });
219
- });
221
+ })
222
+ })
220
223
 
221
224
  httpServer.listen(PORT, () => {
222
- console.log(`HTTP server listening on port ${PORT}`);
223
- });
225
+ console.log(`HTTP server listening on port ${PORT}`)
226
+ })
224
227
  ```
225
228
 
226
229
  Here are the details for the values needed by the `startSSE` method:
@@ -258,21 +261,21 @@ async startHonoSSE({
258
261
  Here's an example of how you might use `startHonoSSE` within an HTTP server request handler. In this example an MCP client could connect to your MCP server at `http://localhost:1234/hono-sse`:
259
262
 
260
263
  ```typescript
261
- import http from "http";
264
+ import http from 'http'
262
265
 
263
266
  const httpServer = http.createServer(async (req, res) => {
264
267
  await server.startHonoSSE({
265
- url: new URL(req.url || "", `http://localhost:1234`),
266
- ssePath: "/hono-sse",
267
- messagePath: "/message",
268
+ url: new URL(req.url || '', `http://localhost:1234`),
269
+ ssePath: '/hono-sse',
270
+ messagePath: '/message',
268
271
  req,
269
272
  res,
270
- });
271
- });
273
+ })
274
+ })
272
275
 
273
276
  httpServer.listen(PORT, () => {
274
- console.log(`HTTP server listening on port ${PORT}`);
275
- });
277
+ console.log(`HTTP server listening on port ${PORT}`)
278
+ })
276
279
  ```
277
280
 
278
281
  Here are the details for the values needed by the `startHonoSSE` method:
@@ -310,68 +313,68 @@ async startHTTP({
310
313
  Here's an example of how you might use `startHTTP` within an HTTP server request handler. In this example an MCP client could connect to your MCP server at `http://localhost:1234/http`:
311
314
 
312
315
  ```typescript
313
- import http from "http";
316
+ import http from 'http'
314
317
 
315
318
  const httpServer = http.createServer(async (req, res) => {
316
319
  await server.startHTTP({
317
- url: new URL(req.url || "", "http://localhost:1234"),
320
+ url: new URL(req.url || '', 'http://localhost:1234'),
318
321
  httpPath: `/mcp`,
319
322
  req,
320
323
  res,
321
324
  options: {
322
325
  sessionIdGenerator: () => randomUUID(),
323
326
  },
324
- });
325
- });
327
+ })
328
+ })
326
329
 
327
330
  httpServer.listen(PORT, () => {
328
- console.log(`HTTP server listening on port ${PORT}`);
329
- });
331
+ console.log(`HTTP server listening on port ${PORT}`)
332
+ })
330
333
  ```
331
334
 
332
335
  For **serverless environments** (Supabase Edge Functions, Cloudflare Workers, Vercel Edge, etc.), use `serverless: true` to enable stateless operation:
333
336
 
334
337
  ```typescript
335
338
  // Supabase Edge Function example
336
- import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
337
- import { MCPServer } from "@mastra/mcp";
339
+ import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
340
+ import { MCPServer } from '@mastra/mcp'
338
341
  // Note: You will need to convert req/res format from Deno to Node
339
- import { toReqRes, toFetchResponse } from "fetch-to-node";
342
+ import { toReqRes, toFetchResponse } from 'fetch-to-node'
340
343
 
341
344
  const server = new MCPServer({
342
- id: "my-serverless-mcp",
343
- name: "My Serverless MCP",
344
- version: "1.0.0",
345
- tools: { /* your tools */ },
346
- });
345
+ id: 'my-serverless-mcp',
346
+ name: 'My Serverless MCP',
347
+ version: '1.0.0',
348
+ tools: {
349
+ /* your tools */
350
+ },
351
+ })
347
352
 
348
- serve(async (req) => {
349
- const url = new URL(req.url);
353
+ serve(async req => {
354
+ const url = new URL(req.url)
350
355
 
351
- if (url.pathname === "/mcp") {
356
+ if (url.pathname === '/mcp') {
352
357
  // Convert Deno Request to Node.js-compatible format
353
- const { req: nodeReq, res: nodeRes } = toReqRes(req);
358
+ const { req: nodeReq, res: nodeRes } = toReqRes(req)
354
359
 
355
360
  await server.startHTTP({
356
361
  url,
357
- httpPath: "/mcp",
362
+ httpPath: '/mcp',
358
363
  req: nodeReq,
359
364
  res: nodeRes,
360
365
  options: {
361
366
  serverless: true, // ← Enable stateless mode for serverless
362
367
  },
363
- });
368
+ })
364
369
 
365
- return toFetchResponse(nodeRes);
370
+ return toFetchResponse(nodeRes)
366
371
  }
367
372
 
368
- return new Response("Not found", { status: 404 });
369
- });
373
+ return new Response('Not found', { status: 404 })
374
+ })
370
375
  ```
371
376
 
372
- > **Info:** **When to use `serverless: true`**
373
- >
374
- > Use `serverless: true` when deploying to environments where each request runs in a fresh, stateless execution context:
377
+ > **When to use serverless: true:** Use `serverless: true` when deploying to environments where each request runs in a fresh, stateless execution context:
375
378
  >
376
379
  > - Supabase Edge Functions
377
380
  > - Cloudflare Workers
@@ -550,70 +553,66 @@ The `resources` option takes an object of type `MCPServerResources`. This type d
550
553
  ```typescript
551
554
  export type MCPServerResources = {
552
555
  // Callback to list available resources
553
- listResources: () => Promise<Resource[]>;
556
+ listResources: () => Promise<Resource[]>
554
557
 
555
558
  // Callback to get the content of a specific resource
556
559
  getResourceContent: ({
557
560
  uri,
558
561
  }: {
559
- uri: string;
560
- }) => Promise<MCPServerResourceContent | MCPServerResourceContent[]>;
562
+ uri: string
563
+ }) => Promise<MCPServerResourceContent | MCPServerResourceContent[]>
561
564
 
562
565
  // Optional callback to list available resource templates
563
- resourceTemplates?: () => Promise<ResourceTemplate[]>;
564
- };
566
+ resourceTemplates?: () => Promise<ResourceTemplate[]>
567
+ }
565
568
 
566
- export type MCPServerResourceContent = { text?: string } | { blob?: string };
569
+ export type MCPServerResourceContent = { text?: string } | { blob?: string }
567
570
  ```
568
571
 
569
572
  Example:
570
573
 
571
574
  ```typescript
572
- import { MCPServer } from "@mastra/mcp";
573
- import type {
574
- MCPServerResourceContent,
575
- Resource,
576
- ResourceTemplate,
577
- } from "@mastra/mcp";
575
+ import { MCPServer } from '@mastra/mcp'
576
+ import type { MCPServerResourceContent, Resource, ResourceTemplate } from '@mastra/mcp'
578
577
 
579
578
  // Resources/resource templates will generally be dynamically fetched.
580
579
  const myResources: Resource[] = [
581
- { uri: "file://data/123.txt", name: "Data File", mimeType: "text/plain" },
582
- ];
580
+ { uri: 'file://data/123.txt', name: 'Data File', mimeType: 'text/plain' },
581
+ ]
583
582
 
584
583
  const myResourceContents: Record<string, MCPServerResourceContent> = {
585
- "file://data.txt/123": { text: "This is the content of the data file." },
586
- };
584
+ 'file://data.txt/123': { text: 'This is the content of the data file.' },
585
+ }
587
586
 
588
587
  const myResourceTemplates: ResourceTemplate[] = [
589
588
  {
590
- uriTemplate: "file://data/{id}",
591
- name: "Data File",
592
- description: "A file containing data.",
593
- mimeType: "text/plain",
589
+ uriTemplate: 'file://data/{id}',
590
+ name: 'Data File',
591
+ description: 'A file containing data.',
592
+ mimeType: 'text/plain',
594
593
  },
595
- ];
594
+ ]
596
595
 
597
596
  const myResourceHandlers: MCPServerResources = {
598
597
  listResources: async () => myResources,
599
598
  getResourceContent: async ({ uri }) => {
600
599
  if (myResourceContents[uri]) {
601
- return myResourceContents[uri];
600
+ return myResourceContents[uri]
602
601
  }
603
- throw new Error(`Resource content not found for ${uri}`);
602
+ throw new Error(`Resource content not found for ${uri}`)
604
603
  },
605
604
  resourceTemplates: async () => myResourceTemplates,
606
- };
605
+ }
607
606
 
608
607
  const serverWithResources = new MCPServer({
609
- id: "resourceful-server",
610
- name: "Resourceful Server",
611
- version: "1.0.0",
608
+ id: 'resourceful-server',
609
+ name: 'Resourceful Server',
610
+ version: '1.0.0',
612
611
  tools: {
613
612
  /* ... your tools ... */
614
613
  },
615
614
  resources: myResourceHandlers,
616
- });
615
+ })
617
616
  ```
618
617
 
619
618
  ### Notifying Clients of Resource Changes
@@ -632,7 +631,7 @@ Example:
632
631
 
633
632
  ```typescript
634
633
  // After updating the content of 'file://data.txt'
635
- await serverWithResources.resources.notifyUpdated({ uri: "file://data.txt" });
634
+ await serverWithResources.resources.notifyUpdated({ uri: 'file://data.txt' })
636
635
  ```
637
636
 
638
637
  #### `server.resources.notifyListChanged()`
@@ -647,7 +646,7 @@ Example:
647
646
 
648
647
  ```typescript
649
648
  // After adding a new resource to the list managed by 'myResourceHandlers.listResources'
650
- await serverWithResources.resources.notifyListChanged();
649
+ await serverWithResources.resources.notifyListChanged()
651
650
  ```
652
651
 
653
652
  ## Prompt Handling
@@ -665,7 +664,7 @@ The `prompts` option takes an object of type `MCPServerPrompts`. This type defin
665
664
  ```typescript
666
665
  export type MCPServerPrompts = {
667
666
  // Callback to list available prompts
668
- listPrompts: () => Promise<Prompt[]>;
667
+ listPrompts: () => Promise<Prompt[]>
669
668
 
670
669
  // Callback to get the messages/content for a specific prompt
671
670
  getPromptMessages?: ({
@@ -673,80 +672,78 @@ export type MCPServerPrompts = {
673
672
  version,
674
673
  args,
675
674
  }: {
676
- name: string;
677
- version?: string;
678
- args?: any;
679
- }) => Promise<{ prompt: Prompt; messages: PromptMessage[] }>;
680
- };
675
+ name: string
676
+ version?: string
677
+ args?: any
678
+ }) => Promise<{ prompt: Prompt; messages: PromptMessage[] }>
679
+ }
681
680
  ```
682
681
 
683
682
  Example:
684
683
 
685
684
  ```typescript
686
- import { MCPServer } from "@mastra/mcp";
687
- import type { Prompt, PromptMessage, MCPServerPrompts } from "@mastra/mcp";
685
+ import { MCPServer } from '@mastra/mcp'
686
+ import type { Prompt, PromptMessage, MCPServerPrompts } from '@mastra/mcp'
688
687
 
689
688
  const prompts: Prompt[] = [
690
689
  {
691
- name: "analyze-code",
692
- description: "Analyze code for improvements",
693
- version: "v1",
690
+ name: 'analyze-code',
691
+ description: 'Analyze code for improvements',
692
+ version: 'v1',
694
693
  },
695
694
  {
696
- name: "analyze-code",
697
- description: "Analyze code for improvements (new logic)",
698
- version: "v2",
695
+ name: 'analyze-code',
696
+ description: 'Analyze code for improvements (new logic)',
697
+ version: 'v2',
699
698
  },
700
- ];
699
+ ]
701
700
 
702
701
  const myPromptHandlers: MCPServerPrompts = {
703
702
  listPrompts: async () => prompts,
704
703
  getPromptMessages: async ({ name, version, args }) => {
705
- if (name === "analyze-code") {
706
- if (version === "v2") {
707
- const prompt = prompts.find(
708
- (p) => p.name === name && p.version === "v2",
709
- );
710
- if (!prompt) throw new Error("Prompt version not found");
704
+ if (name === 'analyze-code') {
705
+ if (version === 'v2') {
706
+ const prompt = prompts.find(p => p.name === name && p.version === 'v2')
707
+ if (!prompt) throw new Error('Prompt version not found')
711
708
  return {
712
709
  prompt,
713
710
  messages: [
714
711
  {
715
- role: "user",
712
+ role: 'user',
716
713
  content: {
717
- type: "text",
714
+ type: 'text',
718
715
  text: `Analyze this code with the new logic: ${args.code}`,
719
716
  },
720
717
  },
721
718
  ],
722
- };
719
+ }
723
720
  }
724
721
  // Default or v1
725
- const prompt = prompts.find((p) => p.name === name && p.version === "v1");
726
- if (!prompt) throw new Error("Prompt version not found");
722
+ const prompt = prompts.find(p => p.name === name && p.version === 'v1')
723
+ if (!prompt) throw new Error('Prompt version not found')
727
724
  return {
728
725
  prompt,
729
726
  messages: [
730
727
  {
731
- role: "user",
732
- content: { type: "text", text: `Analyze this code: ${args.code}` },
728
+ role: 'user',
729
+ content: { type: 'text', text: `Analyze this code: ${args.code}` },
733
730
  },
734
731
  ],
735
- };
732
+ }
736
733
  }
737
- throw new Error("Prompt not found");
734
+ throw new Error('Prompt not found')
738
735
  },
739
- };
736
+ }
740
737
 
741
738
  const serverWithPrompts = new MCPServer({
742
- id: "promptful-server",
743
- name: "Promptful Server",
744
- version: "1.0.0",
739
+ id: 'promptful-server',
740
+ name: 'Promptful Server',
741
+ version: '1.0.0',
745
742
  tools: {
746
743
  /* ... */
747
744
  },
748
745
  prompts: myPromptHandlers,
749
- });
746
+ })
750
747
  ```
751
748
 
752
749
  ### Notifying Clients of Prompt Changes
@@ -758,7 +755,7 @@ If the available prompts change, your server can notify connected clients:
758
755
  Call this method when the overall list of available prompts has changed (e.g., a prompt was added or removed). This will send a `notifications/prompts/list_changed` message to clients, prompting them to re-fetch the list of prompts.
759
756
 
760
757
  ```typescript
761
- await serverWithPrompts.prompts.notifyListChanged();
758
+ await serverWithPrompts.prompts.notifyListChanged()
762
759
  ```
763
760
 
764
761
  ### Best Practices for Prompt Handling
@@ -798,19 +795,19 @@ execute: async (inputData, context) => {
798
795
 
799
796
  // Access authentication information (when available)
800
797
  if (context.mcp?.extra?.authInfo) {
801
- console.log("Authenticated request from:", context.mcp.extra.authInfo.clientId);
798
+ console.log('Authenticated request from:', context.mcp.extra.authInfo.clientId)
802
799
  }
803
800
 
804
801
  // Use elicitation capabilities
805
802
  const result = await context.mcp.elicitation.sendRequest({
806
- message: "Please provide information",
803
+ message: 'Please provide information',
807
804
  requestedSchema: {
808
805
  /* schema */
809
806
  },
810
- });
807
+ })
811
808
 
812
- return result;
813
- };
809
+ return result
810
+ }
814
811
  ```
815
812
 
816
813
  ### How Elicitation Works
@@ -829,75 +826,72 @@ A common use case is during tool execution. When a tool needs user input, it can
829
826
  Here's an example of a tool that uses elicitation to collect user contact information:
830
827
 
831
828
  ```typescript
832
- import { MCPServer } from "@mastra/mcp";
833
- import { createTool } from "@mastra/core/tools";
834
- import { z } from "zod";
829
+ import { MCPServer } from '@mastra/mcp'
830
+ import { createTool } from '@mastra/core/tools'
831
+ import { z } from 'zod'
835
832
 
836
833
  const server = new MCPServer({
837
- id: "interactive-server",
838
- name: "Interactive Server",
839
- version: "1.0.0",
834
+ id: 'interactive-server',
835
+ name: 'Interactive Server',
836
+ version: '1.0.0',
840
837
  tools: {
841
838
  collectContactInfo: createTool({
842
- id: "collectContactInfo",
843
- description: "Collects user contact information through elicitation",
839
+ id: 'collectContactInfo',
840
+ description: 'Collects user contact information through elicitation',
844
841
  inputSchema: z.object({
845
- reason: z
846
- .string()
847
- .optional()
848
- .describe("Reason for collecting contact info"),
842
+ reason: z.string().optional().describe('Reason for collecting contact info'),
849
843
  }),
850
844
  execute: async (inputData, context) => {
851
- const { reason } = inputData;
845
+ const { reason } = inputData
852
846
 
853
847
  // Log session info if available
854
- console.log("Request from session:", context.mcp?.extra?.sessionId);
848
+ console.log('Request from session:', context.mcp?.extra?.sessionId)
855
849
 
856
850
  try {
857
851
  // Request user input via elicitation
858
852
  const result = await context.mcp.elicitation.sendRequest({
859
853
  message: reason
860
854
  ? `Please provide your contact information. ${reason}`
861
- : "Please provide your contact information",
855
+ : 'Please provide your contact information',
862
856
  requestedSchema: {
863
- type: "object",
857
+ type: 'object',
864
858
  properties: {
865
859
  name: {
866
- type: "string",
867
- title: "Full Name",
868
- description: "Your full name",
860
+ type: 'string',
861
+ title: 'Full Name',
862
+ description: 'Your full name',
869
863
  },
870
864
  email: {
871
- type: "string",
872
- title: "Email Address",
873
- description: "Your email address",
874
- format: "email",
865
+ type: 'string',
866
+ title: 'Email Address',
867
+ description: 'Your email address',
868
+ format: 'email',
875
869
  },
876
870
  phone: {
877
- type: "string",
878
- title: "Phone Number",
879
- description: "Your phone number (optional)",
871
+ type: 'string',
872
+ title: 'Phone Number',
873
+ description: 'Your phone number (optional)',
880
874
  },
881
875
  },
882
- required: ["name", "email"],
876
+ required: ['name', 'email'],
883
877
  },
884
- });
878
+ })
885
879
 
886
880
  // Handle the user's response
887
- if (result.action === "accept") {
888
- return `Contact information collected: ${JSON.stringify(result.content, null, 2)}`;
889
- } else if (result.action === "decline") {
890
- return "Contact information collection was declined by the user.";
881
+ if (result.action === 'accept') {
882
+ return `Contact information collected: ${JSON.stringify(result.content, null, 2)}`
883
+ } else if (result.action === 'decline') {
884
+ return 'Contact information collection was declined by the user.'
891
885
  } else {
892
- return "Contact information collection was cancelled by the user.";
886
+ return 'Contact information collection was cancelled by the user.'
893
887
  }
894
888
  } catch (error) {
895
- return `Error collecting contact information: ${error}`;
889
+ return `Error collecting contact information: ${error}`
896
890
  }
897
891
  },
898
892
  }),
899
893
  },
900
- });
894
+ })
901
895
  ```
902
896
 
903
897
  ### Elicitation Request Schema
@@ -983,9 +977,9 @@ The `ElicitResult` type:
983
977
 
984
978
  ```typescript
985
979
  type ElicitResult = {
986
- action: "accept" | "decline" | "cancel";
987
- content?: any; // Only present when action is 'accept'
988
- };
980
+ action: 'accept' | 'decline' | 'cancel'
981
+ content?: any // Only present when action is 'accept'
982
+ }
989
983
  ```
990
984
 
991
985
  ## OAuth Protection
@@ -993,41 +987,43 @@ type ElicitResult = {
993
987
  To protect your MCP server with OAuth authentication per the [MCP Auth Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization), use the `createOAuthMiddleware` function:
994
988
 
995
989
  ```typescript
996
- import http from "node:http";
997
- import { MCPServer, createOAuthMiddleware, createStaticTokenValidator } from "@mastra/mcp";
990
+ import http from 'node:http'
991
+ import { MCPServer, createOAuthMiddleware, createStaticTokenValidator } from '@mastra/mcp'
998
992
 
999
993
  const mcpServer = new MCPServer({
1000
- id: "protected-server",
1001
- name: "Protected MCP Server",
1002
- version: "1.0.0",
1003
- tools: { /* your tools */ },
1004
- });
994
+ id: 'protected-server',
995
+ name: 'Protected MCP Server',
996
+ version: '1.0.0',
997
+ tools: {
998
+ /* your tools */
999
+ },
1000
+ })
1005
1001
 
1006
1002
  // Create OAuth middleware
1007
1003
  const oauthMiddleware = createOAuthMiddleware({
1008
1004
  oauth: {
1009
- resource: "https://mcp.example.com/mcp",
1010
- authorizationServers: ["https://auth.example.com"],
1011
- scopesSupported: ["mcp:read", "mcp:write"],
1012
- resourceName: "My Protected MCP Server",
1013
- validateToken: createStaticTokenValidator(["allowed-token-1"]),
1005
+ resource: 'https://mcp.example.com/mcp',
1006
+ authorizationServers: ['https://auth.example.com'],
1007
+ scopesSupported: ['mcp:read', 'mcp:write'],
1008
+ resourceName: 'My Protected MCP Server',
1009
+ validateToken: createStaticTokenValidator(['allowed-token-1']),
1014
1010
  },
1015
- mcpPath: "/mcp",
1016
- });
1011
+ mcpPath: '/mcp',
1012
+ })
1017
1013
 
1018
1014
  // Create HTTP server with OAuth protection
1019
1015
  const httpServer = http.createServer(async (req, res) => {
1020
- const url = new URL(req.url || "", "https://mcp.example.com");
1016
+ const url = new URL(req.url || '', 'https://mcp.example.com')
1021
1017
 
1022
1018
  // Apply OAuth middleware first
1023
- const result = await oauthMiddleware(req, res, url);
1024
- if (!result.proceed) return; // Middleware handled response (401, metadata, etc.)
1019
+ const result = await oauthMiddleware(req, res, url)
1020
+ if (!result.proceed) return // Middleware handled response (401, metadata, etc.)
1025
1021
 
1026
1022
  // Token is valid, proceed to MCP handler
1027
- await mcpServer.startHTTP({ url, httpPath: "/mcp", req, res });
1028
- });
1023
+ await mcpServer.startHTTP({ url, httpPath: '/mcp', req, res })
1024
+ })
1029
1025
 
1030
- httpServer.listen(3000);
1026
+ httpServer.listen(3000)
1031
1027
  ```
1032
1028
 
1033
1029
  The middleware automatically:
@@ -1041,38 +1037,38 @@ The middleware automatically:
1041
1037
  For production, use proper token validation:
1042
1038
 
1043
1039
  ```typescript
1044
- import { createOAuthMiddleware, createIntrospectionValidator } from "@mastra/mcp";
1040
+ import { createOAuthMiddleware, createIntrospectionValidator } from '@mastra/mcp'
1045
1041
 
1046
1042
  // Option 1: Token introspection (RFC 7662)
1047
1043
  const middleware = createOAuthMiddleware({
1048
1044
  oauth: {
1049
- resource: "https://mcp.example.com/mcp",
1050
- authorizationServers: ["https://auth.example.com"],
1051
- validateToken: createIntrospectionValidator(
1052
- "https://auth.example.com/oauth/introspect",
1053
- { clientId: "mcp-server", clientSecret: "secret" }
1054
- ),
1045
+ resource: 'https://mcp.example.com/mcp',
1046
+ authorizationServers: ['https://auth.example.com'],
1047
+ validateToken: createIntrospectionValidator('https://auth.example.com/oauth/introspect', {
1048
+ clientId: 'mcp-server',
1049
+ clientSecret: 'secret',
1050
+ }),
1055
1051
  },
1056
- });
1052
+ })
1057
1053
 
1058
1054
  // Option 2: Custom validation (JWT, database lookup, etc.)
1059
1055
  const customMiddleware = createOAuthMiddleware({
1060
1056
  oauth: {
1061
- resource: "https://mcp.example.com/mcp",
1062
- authorizationServers: ["https://auth.example.com"],
1057
+ resource: 'https://mcp.example.com/mcp',
1058
+ authorizationServers: ['https://auth.example.com'],
1063
1059
  validateToken: async (token, resource) => {
1064
- const decoded = await verifyJWT(token);
1060
+ const decoded = await verifyJWT(token)
1065
1061
  if (!decoded) {
1066
- return { valid: false, error: "invalid_token" };
1062
+ return { valid: false, error: 'invalid_token' }
1067
1063
  }
1068
1064
  return {
1069
1065
  valid: true,
1070
- scopes: decoded.scope?.split(" ") || [],
1066
+ scopes: decoded.scope?.split(' ') || [],
1071
1067
  subject: decoded.sub,
1072
- };
1068
+ }
1073
1069
  },
1074
1070
  },
1075
- });
1071
+ })
1076
1072
  ```
1077
1073
 
1078
1074
  ### OAuth Middleware Options
@@ -1106,14 +1102,14 @@ req.auth = { ... } → context?.mcp?.extra?.authInfo.extra = { ... }
1106
1102
  To pass data to your tools, populate `req.auth` on the Node.js request object in your HTTP server middleware before calling `server.startHTTP()`.
1107
1103
 
1108
1104
  ```typescript
1109
- import express from "express";
1105
+ import express from 'express'
1110
1106
 
1111
- const app = express();
1107
+ const app = express()
1112
1108
 
1113
1109
  // Auth middleware - set req.auth before the MCP handler
1114
- app.use("/mcp", (req, res, next) => {
1115
- const token = req.headers.authorization?.replace("Bearer ", "");
1116
- const user = verifyToken(token);
1110
+ app.use('/mcp', (req, res, next) => {
1111
+ const token = req.headers.authorization?.replace('Bearer ', '')
1112
+ const user = verifyToken(token)
1117
1113
 
1118
1114
  // This entire object becomes context.mcp.extra.authInfo
1119
1115
  // @ts-ignore - req.auth is read by the MCP SDK
@@ -1121,14 +1117,14 @@ app.use("/mcp", (req, res, next) => {
1121
1117
  token,
1122
1118
  userId: user.userId,
1123
1119
  email: user.email,
1124
- };
1125
- next();
1126
- });
1127
-
1128
- app.all("/mcp", async (req, res) => {
1129
- const url = new URL(req.url, `http://${req.headers.host}`);
1130
- await server.startHTTP({ url, httpPath: "/mcp", req, res });
1131
- });
1120
+ }
1121
+ next()
1122
+ })
1123
+
1124
+ app.all('/mcp', async (req, res) => {
1125
+ const url = new URL(req.url, `http://${req.headers.host}`)
1126
+ await server.startHTTP({ url, httpPath: '/mcp', req, res })
1127
+ })
1132
1128
  ```
1133
1129
 
1134
1130
  ### Accessing Auth Data in Tools
@@ -1138,23 +1134,23 @@ The `req.auth` object is available as `context.mcp.extra.authInfo` in your tool'
1138
1134
  ```typescript
1139
1135
  execute: async (inputData, context) => {
1140
1136
  // Access the auth data you set in middleware
1141
- const authInfo = context?.mcp?.extra?.authInfo;
1137
+ const authInfo = context?.mcp?.extra?.authInfo
1142
1138
 
1143
1139
  if (!authInfo?.extra?.userId) {
1144
- return { error: "Authentication required" };
1140
+ return { error: 'Authentication required' }
1145
1141
  }
1146
1142
 
1147
1143
  // Use the auth data
1148
- console.log("User ID:", authInfo.extra.userId);
1149
- console.log("Email:", authInfo.extra.email);
1144
+ console.log('User ID:', authInfo.extra.userId)
1145
+ console.log('Email:', authInfo.extra.email)
1150
1146
 
1151
- const response = await fetch("/api/data", {
1147
+ const response = await fetch('/api/data', {
1152
1148
  headers: { Authorization: `Bearer ${authInfo.token}` },
1153
1149
  signal: context?.mcp?.extra?.signal,
1154
- });
1150
+ })
1155
1151
 
1156
- return response.json();
1157
- };
1152
+ return response.json()
1153
+ }
1158
1154
  ```
1159
1155
 
1160
1156
  ### Passing `RequestContext` through to agent
@@ -1162,19 +1158,19 @@ execute: async (inputData, context) => {
1162
1158
  ```typescript
1163
1159
  execute: async (inputData, context) => {
1164
1160
  // Access the auth data you set in middleware
1165
- const authInfo = context?.mcp?.extra?.authInfo;
1161
+ const authInfo = context?.mcp?.extra?.authInfo
1166
1162
 
1167
1163
  const requestContext = context.requestContext || new RequestContext().set('someKey', authInfo)
1168
1164
 
1169
1165
  if (!authInfo?.extra?.userId) {
1170
- return { error: "Authentication required" };
1166
+ return { error: 'Authentication required' }
1171
1167
  }
1172
1168
 
1173
1169
  // Use the auth data
1174
- console.log("User ID:", authInfo.extra.userId);
1175
- console.log("Email:", authInfo.extra.email);
1170
+ console.log('User ID:', authInfo.extra.userId)
1171
+ console.log('Email:', authInfo.extra.email)
1176
1172
 
1177
- const agent = context?.mastra?.getAgentById('some-agent-id');
1173
+ const agent = context?.mastra?.getAgentById('some-agent-id')
1178
1174
 
1179
1175
  if (!agent) {
1180
1176
  return { error: "Agent 'some-agent-id' not found" }
@@ -1183,7 +1179,7 @@ execute: async (inputData, context) => {
1183
1179
  const response = await agent.generate(prompt, { requestContext })
1184
1180
 
1185
1181
  return response.text
1186
- };
1182
+ }
1187
1183
  ```
1188
1184
 
1189
1185
  ### The `extra` Object
@@ -1203,53 +1199,53 @@ The full `context.mcp.extra` object contains:
1203
1199
  Here's a complete example showing the data flow from middleware to tool:
1204
1200
 
1205
1201
  ```typescript
1206
- import express from "express";
1207
- import { MCPServer } from "@mastra/mcp";
1208
- import { createTool } from "@mastra/core/tools";
1209
- import { z } from "zod";
1202
+ import express from 'express'
1203
+ import { MCPServer } from '@mastra/mcp'
1204
+ import { createTool } from '@mastra/core/tools'
1205
+ import { z } from 'zod'
1210
1206
 
1211
1207
  const verifyToken = (token: string) => {
1212
1208
  // TODO: Implement token verification
1213
1209
  return {
1214
- userId: "123",
1215
- email: "test@test.com",
1216
- };
1217
- };
1210
+ userId: '123',
1211
+ email: 'test@test.com',
1212
+ }
1213
+ }
1218
1214
 
1219
1215
  // 1. Define your tool that uses auth context
1220
1216
  const getUserData = createTool({
1221
- id: "get-user-data",
1222
- description: "Fetches data for the authenticated user",
1217
+ id: 'get-user-data',
1218
+ description: 'Fetches data for the authenticated user',
1223
1219
  inputSchema: z.object({}),
1224
1220
  execute: async (inputData, context) => {
1225
- const authInfo = context?.mcp?.extra?.authInfo;
1221
+ const authInfo = context?.mcp?.extra?.authInfo
1226
1222
 
1227
1223
  if (!authInfo?.extra?.userId) {
1228
- return { error: "Authentication required" };
1224
+ return { error: 'Authentication required' }
1229
1225
  }
1230
1226
 
1231
1227
  // Access the data you set in middleware
1232
1228
  return {
1233
1229
  userId: authInfo.extra.userId,
1234
1230
  email: authInfo.extra.email,
1235
- };
1231
+ }
1236
1232
  },
1237
- });
1233
+ })
1238
1234
 
1239
1235
  // 2. Create the MCP server with your tools
1240
1236
  const server = new MCPServer({
1241
- id: "my-server",
1242
- name: "My Server",
1243
- version: "1.0.0",
1237
+ id: 'my-server',
1238
+ name: 'My Server',
1239
+ version: '1.0.0',
1244
1240
  tools: { getUserData },
1245
- });
1241
+ })
1246
1242
 
1247
1243
  // 3. Set up Express with auth middleware
1248
- const app = express();
1244
+ const app = express()
1249
1245
 
1250
- app.use("/mcp", (req, res, next) => {
1251
- const token = req.headers.authorization?.replace("Bearer ", "");
1252
- const user = verifyToken(token);
1246
+ app.use('/mcp', (req, res, next) => {
1247
+ const token = req.headers.authorization?.replace('Bearer ', '')
1248
+ const user = verifyToken(token)
1253
1249
 
1254
1250
  // This entire object becomes context.mcp.extra.authInfo
1255
1251
  // @ts-ignore - req.auth is read by the MCP SDK
@@ -1257,16 +1253,16 @@ app.use("/mcp", (req, res, next) => {
1257
1253
  token,
1258
1254
  userId: user.userId,
1259
1255
  email: user.email,
1260
- };
1261
- next();
1262
- });
1256
+ }
1257
+ next()
1258
+ })
1263
1259
 
1264
- app.all("/mcp", async (req, res) => {
1265
- const url = new URL(req.url, `http://${req.headers.host}`);
1266
- await server.startHTTP({ url, httpPath: "/mcp", req, res });
1267
- });
1260
+ app.all('/mcp', async (req, res) => {
1261
+ const url = new URL(req.url, `http://${req.headers.host}`)
1262
+ await server.startHTTP({ url, httpPath: '/mcp', req, res })
1263
+ })
1268
1264
 
1269
- app.listen(3000);
1265
+ app.listen(3000)
1270
1266
  ```
1271
1267
 
1272
1268
  ## Related Information