@mastra/mcp 1.0.0-beta.9 → 1.0.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 +359 -0
- package/README.md +191 -22
- package/dist/__fixtures__/tools.d.ts +8 -5
- package/dist/__fixtures__/tools.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/oauth-provider.d.ts +230 -0
- package/dist/client/oauth-provider.d.ts.map +1 -0
- package/dist/docs/README.md +1 -1
- package/dist/docs/SKILL.md +14 -2
- package/dist/docs/SOURCE_MAP.json +55 -2
- package/dist/docs/mcp/01-overview.md +24 -14
- package/dist/docs/mcp/02-publishing-mcp-server.md +2 -2
- package/dist/docs/tools/01-reference.md +326 -25
- package/dist/docs/tools-mcp/01-mcp-overview.md +8 -0
- package/dist/index.cjs +459 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +399 -5
- package/dist/index.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/oauth-middleware.d.ts +142 -0
- package/dist/server/oauth-middleware.d.ts.map +1 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/oauth-types.d.ts +137 -0
- package/dist/shared/oauth-types.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -46,9 +46,13 @@ export const testMcpClient = new MCPClient({
|
|
|
46
46
|
|
|
47
47
|
Visit [MCPClient](https://mastra.ai/reference/v1/tools/mcp-client) for a full list of configuration options.
|
|
48
48
|
|
|
49
|
+
> **Note:** Authentication
|
|
50
|
+
|
|
51
|
+
For connecting to OAuth-protected MCP servers, see the [OAuth Authentication](https://mastra.ai/reference/v1/tools/mcp-client#oauth-authentication) section.
|
|
52
|
+
|
|
49
53
|
## Using `MCPClient` with an agent
|
|
50
54
|
|
|
51
|
-
To use tools from an MCP server in an agent, import your `MCPClient` and call `.
|
|
55
|
+
To use tools from an MCP server in an agent, import your `MCPClient` and call `.listTools()` in the `tools` parameter. This loads from the defined MCP servers, making them available to the agent.
|
|
52
56
|
|
|
53
57
|
```typescript {3,15} title="src/mastra/agents/test-agent.ts"
|
|
54
58
|
import { Agent } from "@mastra/core/agent";
|
|
@@ -56,6 +60,7 @@ import { Agent } from "@mastra/core/agent";
|
|
|
56
60
|
import { testMcpClient } from "../mcp/test-mcp-client";
|
|
57
61
|
|
|
58
62
|
export const testAgent = new Agent({
|
|
63
|
+
id: "test-agent",
|
|
59
64
|
name: "Test Agent",
|
|
60
65
|
description: "You are a helpful AI assistant",
|
|
61
66
|
instructions: `
|
|
@@ -65,7 +70,7 @@ export const testAgent = new Agent({
|
|
|
65
70
|
|
|
66
71
|
Answer questions using the information you find using the MCP Servers.`,
|
|
67
72
|
model: "openai/gpt-5.1",
|
|
68
|
-
tools: await testMcpClient.
|
|
73
|
+
tools: await testMcpClient.listTools(),
|
|
69
74
|
});
|
|
70
75
|
```
|
|
71
76
|
|
|
@@ -98,6 +103,10 @@ export const testMcpServer = new MCPServer({
|
|
|
98
103
|
|
|
99
104
|
Visit [MCPServer](https://mastra.ai/reference/v1/tools/mcp-server) for a full list of configuration options.
|
|
100
105
|
|
|
106
|
+
> **Note:** Authentication
|
|
107
|
+
|
|
108
|
+
To protect your MCP server with OAuth, see the [OAuth Protection](https://mastra.ai/reference/v1/tools/mcp-server#oauth-protection) section.
|
|
109
|
+
|
|
101
110
|
## Registering an `MCPServer`
|
|
102
111
|
|
|
103
112
|
To make an MCP server available to other systems or agents that support the protocol, register it in the main `Mastra` instance using `mcpServers`.
|
|
@@ -116,20 +125,20 @@ export const mastra = new Mastra({
|
|
|
116
125
|
|
|
117
126
|
`MCPClient` offers two approaches to retrieving tools from connected servers, suitable for different application architectures:
|
|
118
127
|
|
|
119
|
-
| Feature | Static Configuration (`await mcp.
|
|
120
|
-
| :---------------- |
|
|
121
|
-
| **Use Case** | Single-user, static config (e.g., CLI tool)
|
|
122
|
-
| **Configuration** | Fixed at agent initialization
|
|
123
|
-
| **Credentials** | Shared across all uses
|
|
124
|
-
| **Agent Setup** | Tools added in `Agent` constructor
|
|
128
|
+
| Feature | Static Configuration (`await mcp.listTools()`) | Dynamic Configuration (`await mcp.listToolsets()`) |
|
|
129
|
+
| :---------------- | :--------------------------------------------- | :--------------------------------------------------- |
|
|
130
|
+
| **Use Case** | Single-user, static config (e.g., CLI tool) | Multi-user, dynamic config (e.g., SaaS app) |
|
|
131
|
+
| **Configuration** | Fixed at agent initialization | Per-request, dynamic |
|
|
132
|
+
| **Credentials** | Shared across all uses | Can vary per user/request |
|
|
133
|
+
| **Agent Setup** | Tools added in `Agent` constructor | Tools passed in `.generate()` or `.stream()` options |
|
|
125
134
|
|
|
126
135
|
### Static tools
|
|
127
136
|
|
|
128
|
-
Use the `.
|
|
137
|
+
Use the `.listTools()` method to fetch tools from all configured MCP servers. This is suitable when configuration (such as API keys) is static and consistent across users or requests. Call it once and pass the result to the `tools` property when defining your agent.
|
|
129
138
|
|
|
130
139
|
> **Note:**
|
|
131
140
|
|
|
132
|
-
Visit [
|
|
141
|
+
Visit [listTools()](https://mastra.ai/reference/v1/tools/mcp-client#listtools) for more information.
|
|
133
142
|
|
|
134
143
|
```typescript {6} title="src/mastra/agents/test-agent.ts"
|
|
135
144
|
import { Agent } from "@mastra/core/agent";
|
|
@@ -137,13 +146,14 @@ import { Agent } from "@mastra/core/agent";
|
|
|
137
146
|
import { testMcpClient } from "../mcp/test-mcp-client";
|
|
138
147
|
|
|
139
148
|
export const testAgent = new Agent({
|
|
140
|
-
|
|
149
|
+
id: "test-agent",
|
|
150
|
+
tools: await testMcpClient.listTools(),
|
|
141
151
|
});
|
|
142
152
|
```
|
|
143
153
|
|
|
144
154
|
### Dynamic tools
|
|
145
155
|
|
|
146
|
-
Use the `.
|
|
156
|
+
Use the `.listToolsets()` method when tool configuration may vary by request or user, such as in a multi-tenant system where each user provides their own API key. This method returns toolsets that can be passed to the `toolsets` option in the agent's `.generate()` or `.stream()` calls.
|
|
147
157
|
|
|
148
158
|
```typescript {5-16,21}
|
|
149
159
|
import { MCPClient } from "@mastra/mcp";
|
|
@@ -166,7 +176,7 @@ async function handleRequest(userPrompt: string, userApiKey: string) {
|
|
|
166
176
|
const agent = mastra.getAgent("testAgent");
|
|
167
177
|
|
|
168
178
|
const response = await agent.generate(userPrompt, {
|
|
169
|
-
toolsets: await userMcp.
|
|
179
|
+
toolsets: await userMcp.listToolsets(),
|
|
170
180
|
});
|
|
171
181
|
|
|
172
182
|
await userMcp.disconnect();
|
|
@@ -179,7 +189,7 @@ async function handleRequest(userPrompt: string, userApiKey: string) {
|
|
|
179
189
|
|
|
180
190
|
> **Note:**
|
|
181
191
|
|
|
182
|
-
Visit [
|
|
192
|
+
Visit [listToolsets()](https://mastra.ai/reference/v1/tools/mcp-client#listtoolsets) for more information.
|
|
183
193
|
|
|
184
194
|
## Connecting to an MCP registry
|
|
185
195
|
|
|
@@ -104,8 +104,8 @@ const mcp = new MCPClient({
|
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
// You can then get tools or toolsets from this configuration to use in your agent
|
|
107
|
-
const tools = await mcp.
|
|
108
|
-
const toolsets = await mcp.
|
|
107
|
+
const tools = await mcp.listTools();
|
|
108
|
+
const toolsets = await mcp.listToolsets();
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
Note: If you published without an organization scope, the `args` might just be `["-y", "your-package-name@latest"]`.
|
|
@@ -46,7 +46,7 @@ Retrieves all tools from all configured servers, with tool names namespaced by t
|
|
|
46
46
|
Intended to be passed onto an Agent definition.
|
|
47
47
|
|
|
48
48
|
```ts
|
|
49
|
-
new Agent({ tools: await mcp.listTools() });
|
|
49
|
+
new Agent({ id: "agent", tools: await mcp.listTools() });
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
### listToolsets()
|
|
@@ -591,6 +591,104 @@ await mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
|
|
|
591
591
|
- **Clear UI**: Make it obvious what information is being requested and why
|
|
592
592
|
- **Security**: Never auto-accept requests for sensitive information
|
|
593
593
|
|
|
594
|
+
## OAuth Authentication
|
|
595
|
+
|
|
596
|
+
For connecting to MCP servers that require OAuth authentication per the [MCP Auth Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization), use the `MCPOAuthClientProvider`:
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
import { MCPClient, MCPOAuthClientProvider } from "@mastra/mcp";
|
|
600
|
+
|
|
601
|
+
// Create an OAuth provider
|
|
602
|
+
const oauthProvider = new MCPOAuthClientProvider({
|
|
603
|
+
redirectUrl: "http://localhost:3000/oauth/callback",
|
|
604
|
+
clientMetadata: {
|
|
605
|
+
redirect_uris: ["http://localhost:3000/oauth/callback"],
|
|
606
|
+
client_name: "My MCP Client",
|
|
607
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
608
|
+
response_types: ["code"],
|
|
609
|
+
},
|
|
610
|
+
onRedirectToAuthorization: (url) => {
|
|
611
|
+
// Handle authorization redirect (open browser, redirect response, etc.)
|
|
612
|
+
console.log(`Please visit: ${url}`);
|
|
613
|
+
},
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
// Use the provider with MCPClient
|
|
617
|
+
const client = new MCPClient({
|
|
618
|
+
servers: {
|
|
619
|
+
protectedServer: {
|
|
620
|
+
url: new URL("https://mcp.example.com/mcp"),
|
|
621
|
+
authProvider: oauthProvider,
|
|
622
|
+
},
|
|
623
|
+
},
|
|
624
|
+
});
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### Quick Token Provider
|
|
628
|
+
|
|
629
|
+
For testing or when you already have a valid access token:
|
|
630
|
+
|
|
631
|
+
```typescript
|
|
632
|
+
import { MCPClient, createSimpleTokenProvider } from "@mastra/mcp";
|
|
633
|
+
|
|
634
|
+
const provider = createSimpleTokenProvider("your-access-token", {
|
|
635
|
+
redirectUrl: "http://localhost:3000/callback",
|
|
636
|
+
clientMetadata: {
|
|
637
|
+
redirect_uris: ["http://localhost:3000/callback"],
|
|
638
|
+
client_name: "Test Client",
|
|
639
|
+
},
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
const client = new MCPClient({
|
|
643
|
+
servers: {
|
|
644
|
+
testServer: {
|
|
645
|
+
url: new URL("https://mcp.example.com/mcp"),
|
|
646
|
+
authProvider: provider,
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
});
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### Custom Token Storage
|
|
653
|
+
|
|
654
|
+
For persistent token storage across sessions, implement the `OAuthStorage` interface:
|
|
655
|
+
|
|
656
|
+
```typescript
|
|
657
|
+
import { MCPOAuthClientProvider, OAuthStorage } from "@mastra/mcp";
|
|
658
|
+
|
|
659
|
+
class DatabaseOAuthStorage implements OAuthStorage {
|
|
660
|
+
constructor(private db: Database, private userId: string) {}
|
|
661
|
+
|
|
662
|
+
async set(key: string, value: string): Promise<void> {
|
|
663
|
+
await this.db.query(
|
|
664
|
+
"INSERT INTO oauth_tokens (user_id, key, value) VALUES (?, ?, ?) ON CONFLICT DO UPDATE SET value = ?",
|
|
665
|
+
[this.userId, key, value, value]
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
async get(key: string): Promise<string | undefined> {
|
|
670
|
+
const result = await this.db.query(
|
|
671
|
+
"SELECT value FROM oauth_tokens WHERE user_id = ? AND key = ?",
|
|
672
|
+
[this.userId, key]
|
|
673
|
+
);
|
|
674
|
+
return result?.[0]?.value;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
async delete(key: string): Promise<void> {
|
|
678
|
+
await this.db.query(
|
|
679
|
+
"DELETE FROM oauth_tokens WHERE user_id = ? AND key = ?",
|
|
680
|
+
[this.userId, key]
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
const provider = new MCPOAuthClientProvider({
|
|
686
|
+
redirectUrl: "http://localhost:3000/callback",
|
|
687
|
+
clientMetadata: { /* ... */ },
|
|
688
|
+
storage: new DatabaseOAuthStorage(db, "user-123"),
|
|
689
|
+
});
|
|
690
|
+
```
|
|
691
|
+
|
|
594
692
|
## Examples
|
|
595
693
|
|
|
596
694
|
### Static Tool Configuration
|
|
@@ -622,6 +720,7 @@ const mcp = new MCPClient({
|
|
|
622
720
|
|
|
623
721
|
// Create an agent with access to all tools
|
|
624
722
|
const agent = new Agent({
|
|
723
|
+
id: "multi-tool-agent",
|
|
625
724
|
name: "Multi-tool Agent",
|
|
626
725
|
instructions: "You have access to multiple tool servers.",
|
|
627
726
|
model: "openai/gpt-5.1",
|
|
@@ -677,6 +776,7 @@ import { MCPClient } from "@mastra/mcp";
|
|
|
677
776
|
|
|
678
777
|
// Create the agent first, without any tools
|
|
679
778
|
const agent = new Agent({
|
|
779
|
+
id: "multi-tool-agent",
|
|
680
780
|
name: "Multi-tool Agent",
|
|
681
781
|
instructions: "You help users check stocks and weather.",
|
|
682
782
|
model: "openai/gpt-5.1",
|
|
@@ -1760,44 +1860,245 @@ type ElicitResult = {
|
|
|
1760
1860
|
};
|
|
1761
1861
|
```
|
|
1762
1862
|
|
|
1863
|
+
## OAuth Protection
|
|
1864
|
+
|
|
1865
|
+
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:
|
|
1866
|
+
|
|
1867
|
+
```typescript
|
|
1868
|
+
import http from "node:http";
|
|
1869
|
+
import { MCPServer, createOAuthMiddleware, createStaticTokenValidator } from "@mastra/mcp";
|
|
1870
|
+
|
|
1871
|
+
const mcpServer = new MCPServer({
|
|
1872
|
+
id: "protected-server",
|
|
1873
|
+
name: "Protected MCP Server",
|
|
1874
|
+
version: "1.0.0",
|
|
1875
|
+
tools: { /* your tools */ },
|
|
1876
|
+
});
|
|
1877
|
+
|
|
1878
|
+
// Create OAuth middleware
|
|
1879
|
+
const oauthMiddleware = createOAuthMiddleware({
|
|
1880
|
+
oauth: {
|
|
1881
|
+
resource: "https://mcp.example.com/mcp",
|
|
1882
|
+
authorizationServers: ["https://auth.example.com"],
|
|
1883
|
+
scopesSupported: ["mcp:read", "mcp:write"],
|
|
1884
|
+
resourceName: "My Protected MCP Server",
|
|
1885
|
+
validateToken: createStaticTokenValidator(["allowed-token-1"]),
|
|
1886
|
+
},
|
|
1887
|
+
mcpPath: "/mcp",
|
|
1888
|
+
});
|
|
1889
|
+
|
|
1890
|
+
// Create HTTP server with OAuth protection
|
|
1891
|
+
const httpServer = http.createServer(async (req, res) => {
|
|
1892
|
+
const url = new URL(req.url || "", "https://mcp.example.com");
|
|
1893
|
+
|
|
1894
|
+
// Apply OAuth middleware first
|
|
1895
|
+
const result = await oauthMiddleware(req, res, url);
|
|
1896
|
+
if (!result.proceed) return; // Middleware handled response (401, metadata, etc.)
|
|
1897
|
+
|
|
1898
|
+
// Token is valid, proceed to MCP handler
|
|
1899
|
+
await mcpServer.startHTTP({ url, httpPath: "/mcp", req, res });
|
|
1900
|
+
});
|
|
1901
|
+
|
|
1902
|
+
httpServer.listen(3000);
|
|
1903
|
+
```
|
|
1904
|
+
|
|
1905
|
+
The middleware automatically:
|
|
1906
|
+
|
|
1907
|
+
- Serves **Protected Resource Metadata** at `/.well-known/oauth-protected-resource` (RFC 9728)
|
|
1908
|
+
- Returns `401 Unauthorized` with proper `WWW-Authenticate` headers when authentication is required
|
|
1909
|
+
- Validates bearer tokens using your provided validator
|
|
1910
|
+
|
|
1911
|
+
### Token Validation
|
|
1912
|
+
|
|
1913
|
+
For production, use proper token validation:
|
|
1914
|
+
|
|
1915
|
+
```typescript
|
|
1916
|
+
import { createOAuthMiddleware, createIntrospectionValidator } from "@mastra/mcp";
|
|
1917
|
+
|
|
1918
|
+
// Option 1: Token introspection (RFC 7662)
|
|
1919
|
+
const middleware = createOAuthMiddleware({
|
|
1920
|
+
oauth: {
|
|
1921
|
+
resource: "https://mcp.example.com/mcp",
|
|
1922
|
+
authorizationServers: ["https://auth.example.com"],
|
|
1923
|
+
validateToken: createIntrospectionValidator(
|
|
1924
|
+
"https://auth.example.com/oauth/introspect",
|
|
1925
|
+
{ clientId: "mcp-server", clientSecret: "secret" }
|
|
1926
|
+
),
|
|
1927
|
+
},
|
|
1928
|
+
});
|
|
1929
|
+
|
|
1930
|
+
// Option 2: Custom validation (JWT, database lookup, etc.)
|
|
1931
|
+
const customMiddleware = createOAuthMiddleware({
|
|
1932
|
+
oauth: {
|
|
1933
|
+
resource: "https://mcp.example.com/mcp",
|
|
1934
|
+
authorizationServers: ["https://auth.example.com"],
|
|
1935
|
+
validateToken: async (token, resource) => {
|
|
1936
|
+
const decoded = await verifyJWT(token);
|
|
1937
|
+
if (!decoded) {
|
|
1938
|
+
return { valid: false, error: "invalid_token" };
|
|
1939
|
+
}
|
|
1940
|
+
return {
|
|
1941
|
+
valid: true,
|
|
1942
|
+
scopes: decoded.scope?.split(" ") || [],
|
|
1943
|
+
subject: decoded.sub,
|
|
1944
|
+
};
|
|
1945
|
+
},
|
|
1946
|
+
},
|
|
1947
|
+
});
|
|
1948
|
+
```
|
|
1949
|
+
|
|
1950
|
+
### OAuth Middleware Options
|
|
1951
|
+
|
|
1763
1952
|
## Authentication Context
|
|
1764
1953
|
|
|
1765
|
-
Tools can access request metadata via `context.mcp.extra` when using HTTP-based transports
|
|
1954
|
+
Tools can access request metadata via `context.mcp.extra` when using HTTP-based transports. This allows you to pass authentication info, user context, or any custom data from your HTTP middleware to your MCP tools.
|
|
1955
|
+
|
|
1956
|
+
### How It Works
|
|
1957
|
+
|
|
1958
|
+
Whatever you set on `req.auth` in your HTTP middleware becomes available as `context.mcp.extra.authInfo` in your tools:
|
|
1959
|
+
|
|
1960
|
+
```
|
|
1961
|
+
req.auth = { ... } → context?.mcp?.extra?.authInfo.extra = { ... }
|
|
1962
|
+
```
|
|
1963
|
+
|
|
1964
|
+
### Setting Up Authentication Middleware
|
|
1965
|
+
|
|
1966
|
+
To pass data to your tools, populate `req.auth` on the Node.js request object in your HTTP server middleware before calling `server.startHTTP()`.
|
|
1967
|
+
|
|
1968
|
+
```typescript
|
|
1969
|
+
import express from "express";
|
|
1970
|
+
|
|
1971
|
+
const app = express();
|
|
1972
|
+
|
|
1973
|
+
// Auth middleware - set req.auth before the MCP handler
|
|
1974
|
+
app.use("/mcp", (req, res, next) => {
|
|
1975
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
1976
|
+
const user = verifyToken(token);
|
|
1977
|
+
|
|
1978
|
+
// This entire object becomes context.mcp.extra.authInfo
|
|
1979
|
+
// @ts-ignore - req.auth is read by the MCP SDK
|
|
1980
|
+
req.auth = {
|
|
1981
|
+
token,
|
|
1982
|
+
userId: user.userId,
|
|
1983
|
+
email: user.email,
|
|
1984
|
+
};
|
|
1985
|
+
next();
|
|
1986
|
+
});
|
|
1987
|
+
|
|
1988
|
+
app.all("/mcp", async (req, res) => {
|
|
1989
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
1990
|
+
await server.startHTTP({ url, httpPath: "/mcp", req, res });
|
|
1991
|
+
});
|
|
1992
|
+
```
|
|
1993
|
+
|
|
1994
|
+
### Accessing Auth Data in Tools
|
|
1995
|
+
|
|
1996
|
+
The `req.auth` object is available as `context.mcp.extra.authInfo` in your tool's execute function:
|
|
1766
1997
|
|
|
1767
1998
|
```typescript
|
|
1768
1999
|
execute: async (inputData, context) => {
|
|
1769
|
-
|
|
1770
|
-
|
|
2000
|
+
// Access the auth data you set in middleware
|
|
2001
|
+
const authInfo = context?.mcp?.extra?.authInfo;
|
|
2002
|
+
|
|
2003
|
+
if (!authInfo?.extra?.userId) {
|
|
2004
|
+
return { error: "Authentication required" };
|
|
1771
2005
|
}
|
|
1772
2006
|
|
|
1773
|
-
// Use the auth
|
|
2007
|
+
// Use the auth data
|
|
2008
|
+
console.log("User ID:", authInfo.extra.userId);
|
|
2009
|
+
console.log("Email:", authInfo.extra.email);
|
|
2010
|
+
|
|
1774
2011
|
const response = await fetch("/api/data", {
|
|
1775
|
-
headers: { Authorization: `Bearer ${
|
|
1776
|
-
signal: context
|
|
2012
|
+
headers: { Authorization: `Bearer ${authInfo.token}` },
|
|
2013
|
+
signal: context?.mcp?.extra?.signal,
|
|
1777
2014
|
});
|
|
1778
2015
|
|
|
1779
2016
|
return response.json();
|
|
1780
2017
|
};
|
|
1781
2018
|
```
|
|
1782
2019
|
|
|
1783
|
-
The `extra`
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
2020
|
+
### The `extra` Object
|
|
2021
|
+
|
|
2022
|
+
The full `context.mcp.extra` object contains:
|
|
2023
|
+
|
|
2024
|
+
| Property | Description |
|
|
2025
|
+
|----------|-------------|
|
|
2026
|
+
| `authInfo` | Whatever you set on `req.auth` in your middleware |
|
|
2027
|
+
| `sessionId` | Session identifier for the MCP connection |
|
|
2028
|
+
| `signal` | AbortSignal for request cancellation |
|
|
2029
|
+
| `sendNotification` | MCP protocol function for sending notifications |
|
|
2030
|
+
| `sendRequest` | MCP protocol function for sending requests |
|
|
2031
|
+
|
|
2032
|
+
### Complete Example
|
|
2033
|
+
|
|
2034
|
+
Here's a complete example showing the data flow from middleware to tool:
|
|
2035
|
+
|
|
2036
|
+
```typescript
|
|
2037
|
+
import express from "express";
|
|
2038
|
+
import { MCPServer } from "@mastra/mcp";
|
|
2039
|
+
import { createTool } from "@mastra/core/tools";
|
|
2040
|
+
import { z } from "zod";
|
|
2041
|
+
|
|
2042
|
+
const verifyToken = (token: string) => {
|
|
2043
|
+
// TODO: Implement token verification
|
|
2044
|
+
return {
|
|
2045
|
+
userId: "123",
|
|
2046
|
+
email: "test@test.com",
|
|
2047
|
+
};
|
|
2048
|
+
};
|
|
2049
|
+
|
|
2050
|
+
// 1. Define your tool that uses auth context
|
|
2051
|
+
const getUserData = createTool({
|
|
2052
|
+
id: "get-user-data",
|
|
2053
|
+
description: "Fetches data for the authenticated user",
|
|
2054
|
+
inputSchema: z.object({}),
|
|
2055
|
+
execute: async (inputData, context) => {
|
|
2056
|
+
const authInfo = context?.mcp?.extra?.authInfo;
|
|
2057
|
+
|
|
2058
|
+
if (!authInfo?.extra?.userId) {
|
|
2059
|
+
return { error: "Authentication required" };
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
// Access the data you set in middleware
|
|
2063
|
+
return {
|
|
2064
|
+
userId: authInfo.extra.userId,
|
|
2065
|
+
email: authInfo.extra.email,
|
|
2066
|
+
};
|
|
2067
|
+
},
|
|
2068
|
+
});
|
|
2069
|
+
|
|
2070
|
+
// 2. Create the MCP server with your tools
|
|
2071
|
+
const server = new MCPServer({
|
|
2072
|
+
id: "my-server",
|
|
2073
|
+
name: "My Server",
|
|
2074
|
+
version: "1.0.0",
|
|
2075
|
+
tools: { getUserData },
|
|
2076
|
+
});
|
|
2077
|
+
|
|
2078
|
+
// 3. Set up Express with auth middleware
|
|
2079
|
+
const app = express();
|
|
2080
|
+
|
|
2081
|
+
app.use("/mcp", (req, res, next) => {
|
|
2082
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
2083
|
+
const user = verifyToken(token);
|
|
2084
|
+
|
|
2085
|
+
// This entire object becomes context.mcp.extra.authInfo
|
|
2086
|
+
// @ts-ignore - req.auth is read by the MCP SDK
|
|
2087
|
+
req.auth = {
|
|
2088
|
+
token,
|
|
2089
|
+
userId: user.userId,
|
|
2090
|
+
email: user.email,
|
|
2091
|
+
};
|
|
2092
|
+
next();
|
|
2093
|
+
});
|
|
2094
|
+
|
|
2095
|
+
app.all("/mcp", async (req, res) => {
|
|
2096
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
2097
|
+
await server.startHTTP({ url, httpPath: "/mcp", req, res });
|
|
2098
|
+
});
|
|
2099
|
+
|
|
2100
|
+
app.listen(3000);
|
|
2101
|
+
```
|
|
1801
2102
|
|
|
1802
2103
|
## Related Information
|
|
1803
2104
|
|
|
@@ -46,6 +46,10 @@ export const testMcpClient = new MCPClient({
|
|
|
46
46
|
|
|
47
47
|
Visit [MCPClient](https://mastra.ai/reference/v1/tools/mcp-client) for a full list of configuration options.
|
|
48
48
|
|
|
49
|
+
> **Note:** Authentication
|
|
50
|
+
|
|
51
|
+
For connecting to OAuth-protected MCP servers, see the [OAuth Authentication](https://mastra.ai/reference/v1/tools/mcp-client#oauth-authentication) section.
|
|
52
|
+
|
|
49
53
|
## Using `MCPClient` with an agent
|
|
50
54
|
|
|
51
55
|
To use tools from an MCP server in an agent, import your `MCPClient` and call `.listTools()` in the `tools` parameter. This loads from the defined MCP servers, making them available to the agent.
|
|
@@ -99,6 +103,10 @@ export const testMcpServer = new MCPServer({
|
|
|
99
103
|
|
|
100
104
|
Visit [MCPServer](https://mastra.ai/reference/v1/tools/mcp-server) for a full list of configuration options.
|
|
101
105
|
|
|
106
|
+
> **Note:** Authentication
|
|
107
|
+
|
|
108
|
+
To protect your MCP server with OAuth, see the [OAuth Protection](https://mastra.ai/reference/v1/tools/mcp-server#oauth-protection) section.
|
|
109
|
+
|
|
102
110
|
### Serverless deployments
|
|
103
111
|
|
|
104
112
|
`MCPServer` can be deployed in serverless environments (Cloudflare Workers, Vercel Edge Functions, AWS Lambda, etc.) by enabling the `serverless: true` option in `startHTTP()`. This runs the server in stateless mode, where each request is handled independently without session management.
|