@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.
- package/CHANGELOG.md +11 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-mcp-overview.md +81 -78
- package/dist/docs/references/docs-mcp-publishing-mcp-server.md +15 -15
- package/dist/docs/references/reference-tools-mcp-client.md +223 -231
- package/dist/docs/references/reference-tools-mcp-server.md +280 -284
- package/dist/index.cjs +34 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +28 -12
- package/dist/index.js.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -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
|
|
15
|
-
import { createTool } from
|
|
16
|
-
import { MCPServer } from
|
|
17
|
-
import { z } from
|
|
18
|
-
import { dataProcessingWorkflow } from
|
|
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:
|
|
22
|
-
name:
|
|
23
|
-
description:
|
|
24
|
-
instructions:
|
|
25
|
-
model:
|
|
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:
|
|
30
|
-
description:
|
|
29
|
+
id: 'getWeather',
|
|
30
|
+
description: 'Gets the current weather for a location.',
|
|
31
31
|
inputSchema: z.object({ location: z.string() }),
|
|
32
|
-
execute: async
|
|
33
|
-
})
|
|
32
|
+
execute: async inputData => `Weather in ${inputData.location} is sunny.`,
|
|
33
|
+
})
|
|
34
34
|
|
|
35
35
|
const server = new MCPServer({
|
|
36
|
-
id:
|
|
37
|
-
name:
|
|
38
|
-
version:
|
|
39
|
-
description:
|
|
40
|
-
instructions:
|
|
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(
|
|
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
|
|
132
|
-
import { z } from
|
|
132
|
+
import { createTool } from '@mastra/core/tools'
|
|
133
|
+
import { z } from 'zod'
|
|
133
134
|
|
|
134
135
|
const fetchUserData = createTool({
|
|
135
|
-
id:
|
|
136
|
-
description:
|
|
136
|
+
id: 'fetchUserData',
|
|
137
|
+
description: 'Fetches user data using authentication from MCP context',
|
|
137
138
|
inputSchema: z.object({
|
|
138
|
-
userId: z.string().describe(
|
|
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(
|
|
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(
|
|
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:
|
|
179
|
-
name:
|
|
180
|
-
version:
|
|
181
|
-
tools: {
|
|
182
|
-
|
|
183
|
-
|
|
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
|
|
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 ||
|
|
214
|
-
ssePath:
|
|
215
|
-
messagePath:
|
|
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
|
|
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 ||
|
|
266
|
-
ssePath:
|
|
267
|
-
messagePath:
|
|
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
|
|
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 ||
|
|
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
|
|
337
|
-
import { MCPServer } from
|
|
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
|
|
342
|
+
import { toReqRes, toFetchResponse } from 'fetch-to-node'
|
|
340
343
|
|
|
341
344
|
const server = new MCPServer({
|
|
342
|
-
id:
|
|
343
|
-
name:
|
|
344
|
-
version:
|
|
345
|
-
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
|
|
349
|
-
const url = new URL(req.url)
|
|
353
|
+
serve(async req => {
|
|
354
|
+
const url = new URL(req.url)
|
|
350
355
|
|
|
351
|
-
if (url.pathname ===
|
|
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:
|
|
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(
|
|
369
|
-
})
|
|
373
|
+
return new Response('Not found', { status: 404 })
|
|
374
|
+
})
|
|
370
375
|
```
|
|
371
376
|
|
|
372
|
-
> **
|
|
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
|
|
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:
|
|
582
|
-
]
|
|
580
|
+
{ uri: 'file://data/123.txt', name: 'Data File', mimeType: 'text/plain' },
|
|
581
|
+
]
|
|
583
582
|
|
|
584
583
|
const myResourceContents: Record<string, MCPServerResourceContent> = {
|
|
585
|
-
|
|
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:
|
|
591
|
-
name:
|
|
592
|
-
description:
|
|
593
|
-
mimeType:
|
|
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:
|
|
610
|
-
name:
|
|
611
|
-
version:
|
|
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:
|
|
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
|
|
687
|
-
import type { Prompt, PromptMessage, MCPServerPrompts } from
|
|
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:
|
|
692
|
-
description:
|
|
693
|
-
version:
|
|
690
|
+
name: 'analyze-code',
|
|
691
|
+
description: 'Analyze code for improvements',
|
|
692
|
+
version: 'v1',
|
|
694
693
|
},
|
|
695
694
|
{
|
|
696
|
-
name:
|
|
697
|
-
description:
|
|
698
|
-
version:
|
|
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 ===
|
|
706
|
-
if (version ===
|
|
707
|
-
const prompt = prompts.find(
|
|
708
|
-
|
|
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:
|
|
712
|
+
role: 'user',
|
|
716
713
|
content: {
|
|
717
|
-
type:
|
|
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(
|
|
726
|
-
if (!prompt) throw new Error(
|
|
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:
|
|
732
|
-
content: { type:
|
|
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(
|
|
734
|
+
throw new Error('Prompt not found')
|
|
738
735
|
},
|
|
739
|
-
}
|
|
736
|
+
}
|
|
740
737
|
|
|
741
738
|
const serverWithPrompts = new MCPServer({
|
|
742
|
-
id:
|
|
743
|
-
name:
|
|
744
|
-
version:
|
|
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(
|
|
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:
|
|
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
|
|
833
|
-
import { createTool } from
|
|
834
|
-
import { z } from
|
|
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:
|
|
838
|
-
name:
|
|
839
|
-
version:
|
|
834
|
+
id: 'interactive-server',
|
|
835
|
+
name: 'Interactive Server',
|
|
836
|
+
version: '1.0.0',
|
|
840
837
|
tools: {
|
|
841
838
|
collectContactInfo: createTool({
|
|
842
|
-
id:
|
|
843
|
-
description:
|
|
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(
|
|
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
|
-
:
|
|
855
|
+
: 'Please provide your contact information',
|
|
862
856
|
requestedSchema: {
|
|
863
|
-
type:
|
|
857
|
+
type: 'object',
|
|
864
858
|
properties: {
|
|
865
859
|
name: {
|
|
866
|
-
type:
|
|
867
|
-
title:
|
|
868
|
-
description:
|
|
860
|
+
type: 'string',
|
|
861
|
+
title: 'Full Name',
|
|
862
|
+
description: 'Your full name',
|
|
869
863
|
},
|
|
870
864
|
email: {
|
|
871
|
-
type:
|
|
872
|
-
title:
|
|
873
|
-
description:
|
|
874
|
-
format:
|
|
865
|
+
type: 'string',
|
|
866
|
+
title: 'Email Address',
|
|
867
|
+
description: 'Your email address',
|
|
868
|
+
format: 'email',
|
|
875
869
|
},
|
|
876
870
|
phone: {
|
|
877
|
-
type:
|
|
878
|
-
title:
|
|
879
|
-
description:
|
|
871
|
+
type: 'string',
|
|
872
|
+
title: 'Phone Number',
|
|
873
|
+
description: 'Your phone number (optional)',
|
|
880
874
|
},
|
|
881
875
|
},
|
|
882
|
-
required: [
|
|
876
|
+
required: ['name', 'email'],
|
|
883
877
|
},
|
|
884
|
-
})
|
|
878
|
+
})
|
|
885
879
|
|
|
886
880
|
// Handle the user's response
|
|
887
|
-
if (result.action ===
|
|
888
|
-
return `Contact information collected: ${JSON.stringify(result.content, null, 2)}
|
|
889
|
-
} else if (result.action ===
|
|
890
|
-
return
|
|
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
|
|
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:
|
|
987
|
-
content?: any
|
|
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
|
|
997
|
-
import { MCPServer, createOAuthMiddleware, createStaticTokenValidator } from
|
|
990
|
+
import http from 'node:http'
|
|
991
|
+
import { MCPServer, createOAuthMiddleware, createStaticTokenValidator } from '@mastra/mcp'
|
|
998
992
|
|
|
999
993
|
const mcpServer = new MCPServer({
|
|
1000
|
-
id:
|
|
1001
|
-
name:
|
|
1002
|
-
version:
|
|
1003
|
-
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:
|
|
1010
|
-
authorizationServers: [
|
|
1011
|
-
scopesSupported: [
|
|
1012
|
-
resourceName:
|
|
1013
|
-
validateToken: createStaticTokenValidator([
|
|
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:
|
|
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 ||
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
1050
|
-
authorizationServers: [
|
|
1051
|
-
validateToken: createIntrospectionValidator(
|
|
1052
|
-
|
|
1053
|
-
|
|
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:
|
|
1062
|
-
authorizationServers: [
|
|
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:
|
|
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
|
|
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(
|
|
1115
|
-
const token = req.headers.authorization?.replace(
|
|
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(
|
|
1129
|
-
const url = new URL(req.url, `http://${req.headers.host}`)
|
|
1130
|
-
await server.startHTTP({ url, httpPath:
|
|
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:
|
|
1140
|
+
return { error: 'Authentication required' }
|
|
1145
1141
|
}
|
|
1146
1142
|
|
|
1147
1143
|
// Use the auth data
|
|
1148
|
-
console.log(
|
|
1149
|
-
console.log(
|
|
1144
|
+
console.log('User ID:', authInfo.extra.userId)
|
|
1145
|
+
console.log('Email:', authInfo.extra.email)
|
|
1150
1146
|
|
|
1151
|
-
const response = await fetch(
|
|
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:
|
|
1166
|
+
return { error: 'Authentication required' }
|
|
1171
1167
|
}
|
|
1172
1168
|
|
|
1173
1169
|
// Use the auth data
|
|
1174
|
-
console.log(
|
|
1175
|
-
console.log(
|
|
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
|
|
1207
|
-
import { MCPServer } from
|
|
1208
|
-
import { createTool } from
|
|
1209
|
-
import { z } from
|
|
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:
|
|
1215
|
-
email:
|
|
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:
|
|
1222
|
-
description:
|
|
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:
|
|
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:
|
|
1242
|
-
name:
|
|
1243
|
-
version:
|
|
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(
|
|
1251
|
-
const token = req.headers.authorization?.replace(
|
|
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(
|
|
1265
|
-
const url = new URL(req.url, `http://${req.headers.host}`)
|
|
1266
|
-
await server.startHTTP({ url, httpPath:
|
|
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
|