mcp-use 0.1.20 → 0.3.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.
Files changed (140) hide show
  1. package/dist/chunk-2HFIPY7C.js +429 -0
  2. package/dist/chunk-4DEFXVWT.js +680 -0
  3. package/dist/chunk-JXLQRAW2.js +532 -0
  4. package/dist/chunk-SHUYVCID.js +6 -0
  5. package/dist/chunk-YUSC6R6V.js +299 -0
  6. package/dist/index.cjs +5762 -0
  7. package/dist/index.d.ts +7 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +3767 -22
  10. package/dist/langfuse-YA2S23SM.js +13 -0
  11. package/dist/src/agents/remote.d.ts.map +1 -1
  12. package/dist/src/agents/utils/ai_sdk.d.ts.map +1 -1
  13. package/dist/src/auth/browser-provider.d.ts +52 -0
  14. package/dist/src/auth/browser-provider.d.ts.map +1 -0
  15. package/dist/src/auth/callback.d.ts +6 -0
  16. package/dist/src/auth/callback.d.ts.map +1 -0
  17. package/dist/src/auth/index.d.ts +7 -0
  18. package/dist/src/auth/index.d.ts.map +1 -0
  19. package/dist/src/auth/types.d.ts +18 -0
  20. package/dist/src/auth/types.d.ts.map +1 -0
  21. package/dist/src/browser.cjs +323 -0
  22. package/dist/src/browser.d.ts +8 -0
  23. package/dist/src/browser.d.ts.map +1 -0
  24. package/dist/src/browser.js +9 -0
  25. package/dist/src/client/base.d.ts +32 -0
  26. package/dist/src/client/base.d.ts.map +1 -0
  27. package/dist/src/client.d.ts +19 -16
  28. package/dist/src/client.d.ts.map +1 -1
  29. package/dist/src/logging.d.ts +1 -1
  30. package/dist/src/logging.d.ts.map +1 -1
  31. package/dist/src/oauth-helper.d.ts +125 -0
  32. package/dist/src/oauth-helper.d.ts.map +1 -0
  33. package/dist/src/react/index.cjs +986 -0
  34. package/dist/src/react/index.d.ts +9 -0
  35. package/dist/src/react/index.d.ts.map +1 -0
  36. package/dist/src/react/index.js +11 -0
  37. package/dist/src/react/types.d.ts +139 -0
  38. package/dist/src/react/types.d.ts.map +1 -0
  39. package/dist/src/react/useMcp.d.ts +3 -0
  40. package/dist/src/react/useMcp.d.ts.map +1 -0
  41. package/dist/src/server/index.cjs +566 -0
  42. package/dist/src/server/index.d.ts +3 -0
  43. package/dist/src/server/index.d.ts.map +1 -0
  44. package/dist/src/server/index.js +9 -0
  45. package/dist/src/server/logging.d.ts +16 -0
  46. package/dist/src/server/logging.d.ts.map +1 -0
  47. package/dist/src/server/mcp-server.d.ts +282 -0
  48. package/dist/src/server/mcp-server.d.ts.map +1 -0
  49. package/dist/src/server/types.d.ts +47 -0
  50. package/dist/src/server/types.d.ts.map +1 -0
  51. package/dist/src/utils/assert.d.ts +8 -0
  52. package/dist/src/utils/assert.d.ts.map +1 -0
  53. package/dist/tsconfig.tsbuildinfo +1 -0
  54. package/package.json +72 -40
  55. package/dist/examples/add_server_tool.d.ts +0 -8
  56. package/dist/examples/add_server_tool.d.ts.map +0 -1
  57. package/dist/examples/add_server_tool.js +0 -79
  58. package/dist/examples/ai_sdk_example.d.ts +0 -23
  59. package/dist/examples/ai_sdk_example.d.ts.map +0 -1
  60. package/dist/examples/ai_sdk_example.js +0 -213
  61. package/dist/examples/airbnb_use.d.ts +0 -10
  62. package/dist/examples/airbnb_use.d.ts.map +0 -1
  63. package/dist/examples/airbnb_use.js +0 -43
  64. package/dist/examples/blender_use.d.ts +0 -15
  65. package/dist/examples/blender_use.d.ts.map +0 -1
  66. package/dist/examples/blender_use.js +0 -39
  67. package/dist/examples/browser_use.d.ts +0 -10
  68. package/dist/examples/browser_use.d.ts.map +0 -1
  69. package/dist/examples/browser_use.js +0 -46
  70. package/dist/examples/chat_example.d.ts +0 -10
  71. package/dist/examples/chat_example.d.ts.map +0 -1
  72. package/dist/examples/chat_example.js +0 -86
  73. package/dist/examples/filesystem_use.d.ts +0 -11
  74. package/dist/examples/filesystem_use.d.ts.map +0 -1
  75. package/dist/examples/filesystem_use.js +0 -43
  76. package/dist/examples/http_example.d.ts +0 -18
  77. package/dist/examples/http_example.d.ts.map +0 -1
  78. package/dist/examples/http_example.js +0 -37
  79. package/dist/examples/mcp_everything.d.ts +0 -6
  80. package/dist/examples/mcp_everything.d.ts.map +0 -1
  81. package/dist/examples/mcp_everything.js +0 -25
  82. package/dist/examples/multi_server_example.d.ts +0 -10
  83. package/dist/examples/multi_server_example.d.ts.map +0 -1
  84. package/dist/examples/multi_server_example.js +0 -51
  85. package/dist/examples/observability.d.ts +0 -6
  86. package/dist/examples/observability.d.ts.map +0 -1
  87. package/dist/examples/observability.js +0 -50
  88. package/dist/examples/stream_example.d.ts +0 -12
  89. package/dist/examples/stream_example.d.ts.map +0 -1
  90. package/dist/examples/stream_example.js +0 -198
  91. package/dist/examples/structured_output.d.ts +0 -9
  92. package/dist/examples/structured_output.d.ts.map +0 -1
  93. package/dist/examples/structured_output.js +0 -95
  94. package/dist/src/adapters/base.js +0 -124
  95. package/dist/src/adapters/index.js +0 -2
  96. package/dist/src/adapters/langchain_adapter.js +0 -49
  97. package/dist/src/agents/base.js +0 -9
  98. package/dist/src/agents/index.js +0 -3
  99. package/dist/src/agents/mcp_agent.js +0 -1002
  100. package/dist/src/agents/prompts/system_prompt_builder.js +0 -40
  101. package/dist/src/agents/prompts/templates.js +0 -39
  102. package/dist/src/agents/remote.js +0 -264
  103. package/dist/src/agents/utils/ai_sdk.js +0 -62
  104. package/dist/src/agents/utils/index.js +0 -1
  105. package/dist/src/client.js +0 -133
  106. package/dist/src/config.js +0 -34
  107. package/dist/src/connectors/base.js +0 -143
  108. package/dist/src/connectors/http.js +0 -150
  109. package/dist/src/connectors/index.js +0 -4
  110. package/dist/src/connectors/stdio.js +0 -68
  111. package/dist/src/connectors/websocket.js +0 -157
  112. package/dist/src/logging.js +0 -217
  113. package/dist/src/managers/index.js +0 -2
  114. package/dist/src/managers/server_manager.js +0 -106
  115. package/dist/src/managers/tools/acquire_active_mcp_server.js +0 -17
  116. package/dist/src/managers/tools/add_server_from_config.js +0 -40
  117. package/dist/src/managers/tools/base.js +0 -17
  118. package/dist/src/managers/tools/connect_mcp_server.js +0 -46
  119. package/dist/src/managers/tools/index.js +0 -5
  120. package/dist/src/managers/tools/list_mcp_servers.js +0 -33
  121. package/dist/src/managers/tools/release_mcp_server_connection.js +0 -19
  122. package/dist/src/observability/index.js +0 -12
  123. package/dist/src/observability/langfuse.js +0 -211
  124. package/dist/src/observability/manager.js +0 -199
  125. package/dist/src/observability/types.js +0 -4
  126. package/dist/src/session.js +0 -23
  127. package/dist/src/task_managers/base.js +0 -127
  128. package/dist/src/task_managers/index.js +0 -5
  129. package/dist/src/task_managers/sse.js +0 -43
  130. package/dist/src/task_managers/stdio.js +0 -51
  131. package/dist/src/task_managers/streamable_http.js +0 -50
  132. package/dist/src/task_managers/websocket.js +0 -67
  133. package/dist/src/telemetry/events.js +0 -44
  134. package/dist/src/telemetry/index.js +0 -8
  135. package/dist/src/telemetry/telemetry.js +0 -324
  136. package/dist/src/telemetry/utils.js +0 -39
  137. package/dist/tests/ai_sdk_compatibility.test.js +0 -214
  138. package/dist/tests/stream_events.test.js +0 -307
  139. package/dist/tests/stream_events_simple.test.js +0 -179
  140. package/dist/vitest.config.js +0 -21
@@ -1,143 +0,0 @@
1
- import { logger } from '../logging.js';
2
- /**
3
- * Base class for MCP connectors.
4
- */
5
- export class BaseConnector {
6
- client = null;
7
- connectionManager = null;
8
- toolsCache = null;
9
- connected = false;
10
- opts;
11
- constructor(opts = {}) {
12
- this.opts = opts;
13
- }
14
- /** Disconnect and release resources. */
15
- async disconnect() {
16
- if (!this.connected) {
17
- logger.debug('Not connected to MCP implementation');
18
- return;
19
- }
20
- logger.debug('Disconnecting from MCP implementation');
21
- await this.cleanupResources();
22
- this.connected = false;
23
- logger.debug('Disconnected from MCP implementation');
24
- }
25
- /** Check if the client is connected */
26
- get isClientConnected() {
27
- return this.client != null;
28
- }
29
- /**
30
- * Initialise the MCP session **after** `connect()` has succeeded.
31
- *
32
- * In the SDK, `Client.connect(transport)` automatically performs the
33
- * protocol‑level `initialize` handshake, so we only need to cache the list of
34
- * tools and expose some server info.
35
- */
36
- async initialize(defaultRequestOptions = this.opts.defaultRequestOptions ?? {}) {
37
- if (!this.client) {
38
- throw new Error('MCP client is not connected');
39
- }
40
- logger.debug('Caching server capabilities & tools');
41
- // Cache server capabilities for callers who need them.
42
- const capabilities = this.client.getServerCapabilities();
43
- // Fetch and cache tools
44
- const listToolsRes = await this.client.listTools(undefined, defaultRequestOptions);
45
- this.toolsCache = (listToolsRes.tools ?? []);
46
- logger.debug(`Fetched ${this.toolsCache.length} tools from server`);
47
- return capabilities;
48
- }
49
- /** Lazily expose the cached tools list. */
50
- get tools() {
51
- if (!this.toolsCache) {
52
- throw new Error('MCP client is not initialized; call initialize() first');
53
- }
54
- return this.toolsCache;
55
- }
56
- /** Call a tool on the server. */
57
- async callTool(name, args, options) {
58
- if (!this.client) {
59
- throw new Error('MCP client is not connected');
60
- }
61
- logger.debug(`Calling tool '${name}' with args`, args);
62
- const res = await this.client.callTool({ name, arguments: args }, undefined, options);
63
- logger.debug(`Tool '${name}' returned`, res);
64
- return res;
65
- }
66
- /** List resources from the server. */
67
- async listResources(options) {
68
- if (!this.client) {
69
- throw new Error('MCP client is not connected');
70
- }
71
- logger.debug('Listing resources');
72
- return await this.client.listResources(undefined, options);
73
- }
74
- /** Read a resource by URI. */
75
- async readResource(uri, options) {
76
- if (!this.client) {
77
- throw new Error('MCP client is not connected');
78
- }
79
- logger.debug(`Reading resource ${uri}`);
80
- const res = await this.client.readResource({ uri }, options);
81
- return { content: res.content, mimeType: res.mimeType };
82
- }
83
- async listPrompts() {
84
- if (!this.client) {
85
- throw new Error('MCP client is not connected');
86
- }
87
- logger.debug('Listing prompt');
88
- return await this.client.listPrompts();
89
- }
90
- async getPrompt(name, args) {
91
- if (!this.client) {
92
- throw new Error('MCP client is not connected');
93
- }
94
- logger.debug(`Getting prompt ${name}`);
95
- return await this.client.getPrompt({ name, arguments: args });
96
- }
97
- /** Send a raw request through the client. */
98
- async request(method, params = null, options) {
99
- if (!this.client) {
100
- throw new Error('MCP client is not connected');
101
- }
102
- logger.debug(`Sending raw request '${method}' with params`, params);
103
- return await this.client.request({ method, params: params ?? {} }, undefined, options);
104
- }
105
- /**
106
- * Helper to tear down the client & connection manager safely.
107
- */
108
- async cleanupResources() {
109
- const issues = [];
110
- if (this.client) {
111
- try {
112
- if (typeof this.client.close === 'function') {
113
- await this.client.close();
114
- }
115
- }
116
- catch (e) {
117
- const msg = `Error closing client: ${e}`;
118
- logger.warn(msg);
119
- issues.push(msg);
120
- }
121
- finally {
122
- this.client = null;
123
- }
124
- }
125
- if (this.connectionManager) {
126
- try {
127
- await this.connectionManager.stop();
128
- }
129
- catch (e) {
130
- const msg = `Error stopping connection manager: ${e}`;
131
- logger.warn(msg);
132
- issues.push(msg);
133
- }
134
- finally {
135
- this.connectionManager = null;
136
- }
137
- }
138
- this.toolsCache = null;
139
- if (issues.length) {
140
- logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
141
- }
142
- }
143
- }
@@ -1,150 +0,0 @@
1
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
- import { StreamableHTTPError } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
3
- import { logger } from '../logging.js';
4
- import { SseConnectionManager } from '../task_managers/sse.js';
5
- import { StreamableHttpConnectionManager } from '../task_managers/streamable_http.js';
6
- import { BaseConnector } from './base.js';
7
- export class HttpConnector extends BaseConnector {
8
- baseUrl;
9
- headers;
10
- timeout;
11
- sseReadTimeout;
12
- clientInfo;
13
- preferSse;
14
- transportType = null;
15
- constructor(baseUrl, opts = {}) {
16
- super(opts);
17
- this.baseUrl = baseUrl.replace(/\/$/, '');
18
- this.headers = { ...(opts.headers ?? {}) };
19
- if (opts.authToken) {
20
- this.headers.Authorization = `Bearer ${opts.authToken}`;
21
- }
22
- this.timeout = opts.timeout ?? 5;
23
- this.sseReadTimeout = opts.sseReadTimeout ?? 60 * 5;
24
- this.clientInfo = opts.clientInfo ?? { name: 'http-connector', version: '1.0.0' };
25
- this.preferSse = opts.preferSse ?? false;
26
- }
27
- /** Establish connection to the MCP implementation via HTTP (streamable or SSE). */
28
- async connect() {
29
- if (this.connected) {
30
- logger.debug('Already connected to MCP implementation');
31
- return;
32
- }
33
- const baseUrl = this.baseUrl;
34
- // If preferSse is set, skip directly to SSE
35
- if (this.preferSse) {
36
- logger.debug(`Connecting to MCP implementation via HTTP/SSE: ${baseUrl}`);
37
- await this.connectWithSse(baseUrl);
38
- return;
39
- }
40
- // Try streamable HTTP first, then fall back to SSE
41
- logger.debug(`Connecting to MCP implementation via HTTP: ${baseUrl}`);
42
- try {
43
- // Try streamable HTTP transport first
44
- logger.debug('Attempting streamable HTTP transport...');
45
- await this.connectWithStreamableHttp(baseUrl);
46
- }
47
- catch (err) {
48
- // Check if this is a 4xx error that indicates we should try SSE fallback
49
- let fallbackReason = 'Unknown error';
50
- if (err instanceof StreamableHTTPError) {
51
- if (err.code === 404 || err.code === 405) {
52
- fallbackReason = `Server returned ${err.code} - server likely doesn't support streamable HTTP`;
53
- logger.debug(fallbackReason);
54
- }
55
- else {
56
- fallbackReason = `Server returned ${err.code}: ${err.message}`;
57
- logger.debug(fallbackReason);
58
- }
59
- }
60
- else if (err instanceof Error) {
61
- // Check for 404/405 in error message as fallback detection
62
- const errorStr = err.toString();
63
- if (errorStr.includes('405 Method Not Allowed') || errorStr.includes('404 Not Found')) {
64
- fallbackReason = 'Server doesn\'t support streamable HTTP (405/404)';
65
- logger.debug(fallbackReason);
66
- }
67
- else {
68
- fallbackReason = `Streamable HTTP failed: ${err.message}`;
69
- logger.debug(fallbackReason);
70
- }
71
- }
72
- // Always try SSE fallback for maximum compatibility
73
- logger.debug('Falling back to SSE transport...');
74
- try {
75
- await this.connectWithSse(baseUrl);
76
- }
77
- catch (sseErr) {
78
- logger.error(`Failed to connect with both transports:`);
79
- logger.error(` Streamable HTTP: ${fallbackReason}`);
80
- logger.error(` SSE: ${sseErr}`);
81
- await this.cleanupResources();
82
- throw new Error('Could not connect to server with any available transport');
83
- }
84
- }
85
- }
86
- async connectWithStreamableHttp(baseUrl) {
87
- try {
88
- // Create and start the streamable HTTP connection manager
89
- this.connectionManager = new StreamableHttpConnectionManager(baseUrl, {
90
- requestInit: {
91
- headers: this.headers,
92
- },
93
- // Pass through timeout and other options
94
- reconnectionOptions: {
95
- maxReconnectionDelay: 30000,
96
- initialReconnectionDelay: 1000,
97
- reconnectionDelayGrowFactor: 1.5,
98
- maxRetries: 2,
99
- },
100
- });
101
- const transport = await this.connectionManager.start();
102
- // Create and connect the client
103
- this.client = new Client(this.clientInfo, this.opts.clientOptions);
104
- await this.client.connect(transport);
105
- this.connected = true;
106
- this.transportType = 'streamable-http';
107
- logger.debug(`Successfully connected to MCP implementation via streamable HTTP: ${baseUrl}`);
108
- }
109
- catch (err) {
110
- // Clean up partial resources before throwing
111
- await this.cleanupResources();
112
- throw err;
113
- }
114
- }
115
- async connectWithSse(baseUrl) {
116
- try {
117
- // Create and start the SSE connection manager
118
- this.connectionManager = new SseConnectionManager(baseUrl, {
119
- requestInit: {
120
- headers: this.headers,
121
- },
122
- });
123
- const transport = await this.connectionManager.start();
124
- // Create and connect the client
125
- this.client = new Client(this.clientInfo, this.opts.clientOptions);
126
- await this.client.connect(transport);
127
- this.connected = true;
128
- this.transportType = 'sse';
129
- logger.debug(`Successfully connected to MCP implementation via HTTP/SSE: ${baseUrl}`);
130
- }
131
- catch (err) {
132
- // Clean up partial resources before throwing
133
- await this.cleanupResources();
134
- throw err;
135
- }
136
- }
137
- get publicIdentifier() {
138
- return {
139
- type: 'http',
140
- url: this.baseUrl,
141
- transport: this.transportType || 'unknown',
142
- };
143
- }
144
- /**
145
- * Get the transport type being used (streamable-http or sse)
146
- */
147
- getTransportType() {
148
- return this.transportType;
149
- }
150
- }
@@ -1,4 +0,0 @@
1
- export { BaseConnector } from './base.js';
2
- export { HttpConnector } from './http.js';
3
- export { StdioConnector } from './stdio.js';
4
- export { WebSocketConnector } from './websocket.js';
@@ -1,68 +0,0 @@
1
- import process from 'node:process';
2
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
- import { logger } from '../logging.js';
4
- import { StdioConnectionManager } from '../task_managers/stdio.js';
5
- import { BaseConnector } from './base.js';
6
- export class StdioConnector extends BaseConnector {
7
- command;
8
- args;
9
- env;
10
- errlog;
11
- clientInfo;
12
- constructor({ command = 'npx', args = [], env, errlog = process.stderr, ...rest } = {}) {
13
- super(rest);
14
- this.command = command;
15
- this.args = args;
16
- this.env = env;
17
- this.errlog = errlog;
18
- this.clientInfo = rest.clientInfo ?? { name: 'stdio-connector', version: '1.0.0' };
19
- }
20
- /** Establish connection to the MCP implementation. */
21
- async connect() {
22
- if (this.connected) {
23
- logger.debug('Already connected to MCP implementation');
24
- return;
25
- }
26
- logger.debug(`Connecting to MCP implementation via stdio: ${this.command}`);
27
- try {
28
- // 1. Build server parameters for the transport
29
- // Merge env with process.env, filtering out undefined values
30
- let mergedEnv;
31
- if (this.env) {
32
- mergedEnv = {};
33
- // First add process.env values (excluding undefined)
34
- for (const [key, value] of Object.entries(process.env)) {
35
- if (value !== undefined) {
36
- mergedEnv[key] = value;
37
- }
38
- }
39
- // Then override with provided env
40
- Object.assign(mergedEnv, this.env);
41
- }
42
- const serverParams = {
43
- command: this.command,
44
- args: this.args,
45
- env: mergedEnv,
46
- };
47
- // 2. Start the connection manager -> returns a live transport
48
- this.connectionManager = new StdioConnectionManager(serverParams, this.errlog);
49
- const transport = await this.connectionManager.start();
50
- // 3. Create & connect the MCP client
51
- this.client = new Client(this.clientInfo, this.opts.clientOptions);
52
- await this.client.connect(transport);
53
- this.connected = true;
54
- logger.debug(`Successfully connected to MCP implementation: ${this.command}`);
55
- }
56
- catch (err) {
57
- logger.error(`Failed to connect to MCP implementation: ${err}`);
58
- await this.cleanupResources();
59
- throw err;
60
- }
61
- }
62
- get publicIdentifier() {
63
- return {
64
- 'type': 'stdio',
65
- 'command&args': `${this.command} ${this.args.join(' ')}`,
66
- };
67
- }
68
- }
@@ -1,157 +0,0 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
- import { logger } from '../logging.js';
3
- import { WebSocketConnectionManager } from '../task_managers/websocket.js';
4
- import { BaseConnector } from './base.js';
5
- export class WebSocketConnector extends BaseConnector {
6
- url;
7
- headers;
8
- connectionManager = null;
9
- ws = null;
10
- receiverTask = null;
11
- pending = new Map();
12
- toolsCache = null;
13
- constructor(url, opts = {}) {
14
- super();
15
- this.url = url;
16
- this.headers = { ...(opts.headers ?? {}) };
17
- if (opts.authToken)
18
- this.headers.Authorization = `Bearer ${opts.authToken}`;
19
- }
20
- async connect() {
21
- if (this.connected) {
22
- logger.debug('Already connected to MCP implementation');
23
- return;
24
- }
25
- logger.debug(`Connecting via WebSocket: ${this.url}`);
26
- try {
27
- this.connectionManager = new WebSocketConnectionManager(this.url, this.headers);
28
- this.ws = await this.connectionManager.start();
29
- this.receiverTask = this.receiveLoop();
30
- this.connected = true;
31
- logger.debug('WebSocket connected successfully');
32
- }
33
- catch (e) {
34
- logger.error(`Failed to connect: ${e}`);
35
- await this.cleanupResources();
36
- throw e;
37
- }
38
- }
39
- async disconnect() {
40
- if (!this.connected) {
41
- logger.debug('Not connected to MCP implementation');
42
- return;
43
- }
44
- logger.debug('Disconnecting …');
45
- await this.cleanupResources();
46
- this.connected = false;
47
- }
48
- sendRequest(method, params = null) {
49
- if (!this.ws)
50
- throw new Error('WebSocket is not connected');
51
- const id = uuidv4();
52
- const payload = JSON.stringify({ id, method, params: params ?? {} });
53
- return new Promise((resolve, reject) => {
54
- this.pending.set(id, { resolve, reject });
55
- this.ws.send(payload, (err) => {
56
- if (err) {
57
- this.pending.delete(id);
58
- reject(err);
59
- }
60
- });
61
- });
62
- }
63
- async receiveLoop() {
64
- if (!this.ws)
65
- return;
66
- const socket = this.ws; // Node.ws or browser WS
67
- const onMessage = (msg) => {
68
- let data;
69
- try {
70
- data = JSON.parse(msg.data ?? msg);
71
- }
72
- catch (e) {
73
- logger.warn('Received non‑JSON frame', e);
74
- return;
75
- }
76
- const id = data.id;
77
- if (id && this.pending.has(id)) {
78
- const { resolve, reject } = this.pending.get(id);
79
- this.pending.delete(id);
80
- if ('result' in data)
81
- resolve(data.result);
82
- else if ('error' in data)
83
- reject(data.error);
84
- }
85
- else {
86
- logger.debug('Received unsolicited message', data);
87
- }
88
- };
89
- socket.addEventListener ? socket.addEventListener('message', onMessage) : socket.on('message', onMessage);
90
- // keep promise pending until close
91
- return new Promise((resolve) => {
92
- const onClose = () => {
93
- socket.removeEventListener ? socket.removeEventListener('message', onMessage) : socket.off('message', onMessage);
94
- this.rejectAll(new Error('WebSocket closed'));
95
- resolve();
96
- };
97
- socket.addEventListener ? socket.addEventListener('close', onClose) : socket.on('close', onClose);
98
- });
99
- }
100
- rejectAll(err) {
101
- for (const { reject } of this.pending.values())
102
- reject(err);
103
- this.pending.clear();
104
- }
105
- async initialize() {
106
- logger.debug('Initializing MCP session over WebSocket');
107
- const result = await this.sendRequest('initialize');
108
- const toolsList = await this.listTools();
109
- this.toolsCache = toolsList.map(t => t);
110
- logger.debug(`Initialized with ${this.toolsCache.length} tools`);
111
- return result;
112
- }
113
- async listTools() {
114
- const res = await this.sendRequest('tools/list');
115
- return res.tools ?? [];
116
- }
117
- async callTool(name, args) {
118
- return await this.sendRequest('tools/call', { name, arguments: args });
119
- }
120
- async listResources() {
121
- const resources = await this.sendRequest('resources/list');
122
- return { resources: Array.isArray(resources) ? resources : [] };
123
- }
124
- async readResource(uri) {
125
- const res = await this.sendRequest('resources/read', { uri });
126
- return { content: res.content, mimeType: res.mimeType };
127
- }
128
- async request(method, params = null) {
129
- return await this.sendRequest(method, params);
130
- }
131
- get tools() {
132
- if (!this.toolsCache)
133
- throw new Error('MCP client is not initialized');
134
- return this.toolsCache;
135
- }
136
- async cleanupResources() {
137
- // Stop receiver
138
- if (this.receiverTask)
139
- await this.receiverTask.catch(() => { });
140
- this.receiverTask = null;
141
- // Reject pending
142
- this.rejectAll(new Error('WebSocket disconnected'));
143
- // Stop connection manager → closes socket
144
- if (this.connectionManager) {
145
- await this.connectionManager.stop();
146
- this.connectionManager = null;
147
- this.ws = null;
148
- }
149
- this.toolsCache = null;
150
- }
151
- get publicIdentifier() {
152
- return {
153
- type: 'websocket',
154
- url: this.url,
155
- };
156
- }
157
- }