@mastra/mcp 0.11.3-alpha.1 → 0.11.3-alpha.3
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 +22 -0
- package/dist/client/configuration.d.ts +1 -1
- package/dist/client/configuration.d.ts.map +1 -1
- package/dist/client/promptActions.d.ts +1 -1
- package/dist/client/promptActions.d.ts.map +1 -1
- package/dist/index.cjs +223 -115
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +225 -118
- package/dist/index.js.map +1 -1
- package/dist/server/server.d.ts +6 -5
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/types.d.ts +69 -5
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +15 -2
- package/.turbo/turbo-build.log +0 -4
- package/eslint.config.js +0 -11
- package/integration-tests/node_modules/.bin/tsc +0 -21
- package/integration-tests/node_modules/.bin/tsserver +0 -21
- package/integration-tests/node_modules/.bin/vitest +0 -21
- package/integration-tests/package.json +0 -29
- package/integration-tests/src/mastra/agents/weather.ts +0 -34
- package/integration-tests/src/mastra/index.ts +0 -15
- package/integration-tests/src/mastra/mcp/index.ts +0 -46
- package/integration-tests/src/mastra/tools/weather.ts +0 -13
- package/integration-tests/src/server.test.ts +0 -238
- package/integration-tests/tsconfig.json +0 -13
- package/integration-tests/vitest.config.ts +0 -14
- package/src/__fixtures__/fire-crawl-complex-schema.ts +0 -1013
- package/src/__fixtures__/server-weather.ts +0 -16
- package/src/__fixtures__/stock-price.ts +0 -128
- package/src/__fixtures__/tools.ts +0 -94
- package/src/__fixtures__/weather.ts +0 -269
- package/src/client/client.test.ts +0 -585
- package/src/client/client.ts +0 -628
- package/src/client/configuration.test.ts +0 -856
- package/src/client/configuration.ts +0 -468
- package/src/client/elicitationActions.ts +0 -26
- package/src/client/index.ts +0 -3
- package/src/client/promptActions.ts +0 -70
- package/src/client/resourceActions.ts +0 -119
- package/src/index.ts +0 -2
- package/src/server/index.ts +0 -2
- package/src/server/promptActions.ts +0 -48
- package/src/server/resourceActions.ts +0 -90
- package/src/server/server-logging.test.ts +0 -181
- package/src/server/server.test.ts +0 -2142
- package/src/server/server.ts +0 -1445
- package/src/server/types.ts +0 -59
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -5
- package/tsup.config.ts +0 -17
- package/vitest.config.ts +0 -8
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import { MCPClient } from '@mastra/mcp';
|
|
3
|
-
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
|
4
|
-
import { ServerInfo } from '@mastra/core/mcp';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
|
|
7
|
-
vi.setConfig({ testTimeout: 20000, hookTimeout: 20000 });
|
|
8
|
-
|
|
9
|
-
describe('MCPServer through Mastra HTTP Integration (Subprocess)', () => {
|
|
10
|
-
let mastraServer: ReturnType<typeof spawn>;
|
|
11
|
-
const port: number = 4114;
|
|
12
|
-
const mcpServerId = 'myMcpServer';
|
|
13
|
-
const testToolId = 'calculator';
|
|
14
|
-
let client: MCPClient;
|
|
15
|
-
|
|
16
|
-
beforeAll(async () => {
|
|
17
|
-
mastraServer = spawn(
|
|
18
|
-
'pnpm',
|
|
19
|
-
[
|
|
20
|
-
path.resolve(import.meta.dirname, `..`, `..`, `..`, `cli`, `dist`, `index.js`),
|
|
21
|
-
'dev',
|
|
22
|
-
'--port',
|
|
23
|
-
port.toString(),
|
|
24
|
-
],
|
|
25
|
-
{
|
|
26
|
-
stdio: 'pipe',
|
|
27
|
-
detached: true, // Run in a new process group so we can kill it and children
|
|
28
|
-
},
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
// Wait for server to be ready
|
|
32
|
-
await new Promise<void>((resolve, reject) => {
|
|
33
|
-
let output = '';
|
|
34
|
-
mastraServer.stdout?.on('data', data => {
|
|
35
|
-
output += data.toString();
|
|
36
|
-
console.log(output);
|
|
37
|
-
if (output.includes('http://localhost:')) {
|
|
38
|
-
resolve();
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
mastraServer.stderr?.on('data', data => {
|
|
42
|
-
console.error('Mastra server error:', data.toString());
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
setTimeout(() => reject(new Error('Mastra server failed to start')), 100000);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
client = new MCPClient({
|
|
49
|
-
servers: {
|
|
50
|
-
[mcpServerId]: {
|
|
51
|
-
url: new URL(`http://localhost:${port}/api/mcp/${mcpServerId}/mcp`),
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
afterAll(() => {
|
|
58
|
-
// Kill the server and its process group
|
|
59
|
-
if (mastraServer?.pid) {
|
|
60
|
-
try {
|
|
61
|
-
process.kill(-mastraServer.pid, 'SIGTERM');
|
|
62
|
-
} catch (e) {
|
|
63
|
-
console.error('Failed to kill Mastra server:', e);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should allow an HTTP client to call a tool via Mastra MCP endpoint (Subprocess)', async () => {
|
|
69
|
-
const toolCallPayload = {
|
|
70
|
-
jsonrpc: '2.0',
|
|
71
|
-
id: `test-${Date.now()}`,
|
|
72
|
-
method: 'CallTool',
|
|
73
|
-
params: {
|
|
74
|
-
name: testToolId,
|
|
75
|
-
args: { num1: 10, num2: 5, operation: 'add' },
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const tools = await client.getTools();
|
|
80
|
-
console.log('Tools:', tools);
|
|
81
|
-
|
|
82
|
-
const tool = tools['myMcpServer_calculator'];
|
|
83
|
-
console.log('Tool:', tool);
|
|
84
|
-
|
|
85
|
-
const result = await tool.execute({ context: toolCallPayload.params.args });
|
|
86
|
-
console.log('Result:', result);
|
|
87
|
-
|
|
88
|
-
expect(result).toBeDefined();
|
|
89
|
-
expect(result.isError).toBe(false);
|
|
90
|
-
expect(result.content).toBeInstanceOf(Array);
|
|
91
|
-
expect(result.content.length).toBeGreaterThan(0);
|
|
92
|
-
|
|
93
|
-
const toolOutput = result.content[0];
|
|
94
|
-
expect(toolOutput.type).toBe('text');
|
|
95
|
-
|
|
96
|
-
const expectedToolResult = 15;
|
|
97
|
-
expect(JSON.parse(toolOutput.text)).toEqual(expectedToolResult);
|
|
98
|
-
}, 25000);
|
|
99
|
-
|
|
100
|
-
it('should allow a client to call a tool via Mastra MCP SSE endpoints (Subprocess)', async () => {
|
|
101
|
-
const sseUrl = new URL(`http://localhost:${port}/api/mcp/${mcpServerId}/sse`);
|
|
102
|
-
|
|
103
|
-
// Configure MCPClient for SSE transport
|
|
104
|
-
const sseClient = new MCPClient({
|
|
105
|
-
servers: {
|
|
106
|
-
[mcpServerId]: {
|
|
107
|
-
url: sseUrl, // URL for establishing SSE connection
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const toolCallPayloadParams = { num1: 10, num2: 5, operation: 'add' };
|
|
113
|
-
|
|
114
|
-
// Get tools (this will connect the client internally if not already connected)
|
|
115
|
-
const tools = await sseClient.getTools();
|
|
116
|
-
|
|
117
|
-
const toolName = `${mcpServerId}_${testToolId}`;
|
|
118
|
-
const tool = tools[toolName];
|
|
119
|
-
expect(tool, `Tool '${toolName}' should be available via SSE client`).toBeDefined();
|
|
120
|
-
|
|
121
|
-
// Execute the tool
|
|
122
|
-
const result = await tool.execute({ context: toolCallPayloadParams });
|
|
123
|
-
|
|
124
|
-
expect(result).toBeDefined();
|
|
125
|
-
expect(result.isError).toBe(false);
|
|
126
|
-
expect(result.content).toBeInstanceOf(Array);
|
|
127
|
-
expect(result.content.length).toBeGreaterThan(0);
|
|
128
|
-
|
|
129
|
-
const toolOutput = result.content[0];
|
|
130
|
-
expect(toolOutput.type).toBe('text');
|
|
131
|
-
|
|
132
|
-
const expectedToolResult = 15; // 10 + 5
|
|
133
|
-
expect(JSON.parse(toolOutput.text)).toEqual(expectedToolResult);
|
|
134
|
-
}, 25000);
|
|
135
|
-
|
|
136
|
-
// --- New tests for MCP Registry API Style Routes ---
|
|
137
|
-
describe('MCP Registry API Style Endpoints', () => {
|
|
138
|
-
const defaultMcpServerLogicalId = 'myMcpServer'; // Assuming this is the ID of the default server
|
|
139
|
-
|
|
140
|
-
it('GET /api/mcp/v0/servers - should list available MCP servers', async () => {
|
|
141
|
-
const response = await fetch(`http://localhost:${port}/api/mcp/v0/servers`);
|
|
142
|
-
expect(response.status).toBe(200);
|
|
143
|
-
expect(response.headers.get('content-type')).toContain('application/json');
|
|
144
|
-
const body = await response.json();
|
|
145
|
-
|
|
146
|
-
expect(body).toHaveProperty('servers');
|
|
147
|
-
expect(body).toHaveProperty('total_count');
|
|
148
|
-
expect(Array.isArray(body.servers)).toBe(true);
|
|
149
|
-
expect(body.total_count).toBeGreaterThanOrEqual(1); // Expect at least the default server
|
|
150
|
-
|
|
151
|
-
const defaultServerInfo: ServerInfo = body.servers.find((s: ServerInfo) => s.id === defaultMcpServerLogicalId);
|
|
152
|
-
expect(defaultServerInfo).toBeDefined();
|
|
153
|
-
expect(defaultServerInfo).toHaveProperty('name');
|
|
154
|
-
expect(defaultServerInfo).toHaveProperty('version_detail');
|
|
155
|
-
// Based on default mastra dev setup, if myMcpServer is the key, its id becomes 'myMcpServer'
|
|
156
|
-
// And its name might be something like 'my-mcp-server' if not explicitly set in MCPServerConfig for it.
|
|
157
|
-
// For this test, we assume the `id` is the key used in Mastra config.
|
|
158
|
-
expect(defaultServerInfo.id).toBe(defaultMcpServerLogicalId);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it('GET /api/mcp/v0/servers/:id - should get specific server details', async () => {
|
|
162
|
-
// First, get all servers to find the actual version of the default server
|
|
163
|
-
const listResponse = await fetch(`http://localhost:${port}/api/mcp/v0/servers`);
|
|
164
|
-
const listBody = await listResponse.json();
|
|
165
|
-
const defaultServer = listBody.servers.find((s: any) => s.id === defaultMcpServerLogicalId);
|
|
166
|
-
expect(defaultServer).toBeDefined();
|
|
167
|
-
const actualVersion = defaultServer.version_detail.version;
|
|
168
|
-
|
|
169
|
-
const response = await fetch(`http://localhost:${port}/api/mcp/v0/servers/${defaultMcpServerLogicalId}`);
|
|
170
|
-
expect(response.status).toBe(200);
|
|
171
|
-
const body = await response.json();
|
|
172
|
-
|
|
173
|
-
expect(body.id).toBe(defaultMcpServerLogicalId);
|
|
174
|
-
expect(body).toHaveProperty('name');
|
|
175
|
-
expect(body).toHaveProperty('version_detail');
|
|
176
|
-
expect(body.version_detail.version).toBe(actualVersion);
|
|
177
|
-
// Add more assertions for package_canonical, packages, remotes if they are expected for the default server
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('GET /api/mcp/v0/servers/:id - should get specific server version if it matches', async () => {
|
|
181
|
-
const listResponse = await fetch(`http://localhost:${port}/api/mcp/v0/servers`);
|
|
182
|
-
const listBody = await listResponse.json();
|
|
183
|
-
const defaultServer = listBody.servers.find((s: any) => s.id === defaultMcpServerLogicalId);
|
|
184
|
-
expect(defaultServer).toBeDefined();
|
|
185
|
-
const actualVersion = defaultServer.version_detail.version;
|
|
186
|
-
|
|
187
|
-
const response = await fetch(
|
|
188
|
-
`http://localhost:${port}/api/mcp/v0/servers/${defaultMcpServerLogicalId}?version=${actualVersion}`,
|
|
189
|
-
);
|
|
190
|
-
expect(response.status).toBe(200);
|
|
191
|
-
const body = await response.json();
|
|
192
|
-
expect(body.id).toBe(defaultMcpServerLogicalId);
|
|
193
|
-
expect(body.version_detail.version).toBe(actualVersion);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
it('GET /api/mcp/v0/servers/:id - should return 404 if specific server version does not match', async () => {
|
|
197
|
-
const nonExistentVersion = '0.0.0-nonexistent';
|
|
198
|
-
const response = await fetch(
|
|
199
|
-
`http://localhost:${port}/api/mcp/v0/servers/${defaultMcpServerLogicalId}?version=${nonExistentVersion}`,
|
|
200
|
-
);
|
|
201
|
-
expect(response.status).toBe(404);
|
|
202
|
-
const body = await response.json();
|
|
203
|
-
expect(body).toHaveProperty('error');
|
|
204
|
-
expect(body.error).toContain(`but not version '${nonExistentVersion}'`);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it('GET /api/mcp/v0/servers/:id - should return 404 for a non-existent server ID', async () => {
|
|
208
|
-
const nonExistentId = 'non-existent-server-id-12345';
|
|
209
|
-
const response = await fetch(`http://localhost:${port}/api/mcp/v0/servers/${nonExistentId}`);
|
|
210
|
-
expect(response.status).toBe(404);
|
|
211
|
-
const body = await response.json();
|
|
212
|
-
expect(body).toHaveProperty('error');
|
|
213
|
-
expect(body.error).toContain(`MCP server with ID '${nonExistentId}' not found`);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('GET /api/mcp/v0/servers - should handle pagination (limit=1, offset=0)', async () => {
|
|
217
|
-
const response = await fetch(`http://localhost:${port}/api/mcp/v0/servers?limit=1&offset=0`);
|
|
218
|
-
expect(response.status).toBe(200);
|
|
219
|
-
const body = await response.json();
|
|
220
|
-
expect(body.servers.length).toBe(1);
|
|
221
|
-
expect(body.total_count).toBeGreaterThanOrEqual(1);
|
|
222
|
-
if (body.total_count > 1) {
|
|
223
|
-
expect(body.next).not.toBeNull();
|
|
224
|
-
} else {
|
|
225
|
-
expect(body.next).toBeNull();
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it('Should be able to get lazy loaded tools', async () => {
|
|
230
|
-
const agent = await fetch(`http://localhost:${port}/api/agents/test`);
|
|
231
|
-
const agentJson = await agent.json();
|
|
232
|
-
const tools = agentJson.tools;
|
|
233
|
-
|
|
234
|
-
expect(tools).toHaveProperty('weather_fetchWeather');
|
|
235
|
-
expect(Object.keys(tools).length).toBe(4);
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"forceConsistentCasingInFileNames": true
|
|
10
|
-
},
|
|
11
|
-
"include": ["src/**/*"],
|
|
12
|
-
"exclude": ["node_modules"]
|
|
13
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vitest/config';
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
test: {
|
|
5
|
-
globals: true,
|
|
6
|
-
environment: 'node',
|
|
7
|
-
testTimeout: 60000,
|
|
8
|
-
hookTimeout: 30000,
|
|
9
|
-
coverage: {
|
|
10
|
-
provider: 'v8',
|
|
11
|
-
reporter: ['text', 'json', 'html'],
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
});
|