@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
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
2
|
-
import type { IMastraLogger } from '@mastra/core/logger';
|
|
3
|
-
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
-
|
|
5
|
-
interface ServerPromptActionsDependencies {
|
|
6
|
-
getLogger: () => IMastraLogger;
|
|
7
|
-
getSdkServer: () => Server;
|
|
8
|
-
clearDefinedPrompts: () => void;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class ServerPromptActions {
|
|
12
|
-
private readonly getLogger: () => IMastraLogger;
|
|
13
|
-
private readonly getSdkServer: () => Server;
|
|
14
|
-
private readonly clearDefinedPrompts: () => void;
|
|
15
|
-
|
|
16
|
-
constructor(dependencies: ServerPromptActionsDependencies) {
|
|
17
|
-
this.getLogger = dependencies.getLogger;
|
|
18
|
-
this.getSdkServer = dependencies.getSdkServer;
|
|
19
|
-
this.clearDefinedPrompts = dependencies.clearDefinedPrompts;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Notifies the server that the overall list of available prompts has changed.
|
|
24
|
-
* This will clear the internal cache of defined prompts and send a list_changed notification to clients.
|
|
25
|
-
*/
|
|
26
|
-
public async notifyListChanged(): Promise<void> {
|
|
27
|
-
this.getLogger().info('Prompt list change externally notified. Clearing definedPrompts and sending notification.');
|
|
28
|
-
this.clearDefinedPrompts();
|
|
29
|
-
try {
|
|
30
|
-
await this.getSdkServer().sendPromptListChanged();
|
|
31
|
-
} catch (error) {
|
|
32
|
-
const mastraError = new MastraError(
|
|
33
|
-
{
|
|
34
|
-
id: 'MCP_SERVER_PROMPT_LIST_CHANGED_NOTIFICATION_FAILED',
|
|
35
|
-
domain: ErrorDomain.MCP,
|
|
36
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
37
|
-
text: 'Failed to send prompt list changed notification',
|
|
38
|
-
},
|
|
39
|
-
error,
|
|
40
|
-
);
|
|
41
|
-
this.getLogger().error('Failed to send prompt list changed notification:', {
|
|
42
|
-
error: mastraError.toString(),
|
|
43
|
-
});
|
|
44
|
-
this.getLogger().trackException(mastraError);
|
|
45
|
-
throw mastraError;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
2
|
-
import type { IMastraLogger } from '@mastra/core/logger';
|
|
3
|
-
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
-
|
|
5
|
-
interface ServerResourceActionsDependencies {
|
|
6
|
-
getSubscriptions: () => Set<string>;
|
|
7
|
-
getLogger: () => IMastraLogger;
|
|
8
|
-
getSdkServer: () => Server;
|
|
9
|
-
clearDefinedResources: () => void;
|
|
10
|
-
clearDefinedResourceTemplates: () => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class ServerResourceActions {
|
|
14
|
-
private readonly getSubscriptions: () => Set<string>;
|
|
15
|
-
private readonly getLogger: () => IMastraLogger;
|
|
16
|
-
private readonly getSdkServer: () => Server;
|
|
17
|
-
private readonly clearDefinedResources: () => void;
|
|
18
|
-
private readonly clearDefinedResourceTemplates: () => void;
|
|
19
|
-
|
|
20
|
-
constructor(dependencies: ServerResourceActionsDependencies) {
|
|
21
|
-
this.getSubscriptions = dependencies.getSubscriptions;
|
|
22
|
-
this.getLogger = dependencies.getLogger;
|
|
23
|
-
this.getSdkServer = dependencies.getSdkServer;
|
|
24
|
-
this.clearDefinedResources = dependencies.clearDefinedResources;
|
|
25
|
-
this.clearDefinedResourceTemplates = dependencies.clearDefinedResourceTemplates;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Checks if any resources have been updated.
|
|
30
|
-
* If the resource is subscribed to by clients, an update notification will be sent.
|
|
31
|
-
*/
|
|
32
|
-
public async notifyUpdated({ uri }: { uri: string }): Promise<void> {
|
|
33
|
-
if (this.getSubscriptions().has(uri)) {
|
|
34
|
-
this.getLogger().info(`Sending notifications/resources/updated for externally notified resource: ${uri}`);
|
|
35
|
-
try {
|
|
36
|
-
await this.getSdkServer().sendResourceUpdated({ uri });
|
|
37
|
-
} catch (error) {
|
|
38
|
-
const mastraError = new MastraError(
|
|
39
|
-
{
|
|
40
|
-
id: 'MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED',
|
|
41
|
-
domain: ErrorDomain.MCP,
|
|
42
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
43
|
-
text: 'Failed to send resource updated notification',
|
|
44
|
-
details: {
|
|
45
|
-
uri,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
error,
|
|
49
|
-
);
|
|
50
|
-
this.getLogger().trackException(mastraError);
|
|
51
|
-
this.getLogger().error('Failed to send resource updated notification:', {
|
|
52
|
-
error: mastraError.toString(),
|
|
53
|
-
});
|
|
54
|
-
throw mastraError;
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
this.getLogger().debug(`Resource ${uri} was updated, but no active subscriptions for it.`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Notifies the server that the overall list of available resources has changed.
|
|
63
|
-
* This will clear the internal cache of defined resources and send a list_changed notification to clients.
|
|
64
|
-
*/
|
|
65
|
-
public async notifyListChanged(): Promise<void> {
|
|
66
|
-
this.getLogger().info(
|
|
67
|
-
'Resource list change externally notified. Clearing definedResources and sending notification.',
|
|
68
|
-
);
|
|
69
|
-
this.clearDefinedResources(); // Clear cached resources
|
|
70
|
-
this.clearDefinedResourceTemplates(); // Clear cached resource templates
|
|
71
|
-
try {
|
|
72
|
-
await this.getSdkServer().sendResourceListChanged();
|
|
73
|
-
} catch (error) {
|
|
74
|
-
const mastraError = new MastraError(
|
|
75
|
-
{
|
|
76
|
-
id: 'MCP_SERVER_RESOURCE_LIST_CHANGED_NOTIFICATION_FAILED',
|
|
77
|
-
domain: ErrorDomain.MCP,
|
|
78
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
79
|
-
text: 'Failed to send resource list changed notification',
|
|
80
|
-
},
|
|
81
|
-
error,
|
|
82
|
-
);
|
|
83
|
-
this.getLogger().trackException(mastraError);
|
|
84
|
-
this.getLogger().error('Failed to send resource list changed notification:', {
|
|
85
|
-
error: mastraError.toString(),
|
|
86
|
-
});
|
|
87
|
-
throw mastraError;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { describe, it, expect, vi, beforeEach, afterEach, beforeAll, afterAll } from 'vitest';
|
|
4
|
-
import type { LogMessage } from '../client/client';
|
|
5
|
-
import { MCPClient } from '../client/configuration';
|
|
6
|
-
|
|
7
|
-
// Increase test timeout for server operations
|
|
8
|
-
vi.setConfig({ testTimeout: 80000, hookTimeout: 80000 });
|
|
9
|
-
|
|
10
|
-
describe('MCP Server Logging', () => {
|
|
11
|
-
let consoleLogSpy: ReturnType<typeof vi.spyOn>;
|
|
12
|
-
let weatherProcess: ReturnType<typeof spawn>;
|
|
13
|
-
let weatherServerPort: number;
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
weatherServerPort = 60000 + Math.floor(Math.random() * 1000); // Generate a random port
|
|
16
|
-
|
|
17
|
-
// Start the weather SSE server
|
|
18
|
-
weatherProcess = spawn('npx', ['-y', 'tsx', path.join(__dirname, '..', '__fixtures__/weather.ts')], {
|
|
19
|
-
env: { ...process.env, WEATHER_SERVER_PORT: String(weatherServerPort) },
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Wait for SSE server to be ready
|
|
23
|
-
let resolved = false;
|
|
24
|
-
await new Promise<void>((resolve, reject) => {
|
|
25
|
-
weatherProcess.on(`exit`, () => {
|
|
26
|
-
if (!resolved) reject();
|
|
27
|
-
});
|
|
28
|
-
if (weatherProcess.stderr) {
|
|
29
|
-
weatherProcess.stderr.on(`data`, chunk => {
|
|
30
|
-
console.error(chunk.toString());
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
if (weatherProcess.stdout) {
|
|
34
|
-
weatherProcess.stdout.on('data', chunk => {
|
|
35
|
-
if (chunk.toString().includes('server is running on SSE')) {
|
|
36
|
-
resolve();
|
|
37
|
-
resolved = true;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
beforeEach(() => {
|
|
45
|
-
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
afterEach(() => {
|
|
49
|
-
consoleLogSpy.mockRestore();
|
|
50
|
-
vi.clearAllMocks();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
afterAll(async () => {
|
|
54
|
-
// Kill the weather SSE server
|
|
55
|
-
weatherProcess.kill('SIGINT');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should log events from specific servers to their handlers', async () => {
|
|
59
|
-
// Create individual log handlers for each server
|
|
60
|
-
const weatherLogHandler = vi.fn();
|
|
61
|
-
const stockLogHandler = vi.fn();
|
|
62
|
-
|
|
63
|
-
const config = new MCPClient({
|
|
64
|
-
id: 'server-log-test',
|
|
65
|
-
servers: {
|
|
66
|
-
weather: {
|
|
67
|
-
url: new URL(`http://localhost:${weatherServerPort}/sse`),
|
|
68
|
-
logger: weatherLogHandler,
|
|
69
|
-
},
|
|
70
|
-
stock: {
|
|
71
|
-
command: 'npx',
|
|
72
|
-
args: ['-y', 'tsx', path.join(__dirname, '..', '__fixtures__/stock-price.ts')],
|
|
73
|
-
env: {
|
|
74
|
-
FAKE_CREDS: 'test',
|
|
75
|
-
},
|
|
76
|
-
logger: stockLogHandler,
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
await config.getTools();
|
|
82
|
-
|
|
83
|
-
// Verify weather logs went to weather handler only
|
|
84
|
-
expect(weatherLogHandler).toHaveBeenCalled();
|
|
85
|
-
|
|
86
|
-
// Check logs contain server name
|
|
87
|
-
const weatherLogs = weatherLogHandler.mock.calls.map(call => call[0]);
|
|
88
|
-
weatherLogs.forEach(log => {
|
|
89
|
-
expect(log).toMatchObject({
|
|
90
|
-
serverName: 'weather',
|
|
91
|
-
timestamp: expect.any(Date),
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Verify stock logs went to stock handler only
|
|
96
|
-
expect(stockLogHandler).toHaveBeenCalled();
|
|
97
|
-
|
|
98
|
-
// Check logs contain server name
|
|
99
|
-
const stockLogs = stockLogHandler.mock.calls.map(call => call[0]);
|
|
100
|
-
stockLogs.forEach(log => {
|
|
101
|
-
expect(log).toMatchObject({
|
|
102
|
-
serverName: 'stock',
|
|
103
|
-
timestamp: expect.any(Date),
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Clean up
|
|
108
|
-
await config.disconnect();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('should work with handlers that filter events by log level', async () => {
|
|
112
|
-
// Create a handler that only logs errors and critical/emergency messages
|
|
113
|
-
const errorCounter = { count: 0 };
|
|
114
|
-
const highSeverityHandler = vi.fn((logMessage: LogMessage) => {
|
|
115
|
-
if (['error', 'critical', 'alert', 'emergency'].includes(logMessage.level)) {
|
|
116
|
-
errorCounter.count++;
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// Intentionally use a non-existent command to generate errors
|
|
121
|
-
const config = new MCPClient({
|
|
122
|
-
id: 'error-log-test',
|
|
123
|
-
servers: {
|
|
124
|
-
badServer: {
|
|
125
|
-
command: 'nonexistent-command-that-will-fail',
|
|
126
|
-
args: [],
|
|
127
|
-
logger: highSeverityHandler,
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
// This should fail, but our logger should capture the error
|
|
133
|
-
try {
|
|
134
|
-
await config.getTools();
|
|
135
|
-
} catch {
|
|
136
|
-
// Expected to fail
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Verify error logger was called
|
|
140
|
-
expect(highSeverityHandler).toHaveBeenCalled();
|
|
141
|
-
|
|
142
|
-
// Check we logged at least one error
|
|
143
|
-
expect(errorCounter.count).toBeGreaterThan(0);
|
|
144
|
-
|
|
145
|
-
// Clean up
|
|
146
|
-
await config.disconnect();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should support console logging patterns', async () => {
|
|
150
|
-
const logMessages: string[] = [];
|
|
151
|
-
|
|
152
|
-
const consoleLogger = (logMessage: LogMessage) => {
|
|
153
|
-
const formatted = `${logMessage.level}: ${logMessage.message}`;
|
|
154
|
-
logMessages.push(formatted);
|
|
155
|
-
console.log(formatted);
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const config = new MCPClient({
|
|
159
|
-
id: 'console-log-test',
|
|
160
|
-
servers: {
|
|
161
|
-
echoServer: {
|
|
162
|
-
command: 'echo',
|
|
163
|
-
args: ['test'],
|
|
164
|
-
logger: consoleLogger,
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
try {
|
|
170
|
-
await config.getTools();
|
|
171
|
-
} catch {
|
|
172
|
-
// May fail, but we just care about logging
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Verify console.log was called
|
|
176
|
-
expect(consoleLogSpy).toHaveBeenCalled();
|
|
177
|
-
|
|
178
|
-
// Clean up
|
|
179
|
-
await config.disconnect();
|
|
180
|
-
});
|
|
181
|
-
});
|