@mastra/mcp 0.4.1-alpha.2 → 0.4.1-alpha.4
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/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +15 -0
- package/README.md +144 -92
- package/dist/_tsup-dts-rollup.d.cts +100 -40
- package/dist/_tsup-dts-rollup.d.ts +100 -40
- package/dist/index.cjs +200 -66
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +197 -67
- package/package.json +4 -3
- package/src/client.test.ts +121 -33
- package/src/client.ts +172 -56
- package/src/configuration.test.ts +21 -36
- package/src/configuration.ts +107 -26
- package/src/index.ts +2 -1
- package/src/server-logging.test.ts +4 -4
- package/src/server.test.ts +2 -2
|
@@ -5,13 +5,20 @@ import type { Protocol } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
|
5
5
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
6
|
import type { SSEClientTransportOptions } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
7
7
|
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
8
|
-
import type { StdioServerParameters } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
9
8
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
9
|
+
import type { StreamableHTTPClientTransportOptions } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
10
10
|
import { Tool } from '@mastra/core/tools';
|
|
11
11
|
import { ToolExecutionContext } from '@mastra/core';
|
|
12
12
|
import type { ToolsInput } from '@mastra/core/agent';
|
|
13
13
|
import { z } from 'zod';
|
|
14
14
|
|
|
15
|
+
declare type BaseServerOptions = {
|
|
16
|
+
logger?: LogHandler;
|
|
17
|
+
timeout?: number;
|
|
18
|
+
capabilities?: ClientCapabilities;
|
|
19
|
+
enableServerLogs?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
15
22
|
declare type ConvertedTool = {
|
|
16
23
|
name: string;
|
|
17
24
|
description?: string;
|
|
@@ -22,39 +29,26 @@ declare type ConvertedTool = {
|
|
|
22
29
|
|
|
23
30
|
export declare function createLogger(server?: Server): Logger;
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export { LoggingLevel as LoggingLevel_alias_1 }
|
|
36
|
-
|
|
37
|
-
declare type LogHandler = (logMessage: LogMessage) => void;
|
|
38
|
-
export { LogHandler }
|
|
39
|
-
export { LogHandler as LogHandler_alias_1 }
|
|
40
|
-
|
|
41
|
-
declare interface LogMessage {
|
|
42
|
-
level: LoggingLevel;
|
|
43
|
-
message: string;
|
|
44
|
-
timestamp: Date;
|
|
45
|
-
serverName: string;
|
|
46
|
-
details?: Record<string, any>;
|
|
47
|
-
}
|
|
48
|
-
export { LogMessage }
|
|
49
|
-
export { LogMessage as LogMessage_alias_1 }
|
|
32
|
+
declare type HttpServerDefinition = BaseServerOptions & {
|
|
33
|
+
url: URL;
|
|
34
|
+
command?: never;
|
|
35
|
+
args?: never;
|
|
36
|
+
env?: never;
|
|
37
|
+
requestInit?: StreamableHTTPClientTransportOptions['requestInit'];
|
|
38
|
+
eventSourceInit?: SSEClientTransportOptions['eventSourceInit'];
|
|
39
|
+
reconnectionOptions?: StreamableHTTPClientTransportOptions['reconnectionOptions'];
|
|
40
|
+
sessionId?: StreamableHTTPClientTransportOptions['sessionId'];
|
|
41
|
+
};
|
|
50
42
|
|
|
51
|
-
declare class
|
|
43
|
+
export declare class InternalMastraMCPClient extends MastraBase {
|
|
52
44
|
name: string;
|
|
53
|
-
private transport;
|
|
54
45
|
private client;
|
|
55
46
|
private readonly timeout;
|
|
56
47
|
private logHandler?;
|
|
57
48
|
private enableServerLogs?;
|
|
49
|
+
private static hasWarned;
|
|
50
|
+
private serverConfig;
|
|
51
|
+
private transport?;
|
|
58
52
|
constructor({ name, version, server, capabilities, timeout, }: {
|
|
59
53
|
name: string;
|
|
60
54
|
server: MastraMCPServerDefinition;
|
|
@@ -70,41 +64,100 @@ declare class MastraMCPClient extends MastraBase {
|
|
|
70
64
|
*/
|
|
71
65
|
private log;
|
|
72
66
|
private setupLogging;
|
|
67
|
+
private connectStdio;
|
|
68
|
+
private connectHttp;
|
|
73
69
|
private isConnected;
|
|
74
70
|
connect(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Get the current session ID if using the Streamable HTTP transport.
|
|
73
|
+
* Returns undefined if not connected or not using Streamable HTTP.
|
|
74
|
+
*/
|
|
75
|
+
get sessionId(): string | undefined;
|
|
75
76
|
disconnect(): Promise<void>;
|
|
76
77
|
resources(): Promise<ReturnType<Protocol<any, any, any>['request']>>;
|
|
77
78
|
tools(): Promise<Record<string, any>>;
|
|
78
79
|
}
|
|
80
|
+
|
|
81
|
+
export declare interface Logger {
|
|
82
|
+
info: (message: string, data?: any) => Promise<void>;
|
|
83
|
+
warning: (message: string, data?: any) => Promise<void>;
|
|
84
|
+
error: (message: string, error?: any) => Promise<void>;
|
|
85
|
+
debug: (message: string, data?: any) => Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export declare const logger: Logger;
|
|
89
|
+
|
|
90
|
+
export { LoggingLevel }
|
|
91
|
+
export { LoggingLevel as LoggingLevel_alias_1 }
|
|
92
|
+
|
|
93
|
+
declare type LogHandler = (logMessage: LogMessage) => void;
|
|
94
|
+
export { LogHandler }
|
|
95
|
+
export { LogHandler as LogHandler_alias_1 }
|
|
96
|
+
|
|
97
|
+
declare interface LogMessage {
|
|
98
|
+
level: LoggingLevel;
|
|
99
|
+
message: string;
|
|
100
|
+
timestamp: Date;
|
|
101
|
+
serverName: string;
|
|
102
|
+
details?: Record<string, any>;
|
|
103
|
+
}
|
|
104
|
+
export { LogMessage }
|
|
105
|
+
export { LogMessage as LogMessage_alias_1 }
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @deprecated MastraMCPClient is deprecated and will be removed in a future release. Please use MCPClient instead.
|
|
109
|
+
*/
|
|
110
|
+
declare const MastraMCPClient: typeof InternalMastraMCPClient;
|
|
79
111
|
export { MastraMCPClient }
|
|
80
112
|
export { MastraMCPClient as MastraMCPClient_alias_1 }
|
|
81
113
|
|
|
82
|
-
declare type MastraMCPServerDefinition =
|
|
83
|
-
logger?: LogHandler;
|
|
84
|
-
timeout?: number;
|
|
85
|
-
capabilities?: ClientCapabilities;
|
|
86
|
-
enableServerLogs?: boolean;
|
|
87
|
-
};
|
|
114
|
+
declare type MastraMCPServerDefinition = StdioServerDefinition | HttpServerDefinition;
|
|
88
115
|
export { MastraMCPServerDefinition }
|
|
89
116
|
export { MastraMCPServerDefinition as MastraMCPServerDefinition_alias_1 }
|
|
90
117
|
|
|
91
|
-
declare class
|
|
118
|
+
declare class MCPClient extends MastraBase {
|
|
92
119
|
private serverConfigs;
|
|
93
120
|
private id;
|
|
94
121
|
private defaultTimeout;
|
|
95
|
-
|
|
122
|
+
private mcpClientsById;
|
|
123
|
+
private disconnectPromise;
|
|
124
|
+
constructor(args: MCPClientOptions);
|
|
96
125
|
private addToInstanceCache;
|
|
97
126
|
private makeId;
|
|
98
127
|
disconnect(): Promise<void>;
|
|
99
128
|
getTools(): Promise<Record<string, any>>;
|
|
100
129
|
getToolsets(): Promise<Record<string, Record<string, any>>>;
|
|
101
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Get the current session IDs for all connected MCP clients using the Streamable HTTP transport.
|
|
132
|
+
* Returns an object mapping server names to their session IDs.
|
|
133
|
+
*/
|
|
134
|
+
get sessionIds(): Record<string, string>;
|
|
102
135
|
private getConnectedClient;
|
|
103
136
|
private eachClientTools;
|
|
104
137
|
}
|
|
138
|
+
export { MCPClient }
|
|
139
|
+
export { MCPClient as MCPClient_alias_1 }
|
|
140
|
+
|
|
141
|
+
declare interface MCPClientOptions {
|
|
142
|
+
id?: string;
|
|
143
|
+
servers: Record<string, MastraMCPServerDefinition>;
|
|
144
|
+
timeout?: number;
|
|
145
|
+
}
|
|
146
|
+
export { MCPClientOptions }
|
|
147
|
+
export { MCPClientOptions as MCPClientOptions_alias_1 }
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @deprecated MCPConfiguration is deprecated and will be removed in a future release. Use MCPClient instead.
|
|
151
|
+
*/
|
|
152
|
+
declare class MCPConfiguration extends MCPClient {
|
|
153
|
+
constructor(args: MCPClientOptions);
|
|
154
|
+
}
|
|
105
155
|
export { MCPConfiguration }
|
|
106
156
|
export { MCPConfiguration as MCPConfiguration_alias_1 }
|
|
107
157
|
|
|
158
|
+
/**
|
|
159
|
+
* @deprecated MCPConfigurationOptions is deprecated and will be removed in a future release. Use MCPClientOptions instead.
|
|
160
|
+
*/
|
|
108
161
|
declare interface MCPConfigurationOptions {
|
|
109
162
|
id?: string;
|
|
110
163
|
servers: Record<string, MastraMCPServerDefinition>;
|
|
@@ -228,9 +281,16 @@ export declare const server_alias_1: Server<{
|
|
|
228
281
|
} | undefined;
|
|
229
282
|
}>;
|
|
230
283
|
|
|
231
|
-
declare type
|
|
232
|
-
|
|
233
|
-
|
|
284
|
+
declare type StdioServerDefinition = BaseServerOptions & {
|
|
285
|
+
command: string;
|
|
286
|
+
args?: string[];
|
|
287
|
+
env?: Record<string, string>;
|
|
288
|
+
url?: never;
|
|
289
|
+
requestInit?: never;
|
|
290
|
+
eventSourceInit?: never;
|
|
291
|
+
reconnectionOptions?: never;
|
|
292
|
+
sessionId?: never;
|
|
293
|
+
};
|
|
234
294
|
|
|
235
295
|
export declare const weatherTool: Tool<z.ZodObject<{
|
|
236
296
|
location: z.ZodString;
|
package/dist/index.cjs
CHANGED
|
@@ -6,9 +6,11 @@ var utils = require('@mastra/core/utils');
|
|
|
6
6
|
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
7
7
|
var sse_js = require('@modelcontextprotocol/sdk/client/sse.js');
|
|
8
8
|
var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
9
|
+
var streamableHttp_js = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
9
10
|
var protocol_js = require('@modelcontextprotocol/sdk/shared/protocol.js');
|
|
10
11
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
11
12
|
var exitHook = require('exit-hook');
|
|
13
|
+
var equal = require('fast-deep-equal');
|
|
12
14
|
var uuid = require('uuid');
|
|
13
15
|
var core = require('@mastra/core');
|
|
14
16
|
var index_js$1 = require('@modelcontextprotocol/sdk/server/index.js');
|
|
@@ -18,6 +20,8 @@ var fs = require('fs');
|
|
|
18
20
|
var os = require('os');
|
|
19
21
|
var path = require('path');
|
|
20
22
|
|
|
23
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
24
|
+
|
|
21
25
|
function _interopNamespace(e) {
|
|
22
26
|
if (e && e.__esModule) return e;
|
|
23
27
|
var n = Object.create(null);
|
|
@@ -36,6 +40,7 @@ function _interopNamespace(e) {
|
|
|
36
40
|
return Object.freeze(n);
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
var equal__default = /*#__PURE__*/_interopDefault(equal);
|
|
39
44
|
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
40
45
|
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
41
46
|
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
@@ -4117,13 +4122,15 @@ function convertLogLevelToLoggerMethod(level) {
|
|
|
4117
4122
|
return "info";
|
|
4118
4123
|
}
|
|
4119
4124
|
}
|
|
4120
|
-
var
|
|
4125
|
+
var InternalMastraMCPClient = class _InternalMastraMCPClient extends base.MastraBase {
|
|
4121
4126
|
name;
|
|
4122
|
-
transport;
|
|
4123
4127
|
client;
|
|
4124
4128
|
timeout;
|
|
4125
4129
|
logHandler;
|
|
4126
4130
|
enableServerLogs;
|
|
4131
|
+
static hasWarned = false;
|
|
4132
|
+
serverConfig;
|
|
4133
|
+
transport;
|
|
4127
4134
|
constructor({
|
|
4128
4135
|
name,
|
|
4129
4136
|
version = "1.0.0",
|
|
@@ -4132,23 +4139,17 @@ var MastraMCPClient = class extends base.MastraBase {
|
|
|
4132
4139
|
timeout = protocol_js.DEFAULT_REQUEST_TIMEOUT_MSEC
|
|
4133
4140
|
}) {
|
|
4134
4141
|
super({ name: "MastraMCPClient" });
|
|
4142
|
+
if (!_InternalMastraMCPClient.hasWarned) {
|
|
4143
|
+
console.warn(
|
|
4144
|
+
"[DEPRECATION] MastraMCPClient is deprecated and will be removed in a future release. Please use MCPClient instead."
|
|
4145
|
+
);
|
|
4146
|
+
_InternalMastraMCPClient.hasWarned = true;
|
|
4147
|
+
}
|
|
4135
4148
|
this.name = name;
|
|
4136
4149
|
this.timeout = timeout;
|
|
4137
4150
|
this.logHandler = server.logger;
|
|
4138
4151
|
this.enableServerLogs = server.enableServerLogs ?? true;
|
|
4139
|
-
|
|
4140
|
-
if (`url` in serverConfig) {
|
|
4141
|
-
this.transport = new sse_js.SSEClientTransport(serverConfig.url, {
|
|
4142
|
-
requestInit: serverConfig.requestInit,
|
|
4143
|
-
eventSourceInit: serverConfig.eventSourceInit
|
|
4144
|
-
});
|
|
4145
|
-
} else {
|
|
4146
|
-
this.transport = new stdio_js.StdioClientTransport({
|
|
4147
|
-
...serverConfig,
|
|
4148
|
-
// without ...getDefaultEnvironment() commands like npx will fail because there will be no PATH env var
|
|
4149
|
-
env: { ...stdio_js.getDefaultEnvironment(), ...serverConfig.env || {} }
|
|
4150
|
-
});
|
|
4151
|
-
}
|
|
4152
|
+
this.serverConfig = server;
|
|
4152
4153
|
this.client = new index_js.Client(
|
|
4153
4154
|
{
|
|
4154
4155
|
name,
|
|
@@ -4168,11 +4169,12 @@ var MastraMCPClient = class extends base.MastraBase {
|
|
|
4168
4169
|
*/
|
|
4169
4170
|
log(level, message, details) {
|
|
4170
4171
|
const loggerMethod = convertLogLevelToLoggerMethod(level);
|
|
4171
|
-
this.
|
|
4172
|
+
const msg = `[${this.name}] ${message}`;
|
|
4173
|
+
this.logger[loggerMethod](msg, details);
|
|
4172
4174
|
if (this.logHandler) {
|
|
4173
4175
|
this.logHandler({
|
|
4174
4176
|
level,
|
|
4175
|
-
message,
|
|
4177
|
+
message: msg,
|
|
4176
4178
|
timestamp: /* @__PURE__ */ new Date(),
|
|
4177
4179
|
serverName: this.name,
|
|
4178
4180
|
details
|
|
@@ -4195,44 +4197,121 @@ var MastraMCPClient = class extends base.MastraBase {
|
|
|
4195
4197
|
);
|
|
4196
4198
|
}
|
|
4197
4199
|
}
|
|
4200
|
+
async connectStdio(command) {
|
|
4201
|
+
this.log("debug", `Using Stdio transport for command: ${command}`);
|
|
4202
|
+
try {
|
|
4203
|
+
this.transport = new stdio_js.StdioClientTransport({
|
|
4204
|
+
command,
|
|
4205
|
+
args: this.serverConfig.args,
|
|
4206
|
+
env: { ...stdio_js.getDefaultEnvironment(), ...this.serverConfig.env || {} }
|
|
4207
|
+
});
|
|
4208
|
+
await this.client.connect(this.transport, { timeout: this.serverConfig.timeout ?? this.timeout });
|
|
4209
|
+
this.log("debug", `Successfully connected to MCP server via Stdio`);
|
|
4210
|
+
} catch (e) {
|
|
4211
|
+
this.log("error", e instanceof Error ? e.stack || e.message : JSON.stringify(e));
|
|
4212
|
+
throw e;
|
|
4213
|
+
}
|
|
4214
|
+
}
|
|
4215
|
+
async connectHttp(url) {
|
|
4216
|
+
const { requestInit, eventSourceInit } = this.serverConfig;
|
|
4217
|
+
this.log("debug", `Attempting to connect to URL: ${url}`);
|
|
4218
|
+
let shouldTrySSE = url.pathname.endsWith(`/sse`);
|
|
4219
|
+
if (!shouldTrySSE) {
|
|
4220
|
+
try {
|
|
4221
|
+
this.log("debug", "Trying Streamable HTTP transport...");
|
|
4222
|
+
const streamableTransport = new streamableHttp_js.StreamableHTTPClientTransport(url, {
|
|
4223
|
+
requestInit,
|
|
4224
|
+
reconnectionOptions: this.serverConfig.reconnectionOptions,
|
|
4225
|
+
sessionId: this.serverConfig.sessionId
|
|
4226
|
+
});
|
|
4227
|
+
await this.client.connect(streamableTransport, {
|
|
4228
|
+
timeout: (
|
|
4229
|
+
// this is hardcoded to 3s because the long default timeout would be extremely slow for sse backwards compat (60s)
|
|
4230
|
+
3e3
|
|
4231
|
+
)
|
|
4232
|
+
});
|
|
4233
|
+
this.transport = streamableTransport;
|
|
4234
|
+
this.log("debug", "Successfully connected using Streamable HTTP transport.");
|
|
4235
|
+
} catch (error) {
|
|
4236
|
+
this.log("debug", `Streamable HTTP transport failed: ${error}`);
|
|
4237
|
+
shouldTrySSE = true;
|
|
4238
|
+
}
|
|
4239
|
+
}
|
|
4240
|
+
if (shouldTrySSE) {
|
|
4241
|
+
this.log("debug", "Falling back to deprecated HTTP+SSE transport...");
|
|
4242
|
+
try {
|
|
4243
|
+
const sseTransport = new sse_js.SSEClientTransport(url, { requestInit, eventSourceInit });
|
|
4244
|
+
await this.client.connect(sseTransport, { timeout: this.serverConfig.timeout ?? this.timeout });
|
|
4245
|
+
this.transport = sseTransport;
|
|
4246
|
+
this.log("debug", "Successfully connected using deprecated HTTP+SSE transport.");
|
|
4247
|
+
} catch (sseError) {
|
|
4248
|
+
this.log(
|
|
4249
|
+
"error",
|
|
4250
|
+
`Failed to connect with SSE transport after failing to connect to Streamable HTTP transport first. SSE error: ${sseError}`
|
|
4251
|
+
);
|
|
4252
|
+
throw new Error("Could not connect to server with any available HTTP transport");
|
|
4253
|
+
}
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4198
4256
|
isConnected = false;
|
|
4199
4257
|
async connect() {
|
|
4200
4258
|
if (this.isConnected) return;
|
|
4259
|
+
const { command, url } = this.serverConfig;
|
|
4260
|
+
if (command) {
|
|
4261
|
+
await this.connectStdio(command);
|
|
4262
|
+
} else if (url) {
|
|
4263
|
+
await this.connectHttp(url);
|
|
4264
|
+
} else {
|
|
4265
|
+
throw new Error("Server configuration must include either a command or a url.");
|
|
4266
|
+
}
|
|
4267
|
+
this.isConnected = true;
|
|
4268
|
+
const originalOnClose = this.client.onclose;
|
|
4269
|
+
this.client.onclose = () => {
|
|
4270
|
+
this.log("debug", `MCP server connection closed`);
|
|
4271
|
+
this.isConnected = false;
|
|
4272
|
+
if (typeof originalOnClose === `function`) {
|
|
4273
|
+
originalOnClose();
|
|
4274
|
+
}
|
|
4275
|
+
};
|
|
4276
|
+
exitHook.asyncExitHook(
|
|
4277
|
+
async () => {
|
|
4278
|
+
this.log("debug", `Disconnecting MCP server during exit`);
|
|
4279
|
+
await this.disconnect();
|
|
4280
|
+
},
|
|
4281
|
+
{ wait: 5e3 }
|
|
4282
|
+
);
|
|
4283
|
+
process.on("SIGTERM", () => exitHook.gracefulExit());
|
|
4284
|
+
this.log("debug", `Successfully connected to MCP server`);
|
|
4285
|
+
}
|
|
4286
|
+
/**
|
|
4287
|
+
* Get the current session ID if using the Streamable HTTP transport.
|
|
4288
|
+
* Returns undefined if not connected or not using Streamable HTTP.
|
|
4289
|
+
*/
|
|
4290
|
+
get sessionId() {
|
|
4291
|
+
if (this.transport instanceof streamableHttp_js.StreamableHTTPClientTransport) {
|
|
4292
|
+
return this.transport.sessionId;
|
|
4293
|
+
}
|
|
4294
|
+
return void 0;
|
|
4295
|
+
}
|
|
4296
|
+
async disconnect() {
|
|
4297
|
+
if (!this.transport) {
|
|
4298
|
+
this.log("debug", "Disconnect called but no transport was connected.");
|
|
4299
|
+
return;
|
|
4300
|
+
}
|
|
4301
|
+
this.log("debug", `Disconnecting from MCP server`);
|
|
4201
4302
|
try {
|
|
4202
|
-
this.
|
|
4203
|
-
|
|
4204
|
-
timeout: this.timeout
|
|
4205
|
-
});
|
|
4206
|
-
this.isConnected = true;
|
|
4207
|
-
const originalOnClose = this.client.onclose;
|
|
4208
|
-
this.client.onclose = () => {
|
|
4209
|
-
this.log("debug", `MCP server connection closed`);
|
|
4210
|
-
this.isConnected = false;
|
|
4211
|
-
if (typeof originalOnClose === `function`) {
|
|
4212
|
-
originalOnClose();
|
|
4213
|
-
}
|
|
4214
|
-
};
|
|
4215
|
-
exitHook.asyncExitHook(
|
|
4216
|
-
async () => {
|
|
4217
|
-
this.log("debug", `Disconnecting MCP server during exit`);
|
|
4218
|
-
await this.disconnect();
|
|
4219
|
-
},
|
|
4220
|
-
{ wait: 5e3 }
|
|
4221
|
-
);
|
|
4222
|
-
process.on("SIGTERM", () => exitHook.gracefulExit());
|
|
4223
|
-
this.log("info", `Successfully connected to MCP server`);
|
|
4303
|
+
await this.transport.close();
|
|
4304
|
+
this.log("debug", "Successfully disconnected from MCP server");
|
|
4224
4305
|
} catch (e) {
|
|
4225
|
-
this.log("error",
|
|
4306
|
+
this.log("error", "Error during MCP server disconnect", {
|
|
4226
4307
|
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2)
|
|
4227
4308
|
});
|
|
4228
|
-
this.isConnected = false;
|
|
4229
4309
|
throw e;
|
|
4310
|
+
} finally {
|
|
4311
|
+
this.transport = void 0;
|
|
4312
|
+
this.isConnected = false;
|
|
4230
4313
|
}
|
|
4231
4314
|
}
|
|
4232
|
-
async disconnect() {
|
|
4233
|
-
this.log("debug", `Disconnecting from MCP server`);
|
|
4234
|
-
return await this.client.close();
|
|
4235
|
-
}
|
|
4236
4315
|
// TODO: do the type magic to return the right method type. Right now we get infinitely deep infered type errors from Zod without using "any"
|
|
4237
4316
|
async resources() {
|
|
4238
4317
|
this.log("debug", `Requesting resources from MCP server`);
|
|
@@ -4282,48 +4361,74 @@ var MastraMCPClient = class extends base.MastraBase {
|
|
|
4282
4361
|
return toolsRes;
|
|
4283
4362
|
}
|
|
4284
4363
|
};
|
|
4285
|
-
var
|
|
4286
|
-
var
|
|
4364
|
+
var MastraMCPClient = InternalMastraMCPClient;
|
|
4365
|
+
var mcpClientInstances = /* @__PURE__ */ new Map();
|
|
4366
|
+
var MCPClient = class extends base.MastraBase {
|
|
4287
4367
|
serverConfigs = {};
|
|
4288
4368
|
id;
|
|
4289
4369
|
defaultTimeout;
|
|
4370
|
+
mcpClientsById = /* @__PURE__ */ new Map();
|
|
4371
|
+
disconnectPromise = null;
|
|
4290
4372
|
constructor(args) {
|
|
4291
|
-
super({ name: "
|
|
4373
|
+
super({ name: "MCPClient" });
|
|
4292
4374
|
this.defaultTimeout = args.timeout ?? protocol_js.DEFAULT_REQUEST_TIMEOUT_MSEC;
|
|
4293
4375
|
this.serverConfigs = args.servers;
|
|
4294
4376
|
this.id = args.id ?? this.makeId();
|
|
4295
|
-
|
|
4377
|
+
if (args.id) {
|
|
4378
|
+
this.id = args.id;
|
|
4379
|
+
const cached = mcpClientInstances.get(this.id);
|
|
4380
|
+
if (cached && !equal__default.default(cached.serverConfigs, args.servers)) {
|
|
4381
|
+
const existingInstance2 = mcpClientInstances.get(this.id);
|
|
4382
|
+
if (existingInstance2) {
|
|
4383
|
+
void existingInstance2.disconnect();
|
|
4384
|
+
}
|
|
4385
|
+
}
|
|
4386
|
+
} else {
|
|
4387
|
+
this.id = this.makeId();
|
|
4388
|
+
}
|
|
4389
|
+
const existingInstance = mcpClientInstances.get(this.id);
|
|
4296
4390
|
if (existingInstance) {
|
|
4297
4391
|
if (!args.id) {
|
|
4298
|
-
throw new Error(`
|
|
4392
|
+
throw new Error(`MCPClient was initialized multiple times with the same configuration options.
|
|
4299
4393
|
|
|
4300
4394
|
This error is intended to prevent memory leaks.
|
|
4301
4395
|
|
|
4302
4396
|
To fix this you have three different options:
|
|
4303
|
-
1. If you need multiple
|
|
4304
|
-
2. Call "await
|
|
4305
|
-
3. If you only need one instance of
|
|
4397
|
+
1. If you need multiple MCPClient class instances with identical server configurations, set an id when configuring: new MCPClient({ id: "my-unique-id" })
|
|
4398
|
+
2. Call "await client.disconnect()" after you're done using the client and before you recreate another instance with the same options. If the identical MCPClient instance is already closed at the time of re-creating it, you will not see this error.
|
|
4399
|
+
3. If you only need one instance of MCPClient in your app, refactor your code so it's only created one time (ex. move it out of a loop into a higher scope code block)
|
|
4306
4400
|
`);
|
|
4307
4401
|
}
|
|
4308
4402
|
return existingInstance;
|
|
4309
4403
|
}
|
|
4404
|
+
mcpClientInstances.set(this.id, this);
|
|
4310
4405
|
this.addToInstanceCache();
|
|
4311
4406
|
return this;
|
|
4312
4407
|
}
|
|
4313
4408
|
addToInstanceCache() {
|
|
4314
|
-
if (!
|
|
4315
|
-
|
|
4409
|
+
if (!mcpClientInstances.has(this.id)) {
|
|
4410
|
+
mcpClientInstances.set(this.id, this);
|
|
4316
4411
|
}
|
|
4317
4412
|
}
|
|
4318
4413
|
makeId() {
|
|
4319
4414
|
const text = JSON.stringify(this.serverConfigs).normalize("NFKC");
|
|
4320
|
-
const idNamespace = uuid.v5(`
|
|
4415
|
+
const idNamespace = uuid.v5(`MCPClient`, uuid.v5.DNS);
|
|
4321
4416
|
return uuid.v5(text, idNamespace);
|
|
4322
4417
|
}
|
|
4323
4418
|
async disconnect() {
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4419
|
+
if (this.disconnectPromise) {
|
|
4420
|
+
return this.disconnectPromise;
|
|
4421
|
+
}
|
|
4422
|
+
this.disconnectPromise = (async () => {
|
|
4423
|
+
try {
|
|
4424
|
+
mcpClientInstances.delete(this.id);
|
|
4425
|
+
await Promise.all(Array.from(this.mcpClientsById.values()).map((client) => client.disconnect()));
|
|
4426
|
+
this.mcpClientsById.clear();
|
|
4427
|
+
} finally {
|
|
4428
|
+
this.disconnectPromise = null;
|
|
4429
|
+
}
|
|
4430
|
+
})();
|
|
4431
|
+
return this.disconnectPromise;
|
|
4327
4432
|
}
|
|
4328
4433
|
async getTools() {
|
|
4329
4434
|
this.addToInstanceCache();
|
|
@@ -4345,16 +4450,34 @@ To fix this you have three different options:
|
|
|
4345
4450
|
});
|
|
4346
4451
|
return connectedToolsets;
|
|
4347
4452
|
}
|
|
4348
|
-
|
|
4453
|
+
/**
|
|
4454
|
+
* Get the current session IDs for all connected MCP clients using the Streamable HTTP transport.
|
|
4455
|
+
* Returns an object mapping server names to their session IDs.
|
|
4456
|
+
*/
|
|
4457
|
+
get sessionIds() {
|
|
4458
|
+
const sessionIds = {};
|
|
4459
|
+
for (const [serverName, client] of this.mcpClientsById.entries()) {
|
|
4460
|
+
if (client.sessionId) {
|
|
4461
|
+
sessionIds[serverName] = client.sessionId;
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4464
|
+
return sessionIds;
|
|
4465
|
+
}
|
|
4349
4466
|
async getConnectedClient(name, config) {
|
|
4467
|
+
if (this.disconnectPromise) {
|
|
4468
|
+
await this.disconnectPromise;
|
|
4469
|
+
}
|
|
4350
4470
|
const exists = this.mcpClientsById.has(name);
|
|
4471
|
+
const existingClient = this.mcpClientsById.get(name);
|
|
4351
4472
|
if (exists) {
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4473
|
+
if (!existingClient) {
|
|
4474
|
+
throw new Error(`Client ${name} exists but is undefined`);
|
|
4475
|
+
}
|
|
4476
|
+
await existingClient.connect();
|
|
4477
|
+
return existingClient;
|
|
4355
4478
|
}
|
|
4356
4479
|
this.logger.debug(`Connecting to ${name} MCP server`);
|
|
4357
|
-
const mcpClient = new
|
|
4480
|
+
const mcpClient = new InternalMastraMCPClient({
|
|
4358
4481
|
name,
|
|
4359
4482
|
server: config,
|
|
4360
4483
|
timeout: config.timeout ?? this.defaultTimeout
|
|
@@ -4364,10 +4487,12 @@ To fix this you have three different options:
|
|
|
4364
4487
|
await mcpClient.connect();
|
|
4365
4488
|
} catch (e) {
|
|
4366
4489
|
this.mcpClientsById.delete(name);
|
|
4367
|
-
this.logger.error(`
|
|
4490
|
+
this.logger.error(`MCPClient errored connecting to MCP server ${name}`, {
|
|
4368
4491
|
error: e instanceof Error ? e.message : String(e)
|
|
4369
4492
|
});
|
|
4370
|
-
throw new Error(
|
|
4493
|
+
throw new Error(
|
|
4494
|
+
`Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`
|
|
4495
|
+
);
|
|
4371
4496
|
}
|
|
4372
4497
|
this.logger.debug(`Connected to ${name} MCP server`);
|
|
4373
4498
|
return mcpClient;
|
|
@@ -4382,6 +4507,14 @@ To fix this you have three different options:
|
|
|
4382
4507
|
);
|
|
4383
4508
|
}
|
|
4384
4509
|
};
|
|
4510
|
+
var MCPConfiguration = class extends MCPClient {
|
|
4511
|
+
constructor(args) {
|
|
4512
|
+
super(args);
|
|
4513
|
+
this.logger.warn(
|
|
4514
|
+
`MCPConfiguration has been renamed to MCPClient and MCPConfiguration is deprecated. The API is identical but the MCPConfiguration export will be removed in the future. Update your imports now to prevent future errors.`
|
|
4515
|
+
);
|
|
4516
|
+
}
|
|
4517
|
+
};
|
|
4385
4518
|
|
|
4386
4519
|
// ../../node_modules/.pnpm/json-schema-to-zod@2.6.0/node_modules/json-schema-to-zod/dist/esm/parsers/parseAnyOf.js
|
|
4387
4520
|
var parseAnyOf = (schema, refs) => {
|
|
@@ -6502,6 +6635,7 @@ var MCPServer = class {
|
|
|
6502
6635
|
}
|
|
6503
6636
|
};
|
|
6504
6637
|
|
|
6638
|
+
exports.MCPClient = MCPClient;
|
|
6505
6639
|
exports.MCPConfiguration = MCPConfiguration;
|
|
6506
6640
|
exports.MCPServer = MCPServer;
|
|
6507
6641
|
exports.MastraMCPClient = MastraMCPClient;
|
package/dist/index.d.cts
CHANGED
|
@@ -3,6 +3,8 @@ export { LogMessage_alias_1 as LogMessage } from './_tsup-dts-rollup.cjs';
|
|
|
3
3
|
export { LogHandler_alias_1 as LogHandler } from './_tsup-dts-rollup.cjs';
|
|
4
4
|
export { MastraMCPServerDefinition_alias_1 as MastraMCPServerDefinition } from './_tsup-dts-rollup.cjs';
|
|
5
5
|
export { MastraMCPClient_alias_1 as MastraMCPClient } from './_tsup-dts-rollup.cjs';
|
|
6
|
+
export { MCPClientOptions_alias_1 as MCPClientOptions } from './_tsup-dts-rollup.cjs';
|
|
7
|
+
export { MCPClient_alias_1 as MCPClient } from './_tsup-dts-rollup.cjs';
|
|
6
8
|
export { MCPConfigurationOptions_alias_1 as MCPConfigurationOptions } from './_tsup-dts-rollup.cjs';
|
|
7
9
|
export { MCPConfiguration_alias_1 as MCPConfiguration } from './_tsup-dts-rollup.cjs';
|
|
8
10
|
export { MCPServer } from './_tsup-dts-rollup.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { LogMessage_alias_1 as LogMessage } from './_tsup-dts-rollup.js';
|
|
|
3
3
|
export { LogHandler_alias_1 as LogHandler } from './_tsup-dts-rollup.js';
|
|
4
4
|
export { MastraMCPServerDefinition_alias_1 as MastraMCPServerDefinition } from './_tsup-dts-rollup.js';
|
|
5
5
|
export { MastraMCPClient_alias_1 as MastraMCPClient } from './_tsup-dts-rollup.js';
|
|
6
|
+
export { MCPClientOptions_alias_1 as MCPClientOptions } from './_tsup-dts-rollup.js';
|
|
7
|
+
export { MCPClient_alias_1 as MCPClient } from './_tsup-dts-rollup.js';
|
|
6
8
|
export { MCPConfigurationOptions_alias_1 as MCPConfigurationOptions } from './_tsup-dts-rollup.js';
|
|
7
9
|
export { MCPConfiguration_alias_1 as MCPConfiguration } from './_tsup-dts-rollup.js';
|
|
8
10
|
export { MCPServer } from './_tsup-dts-rollup.js';
|