@mastra/mcp 0.11.3-alpha.1 → 0.11.3-alpha.2
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 +9 -0
- package/package.json +16 -3
- 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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @mastra/mcp
|
|
2
2
|
|
|
3
|
+
## 0.11.3-alpha.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#7343](https://github.com/mastra-ai/mastra/pull/7343) [`de3cbc6`](https://github.com/mastra-ai/mastra/commit/de3cbc61079211431bd30487982ea3653517278e) Thanks [@LekoArts](https://github.com/LekoArts)! - Update the `package.json` file to include additional fields like `repository`, `homepage` or `files`.
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`85ef90b`](https://github.com/mastra-ai/mastra/commit/85ef90bb2cd4ae4df855c7ac175f7d392c55c1bf), [`de3cbc6`](https://github.com/mastra-ai/mastra/commit/de3cbc61079211431bd30487982ea3653517278e)]:
|
|
10
|
+
- @mastra/core@0.15.3-alpha.5
|
|
11
|
+
|
|
3
12
|
## 0.11.3-alpha.1
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/mcp",
|
|
3
|
-
"version": "0.11.3-alpha.
|
|
3
|
+
"version": "0.11.3-alpha.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"CHANGELOG.md"
|
|
11
|
+
],
|
|
8
12
|
"exports": {
|
|
9
13
|
".": {
|
|
10
14
|
"import": {
|
|
@@ -53,8 +57,17 @@
|
|
|
53
57
|
"zod": "^3.25.76",
|
|
54
58
|
"zod-to-json-schema": "^3.24.6",
|
|
55
59
|
"@internal/lint": "0.0.34",
|
|
56
|
-
"@
|
|
57
|
-
"@
|
|
60
|
+
"@mastra/core": "0.15.3-alpha.5",
|
|
61
|
+
"@internal/types-builder": "0.0.9"
|
|
62
|
+
},
|
|
63
|
+
"homepage": "https://mastra.ai",
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "git+https://github.com/mastra-ai/mastra.git",
|
|
67
|
+
"directory": "packages/mcp"
|
|
68
|
+
},
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/mastra-ai/mastra/issues"
|
|
58
71
|
},
|
|
59
72
|
"scripts": {
|
|
60
73
|
"build": "tsup --silent --config tsup.config.ts",
|
package/.turbo/turbo-build.log
DELETED
package/eslint.config.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
21
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/typescript@5.8.3/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
21
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.4_@types+debug@4.1.12_@types+node@20.19.11_@vitest+ui@3.2.3_jiti@2.4.2_jsdom_70e728ef477f1e37b982af437efd45b2/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.4_@types+debug@4.1.12_@types+node@20.19.11_@vitest+ui@3.2.3_jiti@2.4.2_jsdom_70e728ef477f1e37b982af437efd45b2/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.4_@types+debug@4.1.12_@types+node@20.19.11_@vitest+ui@3.2.3_jiti@2.4.2_jsdom_70e728ef477f1e37b982af437efd45b2/node_modules/vitest/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/vitest@3.2.4_@types+debug@4.1.12_@types+node@20.19.11_@vitest+ui@3.2.3_jiti@2.4.2_jsdom_70e728ef477f1e37b982af437efd45b2/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../vitest/vitest.mjs" "$@"
|
|
21
|
-
fi
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mcp-server-integration-tests",
|
|
3
|
-
"private": true,
|
|
4
|
-
"version": "0.1.0",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"test:mcp": "vitest run ./src/server.test.ts",
|
|
7
|
-
"dev": "mastra dev"
|
|
8
|
-
},
|
|
9
|
-
"dependencies": {
|
|
10
|
-
"@ai-sdk/openai": "^1.3.24",
|
|
11
|
-
"@ai-sdk/react": "^1.2.12",
|
|
12
|
-
"@mastra/client-js": "workspace:*",
|
|
13
|
-
"@mastra/mcp": "workspace:*",
|
|
14
|
-
"dotenv": "^16.6.1",
|
|
15
|
-
"zod": "^3.25.76"
|
|
16
|
-
},
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"@mastra/core": "workspace:*",
|
|
19
|
-
"@testing-library/react": "^16.3.0",
|
|
20
|
-
"@types/node": "^20.17.57",
|
|
21
|
-
"get-port": "^7.1.0",
|
|
22
|
-
"mastra": "workspace:*",
|
|
23
|
-
"typescript": "^5.8.3",
|
|
24
|
-
"vitest": "^3.2.4"
|
|
25
|
-
},
|
|
26
|
-
"peerDependencies": {
|
|
27
|
-
"@mastra/core": ">=0.10.7-0 <0.16.0-0"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { openai } from '@ai-sdk/openai';
|
|
2
|
-
import { createTool } from '@mastra/core/tools';
|
|
3
|
-
import { Agent } from '@mastra/core/agent';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
import { weatherTool } from '../tools/weather';
|
|
6
|
-
import { MCPClient } from '@mastra/mcp';
|
|
7
|
-
|
|
8
|
-
const client = new MCPClient({
|
|
9
|
-
id: 'weather-server',
|
|
10
|
-
servers: {
|
|
11
|
-
weather: {
|
|
12
|
-
url: new URL(`http://localhost:4114/api/mcp/myMcpServer/mcp`),
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
export const weatherAgent = new Agent({
|
|
18
|
-
name: 'test',
|
|
19
|
-
instructions:
|
|
20
|
-
'You are a weather agent. When asked about weather in any city, use the get_weather tool with the city name as the postal code. When asked for clipboard contents you also get that.',
|
|
21
|
-
model: openai('gpt-4o'),
|
|
22
|
-
tools: async () => {
|
|
23
|
-
const tools = await client.getTools();
|
|
24
|
-
return {
|
|
25
|
-
get_weather: weatherTool,
|
|
26
|
-
clipboard: createTool({
|
|
27
|
-
id: 'clipboard',
|
|
28
|
-
description: 'Returns the contents of the users clipboard',
|
|
29
|
-
inputSchema: z.object({}),
|
|
30
|
-
}),
|
|
31
|
-
...tools,
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Mastra } from '@mastra/core';
|
|
2
|
-
import { weatherAgent } from './agents/weather';
|
|
3
|
-
import { myMcpServer } from './mcp';
|
|
4
|
-
|
|
5
|
-
export const mastra = new Mastra({
|
|
6
|
-
agents: {
|
|
7
|
-
test: weatherAgent,
|
|
8
|
-
},
|
|
9
|
-
mcpServers: {
|
|
10
|
-
myMcpServer,
|
|
11
|
-
},
|
|
12
|
-
server: {
|
|
13
|
-
port: 4114,
|
|
14
|
-
},
|
|
15
|
-
});
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { createTool } from '@mastra/core/tools';
|
|
2
|
-
import { MCPServer } from '@mastra/mcp';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
|
|
5
|
-
export const myMcpServer = new MCPServer({
|
|
6
|
-
name: 'My Calculation & Data MCP Server',
|
|
7
|
-
version: '1.0.0',
|
|
8
|
-
tools: {
|
|
9
|
-
calculator: createTool({
|
|
10
|
-
id: 'calculator',
|
|
11
|
-
description: 'Performs basic arithmetic operations (add, subtract).',
|
|
12
|
-
inputSchema: z.object({
|
|
13
|
-
num1: z.number().describe('The first number.'),
|
|
14
|
-
num2: z.number().describe('The second number.'),
|
|
15
|
-
operation: z.enum(['add', 'subtract']).describe('The operation to perform.'),
|
|
16
|
-
}),
|
|
17
|
-
execute: async ({ context }) => {
|
|
18
|
-
const { num1, num2, operation } = context;
|
|
19
|
-
if (operation === 'add') {
|
|
20
|
-
return num1 + num2;
|
|
21
|
-
}
|
|
22
|
-
if (operation === 'subtract') {
|
|
23
|
-
return num1 - num2;
|
|
24
|
-
}
|
|
25
|
-
throw new Error('Invalid operation');
|
|
26
|
-
},
|
|
27
|
-
}),
|
|
28
|
-
fetchWeather: createTool({
|
|
29
|
-
id: 'fetchWeather',
|
|
30
|
-
description: 'Fetches a (simulated) weather forecast for a given city.',
|
|
31
|
-
inputSchema: z.object({
|
|
32
|
-
city: z.string().describe('The city to get weather for, e.g., London, Paris.'),
|
|
33
|
-
}),
|
|
34
|
-
execute: async ({ context }) => {
|
|
35
|
-
const { city } = context;
|
|
36
|
-
const temperatures = {
|
|
37
|
-
london: '15°C',
|
|
38
|
-
paris: '18°C',
|
|
39
|
-
tokyo: '22°C',
|
|
40
|
-
};
|
|
41
|
-
const temp = temperatures[city.toLowerCase() as keyof typeof temperatures] || '20°C';
|
|
42
|
-
return `The weather in ${city} is ${temp} and sunny.`;
|
|
43
|
-
},
|
|
44
|
-
}),
|
|
45
|
-
},
|
|
46
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { createTool } from '@mastra/core/tools';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
export const weatherTool = createTool({
|
|
5
|
-
id: 'get_weather',
|
|
6
|
-
description: 'Get the weather for a given location',
|
|
7
|
-
inputSchema: z.object({
|
|
8
|
-
postalCode: z.string().describe('The location to get the weather for'),
|
|
9
|
-
}),
|
|
10
|
-
execute: async ({ context: { postalCode } }) => {
|
|
11
|
-
return `The weather in ${postalCode} is sunny. It is currently 70 degrees and feels like 65 degrees.`;
|
|
12
|
-
},
|
|
13
|
-
});
|
|
@@ -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
|
-
});
|