mcp-use 1.11.0-canary.8 → 1.11.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/{chunk-5RTMAOZ6.js → chunk-A4QJRN7Z.js} +5 -1041
- package/dist/{chunk-4LZSXUFM.js → chunk-B7AGEK7F.js} +1 -1
- package/dist/{chunk-TAEHPLGV.js → chunk-GN5HOAV3.js} +664 -136
- package/dist/chunk-QPIDKGV4.js +1246 -0
- package/dist/chunk-UWWLWLS2.js +62 -0
- package/dist/{chunk-ZFZPZ4GE.js → chunk-V77WS6CS.js} +9 -0
- package/dist/{chunk-EBSNALCB.js → chunk-VRHAF2WT.js} +10 -4
- package/dist/{chunk-X7JKFBPN.js → chunk-Y2HHHJQB.js} +159 -8
- package/dist/{chunk-JPKFN73V.js → chunk-ZLZOOXMJ.js} +96 -43
- package/dist/index.cjs +316 -53
- package/dist/index.js +22 -24
- package/dist/notifications-FLGIFS56.js +9 -0
- package/dist/src/agents/index.cjs +153 -47
- package/dist/src/agents/index.d.ts +1 -1
- package/dist/src/agents/index.d.ts.map +1 -1
- package/dist/src/agents/index.js +7 -10
- package/dist/src/agents/mcp_agent.d.ts.map +1 -1
- package/dist/src/{client/prompts.d.ts → agents/prompts/index.d.ts} +3 -3
- package/dist/src/agents/prompts/index.d.ts.map +1 -0
- package/dist/src/browser.cjs +160 -48
- package/dist/src/browser.js +10 -12
- package/dist/src/client/browser.d.ts.map +1 -1
- package/dist/src/client.cjs +3852 -0
- package/dist/src/client.d.ts +2 -0
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +21 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/connectors/http.d.ts +2 -0
- package/dist/src/connectors/http.d.ts.map +1 -1
- package/dist/src/react/index.cjs +313 -52
- package/dist/src/react/index.js +7 -8
- package/dist/src/react/types.d.ts +41 -1
- package/dist/src/react/types.d.ts.map +1 -1
- package/dist/src/react/useMcp.d.ts.map +1 -1
- package/dist/src/server/endpoints/mount-mcp.d.ts.map +1 -1
- package/dist/src/server/index.cjs +1339 -256
- package/dist/src/server/index.d.ts +2 -0
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/index.js +1119 -156
- package/dist/src/server/mcp-server.d.ts +4 -1
- package/dist/src/server/mcp-server.d.ts.map +1 -1
- package/dist/src/server/notifications/index.d.ts +1 -1
- package/dist/src/server/notifications/index.d.ts.map +1 -1
- package/dist/src/server/notifications/notification-registration.d.ts +51 -0
- package/dist/src/server/notifications/notification-registration.d.ts.map +1 -1
- package/dist/src/server/sessions/index.d.ts +3 -1
- package/dist/src/server/sessions/index.d.ts.map +1 -1
- package/dist/src/server/sessions/session-manager.d.ts +30 -16
- package/dist/src/server/sessions/session-manager.d.ts.map +1 -1
- package/dist/src/server/sessions/stores/filesystem.d.ts +121 -0
- package/dist/src/server/sessions/stores/filesystem.d.ts.map +1 -0
- package/dist/src/server/sessions/stores/index.d.ts +94 -0
- package/dist/src/server/sessions/stores/index.d.ts.map +1 -0
- package/dist/src/server/sessions/stores/memory.d.ts +82 -0
- package/dist/src/server/sessions/stores/memory.d.ts.map +1 -0
- package/dist/src/server/sessions/stores/redis.d.ts +164 -0
- package/dist/src/server/sessions/stores/redis.d.ts.map +1 -0
- package/dist/src/server/sessions/streams/index.d.ts +77 -0
- package/dist/src/server/sessions/streams/index.d.ts.map +1 -0
- package/dist/src/server/sessions/streams/memory.d.ts +76 -0
- package/dist/src/server/sessions/streams/memory.d.ts.map +1 -0
- package/dist/src/server/sessions/streams/redis.d.ts +146 -0
- package/dist/src/server/sessions/streams/redis.d.ts.map +1 -0
- package/dist/src/server/types/common.d.ts +82 -28
- package/dist/src/server/types/common.d.ts.map +1 -1
- package/dist/src/server/types/widget.d.ts +2 -2
- package/dist/src/server/types/widget.d.ts.map +1 -1
- package/dist/src/server/utils/response-helpers.d.ts +4 -2
- package/dist/src/server/utils/response-helpers.d.ts.map +1 -1
- package/dist/src/server/widgets/mount-widgets-dev.d.ts.map +1 -1
- package/dist/src/server/widgets/ui-resource-registration.d.ts.map +1 -1
- package/dist/src/task_managers/index.d.ts +10 -0
- package/dist/src/task_managers/index.d.ts.map +1 -1
- package/dist/src/task_managers/sse.d.ts +34 -1
- package/dist/src/task_managers/sse.d.ts.map +1 -1
- package/dist/src/task_managers/streamable_http.d.ts +8 -2
- package/dist/src/task_managers/streamable_http.d.ts.map +1 -1
- package/dist/src/telemetry/telemetry.d.ts +1 -0
- package/dist/src/telemetry/telemetry.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/{tool-execution-helpers-EYAIJERC.js → tool-execution-helpers-ZUA5D5IO.js} +2 -2
- package/dist/tsup.config.d.ts.map +1 -1
- package/package.json +62 -52
- package/dist/chunk-GVU7C2ZD.js +0 -12
- package/dist/chunk-JZNXOM7C.js +0 -204
- package/dist/chunk-XKTBHYNM.js +0 -491
- package/dist/src/client/prompts.cjs +0 -407
- package/dist/src/client/prompts.d.ts.map +0 -1
- package/dist/src/client/prompts.js +0 -11
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Tel
|
|
6
|
-
} from "./chunk-JPKFN73V.js";
|
|
2
|
+
Tel,
|
|
3
|
+
Telemetry
|
|
4
|
+
} from "./chunk-ZLZOOXMJ.js";
|
|
7
5
|
import {
|
|
8
6
|
logger
|
|
9
7
|
} from "./chunk-FRUZDWXH.js";
|
|
@@ -284,6 +282,612 @@ var MCPSession = class {
|
|
|
284
282
|
}
|
|
285
283
|
};
|
|
286
284
|
|
|
285
|
+
// src/client/base.ts
|
|
286
|
+
var BaseMCPClient = class {
|
|
287
|
+
static {
|
|
288
|
+
__name(this, "BaseMCPClient");
|
|
289
|
+
}
|
|
290
|
+
config = {};
|
|
291
|
+
sessions = {};
|
|
292
|
+
activeSessions = [];
|
|
293
|
+
constructor(config) {
|
|
294
|
+
if (config) {
|
|
295
|
+
this.config = config;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
static fromDict(_cfg) {
|
|
299
|
+
throw new Error("fromDict must be implemented by concrete class");
|
|
300
|
+
}
|
|
301
|
+
addServer(name, serverConfig) {
|
|
302
|
+
this.config.mcpServers = this.config.mcpServers || {};
|
|
303
|
+
this.config.mcpServers[name] = serverConfig;
|
|
304
|
+
Tel.getInstance().trackClientAddServer(name, serverConfig);
|
|
305
|
+
}
|
|
306
|
+
removeServer(name) {
|
|
307
|
+
if (this.config.mcpServers?.[name]) {
|
|
308
|
+
delete this.config.mcpServers[name];
|
|
309
|
+
this.activeSessions = this.activeSessions.filter((n) => n !== name);
|
|
310
|
+
Tel.getInstance().trackClientRemoveServer(name);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
getServerNames() {
|
|
314
|
+
return Object.keys(this.config.mcpServers ?? {});
|
|
315
|
+
}
|
|
316
|
+
getServerConfig(name) {
|
|
317
|
+
return this.config.mcpServers?.[name];
|
|
318
|
+
}
|
|
319
|
+
getConfig() {
|
|
320
|
+
return this.config ?? {};
|
|
321
|
+
}
|
|
322
|
+
async createSession(serverName, autoInitialize = true) {
|
|
323
|
+
const servers = this.config.mcpServers ?? {};
|
|
324
|
+
if (Object.keys(servers).length === 0) {
|
|
325
|
+
logger.warn("No MCP servers defined in config");
|
|
326
|
+
}
|
|
327
|
+
if (!servers[serverName]) {
|
|
328
|
+
throw new Error(`Server '${serverName}' not found in config`);
|
|
329
|
+
}
|
|
330
|
+
const connector = this.createConnectorFromConfig(servers[serverName]);
|
|
331
|
+
const session = new MCPSession(connector);
|
|
332
|
+
if (autoInitialize) {
|
|
333
|
+
await session.initialize();
|
|
334
|
+
}
|
|
335
|
+
this.sessions[serverName] = session;
|
|
336
|
+
if (!this.activeSessions.includes(serverName)) {
|
|
337
|
+
this.activeSessions.push(serverName);
|
|
338
|
+
}
|
|
339
|
+
return session;
|
|
340
|
+
}
|
|
341
|
+
async createAllSessions(autoInitialize = true) {
|
|
342
|
+
const servers = this.config.mcpServers ?? {};
|
|
343
|
+
if (Object.keys(servers).length === 0) {
|
|
344
|
+
logger.warn("No MCP servers defined in config");
|
|
345
|
+
}
|
|
346
|
+
for (const name of Object.keys(servers)) {
|
|
347
|
+
await this.createSession(name, autoInitialize);
|
|
348
|
+
}
|
|
349
|
+
return this.sessions;
|
|
350
|
+
}
|
|
351
|
+
getSession(serverName) {
|
|
352
|
+
const session = this.sessions[serverName];
|
|
353
|
+
if (!session) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
return session;
|
|
357
|
+
}
|
|
358
|
+
requireSession(serverName) {
|
|
359
|
+
const session = this.sessions[serverName];
|
|
360
|
+
if (!session) {
|
|
361
|
+
throw new Error(
|
|
362
|
+
`Session '${serverName}' not found. Available sessions: ${this.activeSessions.join(", ") || "none"}`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
return session;
|
|
366
|
+
}
|
|
367
|
+
getAllActiveSessions() {
|
|
368
|
+
return Object.fromEntries(
|
|
369
|
+
this.activeSessions.map((n) => [n, this.sessions[n]])
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
async closeSession(serverName) {
|
|
373
|
+
const session = this.sessions[serverName];
|
|
374
|
+
if (!session) {
|
|
375
|
+
logger.warn(
|
|
376
|
+
`No session exists for server ${serverName}, nothing to close`
|
|
377
|
+
);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
try {
|
|
381
|
+
logger.debug(`Closing session for server ${serverName}`);
|
|
382
|
+
await session.disconnect();
|
|
383
|
+
} catch (e) {
|
|
384
|
+
logger.error(`Error closing session for server '${serverName}': ${e}`);
|
|
385
|
+
} finally {
|
|
386
|
+
delete this.sessions[serverName];
|
|
387
|
+
this.activeSessions = this.activeSessions.filter((n) => n !== serverName);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
async closeAllSessions() {
|
|
391
|
+
const serverNames = Object.keys(this.sessions);
|
|
392
|
+
const errors = [];
|
|
393
|
+
for (const serverName of serverNames) {
|
|
394
|
+
try {
|
|
395
|
+
logger.debug(`Closing session for server ${serverName}`);
|
|
396
|
+
await this.closeSession(serverName);
|
|
397
|
+
} catch (e) {
|
|
398
|
+
const errorMsg = `Failed to close session for server '${serverName}': ${e}`;
|
|
399
|
+
logger.error(errorMsg);
|
|
400
|
+
errors.push(errorMsg);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (errors.length) {
|
|
404
|
+
logger.error(
|
|
405
|
+
`Encountered ${errors.length} errors while closing sessions`
|
|
406
|
+
);
|
|
407
|
+
} else {
|
|
408
|
+
logger.debug("All sessions closed successfully");
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// src/connectors/base.ts
|
|
414
|
+
import {
|
|
415
|
+
ListRootsRequestSchema,
|
|
416
|
+
CreateMessageRequestSchema,
|
|
417
|
+
ElicitRequestSchema
|
|
418
|
+
} from "@mcp-use/modelcontextprotocol-sdk/types.js";
|
|
419
|
+
var BaseConnector = class {
|
|
420
|
+
static {
|
|
421
|
+
__name(this, "BaseConnector");
|
|
422
|
+
}
|
|
423
|
+
client = null;
|
|
424
|
+
connectionManager = null;
|
|
425
|
+
toolsCache = null;
|
|
426
|
+
capabilitiesCache = null;
|
|
427
|
+
serverInfoCache = null;
|
|
428
|
+
connected = false;
|
|
429
|
+
opts;
|
|
430
|
+
notificationHandlers = [];
|
|
431
|
+
rootsCache = [];
|
|
432
|
+
constructor(opts = {}) {
|
|
433
|
+
this.opts = opts;
|
|
434
|
+
if (opts.roots) {
|
|
435
|
+
this.rootsCache = [...opts.roots];
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Track connector initialization event
|
|
440
|
+
* Should be called by subclasses after successful connection
|
|
441
|
+
*/
|
|
442
|
+
trackConnectorInit(data) {
|
|
443
|
+
const connectorType = this.constructor.name;
|
|
444
|
+
Telemetry.getInstance().trackConnectorInit({
|
|
445
|
+
connectorType,
|
|
446
|
+
...data
|
|
447
|
+
}).catch((e) => logger.debug(`Failed to track connector init: ${e}`));
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Register a handler for server notifications
|
|
451
|
+
*
|
|
452
|
+
* @param handler - Function to call when a notification is received
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```typescript
|
|
456
|
+
* connector.onNotification((notification) => {
|
|
457
|
+
* console.log(`Received: ${notification.method}`, notification.params);
|
|
458
|
+
* });
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
onNotification(handler) {
|
|
462
|
+
this.notificationHandlers.push(handler);
|
|
463
|
+
if (this.client) {
|
|
464
|
+
this.setupNotificationHandler();
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Internal: wire notification handlers to the SDK client
|
|
469
|
+
* Includes automatic handling for list_changed notifications per MCP spec
|
|
470
|
+
*/
|
|
471
|
+
setupNotificationHandler() {
|
|
472
|
+
if (!this.client) return;
|
|
473
|
+
this.client.fallbackNotificationHandler = async (notification) => {
|
|
474
|
+
switch (notification.method) {
|
|
475
|
+
case "notifications/tools/list_changed":
|
|
476
|
+
await this.refreshToolsCache();
|
|
477
|
+
break;
|
|
478
|
+
case "notifications/resources/list_changed":
|
|
479
|
+
await this.onResourcesListChanged();
|
|
480
|
+
break;
|
|
481
|
+
case "notifications/prompts/list_changed":
|
|
482
|
+
await this.onPromptsListChanged();
|
|
483
|
+
break;
|
|
484
|
+
default:
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
for (const handler of this.notificationHandlers) {
|
|
488
|
+
try {
|
|
489
|
+
await handler(notification);
|
|
490
|
+
} catch (err) {
|
|
491
|
+
logger.error("Error in notification handler:", err);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Auto-refresh tools cache when server sends tools/list_changed notification
|
|
498
|
+
*/
|
|
499
|
+
async refreshToolsCache() {
|
|
500
|
+
if (!this.client) return;
|
|
501
|
+
try {
|
|
502
|
+
logger.debug(
|
|
503
|
+
"[Auto] Refreshing tools cache due to list_changed notification"
|
|
504
|
+
);
|
|
505
|
+
const result = await this.client.listTools();
|
|
506
|
+
this.toolsCache = result.tools ?? [];
|
|
507
|
+
logger.debug(
|
|
508
|
+
`[Auto] Refreshed tools cache: ${this.toolsCache.length} tools`
|
|
509
|
+
);
|
|
510
|
+
} catch (err) {
|
|
511
|
+
logger.warn("[Auto] Failed to refresh tools cache:", err);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Called when server sends resources/list_changed notification
|
|
516
|
+
* Resources aren't cached by default, but we log for user awareness
|
|
517
|
+
*/
|
|
518
|
+
async onResourcesListChanged() {
|
|
519
|
+
logger.debug(
|
|
520
|
+
"[Auto] Resources list changed - clients should re-fetch if needed"
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Called when server sends prompts/list_changed notification
|
|
525
|
+
* Prompts aren't cached by default, but we log for user awareness
|
|
526
|
+
*/
|
|
527
|
+
async onPromptsListChanged() {
|
|
528
|
+
logger.debug(
|
|
529
|
+
"[Auto] Prompts list changed - clients should re-fetch if needed"
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Set roots and notify the server.
|
|
534
|
+
* Roots represent directories or files that the client has access to.
|
|
535
|
+
*
|
|
536
|
+
* @param roots - Array of Root objects with `uri` (must start with "file://") and optional `name`
|
|
537
|
+
*
|
|
538
|
+
* @example
|
|
539
|
+
* ```typescript
|
|
540
|
+
* await connector.setRoots([
|
|
541
|
+
* { uri: "file:///home/user/project", name: "My Project" },
|
|
542
|
+
* { uri: "file:///home/user/data" }
|
|
543
|
+
* ]);
|
|
544
|
+
* ```
|
|
545
|
+
*/
|
|
546
|
+
async setRoots(roots) {
|
|
547
|
+
this.rootsCache = [...roots];
|
|
548
|
+
if (this.client) {
|
|
549
|
+
logger.debug(
|
|
550
|
+
`Sending roots/list_changed notification with ${roots.length} root(s)`
|
|
551
|
+
);
|
|
552
|
+
await this.client.sendRootsListChanged();
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Get the current roots.
|
|
557
|
+
*/
|
|
558
|
+
getRoots() {
|
|
559
|
+
return [...this.rootsCache];
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Internal: set up roots/list request handler.
|
|
563
|
+
* This is called after the client connects to register the handler for server requests.
|
|
564
|
+
*/
|
|
565
|
+
setupRootsHandler() {
|
|
566
|
+
if (!this.client) return;
|
|
567
|
+
this.client.setRequestHandler(
|
|
568
|
+
ListRootsRequestSchema,
|
|
569
|
+
async (_request, _extra) => {
|
|
570
|
+
logger.debug(
|
|
571
|
+
`Server requested roots list, returning ${this.rootsCache.length} root(s)`
|
|
572
|
+
);
|
|
573
|
+
return { roots: this.rootsCache };
|
|
574
|
+
}
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Internal: set up sampling/createMessage request handler.
|
|
579
|
+
* This is called after the client connects to register the handler for sampling requests.
|
|
580
|
+
*/
|
|
581
|
+
setupSamplingHandler() {
|
|
582
|
+
if (!this.client) {
|
|
583
|
+
logger.debug("setupSamplingHandler: No client available");
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (!this.opts.samplingCallback) {
|
|
587
|
+
logger.debug("setupSamplingHandler: No sampling callback provided");
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
logger.debug("setupSamplingHandler: Setting up sampling request handler");
|
|
591
|
+
this.client.setRequestHandler(
|
|
592
|
+
CreateMessageRequestSchema,
|
|
593
|
+
async (request, _extra) => {
|
|
594
|
+
logger.debug("Server requested sampling, forwarding to callback");
|
|
595
|
+
return await this.opts.samplingCallback(request.params);
|
|
596
|
+
}
|
|
597
|
+
);
|
|
598
|
+
logger.debug(
|
|
599
|
+
"setupSamplingHandler: Sampling handler registered successfully"
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Internal: set up elicitation/create request handler.
|
|
604
|
+
* This is called after the client connects to register the handler for elicitation requests.
|
|
605
|
+
*/
|
|
606
|
+
setupElicitationHandler() {
|
|
607
|
+
if (!this.client) {
|
|
608
|
+
logger.debug("setupElicitationHandler: No client available");
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
if (!this.opts.elicitationCallback) {
|
|
612
|
+
logger.debug("setupElicitationHandler: No elicitation callback provided");
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
logger.debug(
|
|
616
|
+
"setupElicitationHandler: Setting up elicitation request handler"
|
|
617
|
+
);
|
|
618
|
+
this.client.setRequestHandler(
|
|
619
|
+
ElicitRequestSchema,
|
|
620
|
+
async (request, _extra) => {
|
|
621
|
+
logger.debug("Server requested elicitation, forwarding to callback");
|
|
622
|
+
return await this.opts.elicitationCallback(request.params);
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
logger.debug(
|
|
626
|
+
"setupElicitationHandler: Elicitation handler registered successfully"
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
/** Disconnect and release resources. */
|
|
630
|
+
async disconnect() {
|
|
631
|
+
if (!this.connected) {
|
|
632
|
+
logger.debug("Not connected to MCP implementation");
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
logger.debug("Disconnecting from MCP implementation");
|
|
636
|
+
await this.cleanupResources();
|
|
637
|
+
this.connected = false;
|
|
638
|
+
logger.debug("Disconnected from MCP implementation");
|
|
639
|
+
}
|
|
640
|
+
/** Check if the client is connected */
|
|
641
|
+
get isClientConnected() {
|
|
642
|
+
return this.client != null;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Initialise the MCP session **after** `connect()` has succeeded.
|
|
646
|
+
*
|
|
647
|
+
* In the SDK, `Client.connect(transport)` automatically performs the
|
|
648
|
+
* protocol‑level `initialize` handshake, so we only need to cache the list of
|
|
649
|
+
* tools and expose some server info.
|
|
650
|
+
*/
|
|
651
|
+
async initialize(defaultRequestOptions = this.opts.defaultRequestOptions ?? {}) {
|
|
652
|
+
if (!this.client) {
|
|
653
|
+
throw new Error("MCP client is not connected");
|
|
654
|
+
}
|
|
655
|
+
logger.debug("Caching server capabilities & tools");
|
|
656
|
+
const capabilities = this.client.getServerCapabilities();
|
|
657
|
+
this.capabilitiesCache = capabilities || null;
|
|
658
|
+
const serverInfo = this.client.getServerVersion();
|
|
659
|
+
this.serverInfoCache = serverInfo || null;
|
|
660
|
+
const listToolsRes = await this.client.listTools(
|
|
661
|
+
void 0,
|
|
662
|
+
defaultRequestOptions
|
|
663
|
+
);
|
|
664
|
+
this.toolsCache = listToolsRes.tools ?? [];
|
|
665
|
+
logger.debug(`Fetched ${this.toolsCache.length} tools from server`);
|
|
666
|
+
logger.debug("Server capabilities:", capabilities);
|
|
667
|
+
logger.debug("Server info:", serverInfo);
|
|
668
|
+
return capabilities;
|
|
669
|
+
}
|
|
670
|
+
/** Lazily expose the cached tools list. */
|
|
671
|
+
get tools() {
|
|
672
|
+
if (!this.toolsCache) {
|
|
673
|
+
throw new Error("MCP client is not initialized; call initialize() first");
|
|
674
|
+
}
|
|
675
|
+
return this.toolsCache;
|
|
676
|
+
}
|
|
677
|
+
/** Expose cached server capabilities. */
|
|
678
|
+
get serverCapabilities() {
|
|
679
|
+
return this.capabilitiesCache || {};
|
|
680
|
+
}
|
|
681
|
+
/** Expose cached server info. */
|
|
682
|
+
get serverInfo() {
|
|
683
|
+
return this.serverInfoCache;
|
|
684
|
+
}
|
|
685
|
+
/** Call a tool on the server. */
|
|
686
|
+
async callTool(name, args, options) {
|
|
687
|
+
if (!this.client) {
|
|
688
|
+
throw new Error("MCP client is not connected");
|
|
689
|
+
}
|
|
690
|
+
const enhancedOptions = options ? { ...options } : void 0;
|
|
691
|
+
if (enhancedOptions?.resetTimeoutOnProgress && !enhancedOptions.onprogress) {
|
|
692
|
+
enhancedOptions.onprogress = () => {
|
|
693
|
+
};
|
|
694
|
+
logger.debug(
|
|
695
|
+
`[BaseConnector] Added onprogress callback for tool '${name}' to enable progressToken`
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
logger.debug(`Calling tool '${name}' with args`, args);
|
|
699
|
+
const res = await this.client.callTool(
|
|
700
|
+
{ name, arguments: args },
|
|
701
|
+
void 0,
|
|
702
|
+
enhancedOptions
|
|
703
|
+
);
|
|
704
|
+
logger.debug(`Tool '${name}' returned`, res);
|
|
705
|
+
return res;
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* List all available tools from the MCP server.
|
|
709
|
+
* This method fetches fresh tools from the server, unlike the `tools` getter which returns cached tools.
|
|
710
|
+
*
|
|
711
|
+
* @param options - Optional request options
|
|
712
|
+
* @returns Array of available tools
|
|
713
|
+
*/
|
|
714
|
+
async listTools(options) {
|
|
715
|
+
if (!this.client) {
|
|
716
|
+
throw new Error("MCP client is not connected");
|
|
717
|
+
}
|
|
718
|
+
const result = await this.client.listTools(void 0, options);
|
|
719
|
+
return result.tools ?? [];
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* List resources from the server with optional pagination
|
|
723
|
+
*
|
|
724
|
+
* @param cursor - Optional cursor for pagination
|
|
725
|
+
* @param options - Request options
|
|
726
|
+
* @returns Resource list with optional nextCursor for pagination
|
|
727
|
+
*/
|
|
728
|
+
async listResources(cursor, options) {
|
|
729
|
+
if (!this.client) {
|
|
730
|
+
throw new Error("MCP client is not connected");
|
|
731
|
+
}
|
|
732
|
+
logger.debug("Listing resources", cursor ? `with cursor: ${cursor}` : "");
|
|
733
|
+
return await this.client.listResources({ cursor }, options);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* List all resources from the server, automatically handling pagination
|
|
737
|
+
*
|
|
738
|
+
* @param options - Request options
|
|
739
|
+
* @returns Complete list of all resources
|
|
740
|
+
*/
|
|
741
|
+
async listAllResources(options) {
|
|
742
|
+
if (!this.client) {
|
|
743
|
+
throw new Error("MCP client is not connected");
|
|
744
|
+
}
|
|
745
|
+
if (!this.capabilitiesCache?.resources) {
|
|
746
|
+
logger.debug("Server does not advertise resources capability, skipping");
|
|
747
|
+
return { resources: [] };
|
|
748
|
+
}
|
|
749
|
+
try {
|
|
750
|
+
logger.debug("Listing all resources (with auto-pagination)");
|
|
751
|
+
const allResources = [];
|
|
752
|
+
let cursor = void 0;
|
|
753
|
+
do {
|
|
754
|
+
const result = await this.client.listResources({ cursor }, options);
|
|
755
|
+
allResources.push(...result.resources || []);
|
|
756
|
+
cursor = result.nextCursor;
|
|
757
|
+
} while (cursor);
|
|
758
|
+
return { resources: allResources };
|
|
759
|
+
} catch (err) {
|
|
760
|
+
const error = err;
|
|
761
|
+
if (error.code === -32601) {
|
|
762
|
+
logger.debug("Server advertised resources but method not found");
|
|
763
|
+
return { resources: [] };
|
|
764
|
+
}
|
|
765
|
+
throw err;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* List resource templates from the server
|
|
770
|
+
*
|
|
771
|
+
* @param options - Request options
|
|
772
|
+
* @returns List of available resource templates
|
|
773
|
+
*/
|
|
774
|
+
async listResourceTemplates(options) {
|
|
775
|
+
if (!this.client) {
|
|
776
|
+
throw new Error("MCP client is not connected");
|
|
777
|
+
}
|
|
778
|
+
logger.debug("Listing resource templates");
|
|
779
|
+
return await this.client.listResourceTemplates(void 0, options);
|
|
780
|
+
}
|
|
781
|
+
/** Read a resource by URI. */
|
|
782
|
+
async readResource(uri, options) {
|
|
783
|
+
if (!this.client) {
|
|
784
|
+
throw new Error("MCP client is not connected");
|
|
785
|
+
}
|
|
786
|
+
logger.debug(`Reading resource ${uri}`);
|
|
787
|
+
const res = await this.client.readResource({ uri }, options);
|
|
788
|
+
return res;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Subscribe to resource updates
|
|
792
|
+
*
|
|
793
|
+
* @param uri - URI of the resource to subscribe to
|
|
794
|
+
* @param options - Request options
|
|
795
|
+
*/
|
|
796
|
+
async subscribeToResource(uri, options) {
|
|
797
|
+
if (!this.client) {
|
|
798
|
+
throw new Error("MCP client is not connected");
|
|
799
|
+
}
|
|
800
|
+
logger.debug(`Subscribing to resource: ${uri}`);
|
|
801
|
+
return await this.client.subscribeResource({ uri }, options);
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Unsubscribe from resource updates
|
|
805
|
+
*
|
|
806
|
+
* @param uri - URI of the resource to unsubscribe from
|
|
807
|
+
* @param options - Request options
|
|
808
|
+
*/
|
|
809
|
+
async unsubscribeFromResource(uri, options) {
|
|
810
|
+
if (!this.client) {
|
|
811
|
+
throw new Error("MCP client is not connected");
|
|
812
|
+
}
|
|
813
|
+
logger.debug(`Unsubscribing from resource: ${uri}`);
|
|
814
|
+
return await this.client.unsubscribeResource({ uri }, options);
|
|
815
|
+
}
|
|
816
|
+
async listPrompts() {
|
|
817
|
+
if (!this.client) {
|
|
818
|
+
throw new Error("MCP client is not connected");
|
|
819
|
+
}
|
|
820
|
+
if (!this.capabilitiesCache?.prompts) {
|
|
821
|
+
logger.debug("Server does not advertise prompts capability, skipping");
|
|
822
|
+
return { prompts: [] };
|
|
823
|
+
}
|
|
824
|
+
try {
|
|
825
|
+
logger.debug("Listing prompts");
|
|
826
|
+
return await this.client.listPrompts();
|
|
827
|
+
} catch (err) {
|
|
828
|
+
const error = err;
|
|
829
|
+
if (error.code === -32601) {
|
|
830
|
+
logger.debug("Server advertised prompts but method not found");
|
|
831
|
+
return { prompts: [] };
|
|
832
|
+
}
|
|
833
|
+
throw err;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
async getPrompt(name, args) {
|
|
837
|
+
if (!this.client) {
|
|
838
|
+
throw new Error("MCP client is not connected");
|
|
839
|
+
}
|
|
840
|
+
logger.debug(`Getting prompt ${name}`);
|
|
841
|
+
return await this.client.getPrompt({ name, arguments: args });
|
|
842
|
+
}
|
|
843
|
+
/** Send a raw request through the client. */
|
|
844
|
+
async request(method, params = null, options) {
|
|
845
|
+
if (!this.client) {
|
|
846
|
+
throw new Error("MCP client is not connected");
|
|
847
|
+
}
|
|
848
|
+
logger.debug(`Sending raw request '${method}' with params`, params);
|
|
849
|
+
return await this.client.request(
|
|
850
|
+
{ method, params: params ?? {} },
|
|
851
|
+
void 0,
|
|
852
|
+
options
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Helper to tear down the client & connection manager safely.
|
|
857
|
+
*/
|
|
858
|
+
async cleanupResources() {
|
|
859
|
+
const issues = [];
|
|
860
|
+
if (this.client) {
|
|
861
|
+
try {
|
|
862
|
+
if (typeof this.client.close === "function") {
|
|
863
|
+
await this.client.close();
|
|
864
|
+
}
|
|
865
|
+
} catch (e) {
|
|
866
|
+
const msg = `Error closing client: ${e}`;
|
|
867
|
+
logger.warn(msg);
|
|
868
|
+
issues.push(msg);
|
|
869
|
+
} finally {
|
|
870
|
+
this.client = null;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (this.connectionManager) {
|
|
874
|
+
try {
|
|
875
|
+
await this.connectionManager.stop();
|
|
876
|
+
} catch (e) {
|
|
877
|
+
const msg = `Error stopping connection manager: ${e}`;
|
|
878
|
+
logger.warn(msg);
|
|
879
|
+
issues.push(msg);
|
|
880
|
+
} finally {
|
|
881
|
+
this.connectionManager = null;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
this.toolsCache = null;
|
|
885
|
+
if (issues.length) {
|
|
886
|
+
logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
|
|
287
891
|
// src/connectors/http.ts
|
|
288
892
|
import { Client } from "@mcp-use/modelcontextprotocol-sdk/client/index.js";
|
|
289
893
|
import {
|
|
@@ -419,6 +1023,7 @@ var SseConnectionManager = class extends ConnectionManager {
|
|
|
419
1023
|
url;
|
|
420
1024
|
opts;
|
|
421
1025
|
_transport = null;
|
|
1026
|
+
reinitializing = false;
|
|
422
1027
|
/**
|
|
423
1028
|
* Create an SSE connection manager.
|
|
424
1029
|
*
|
|
@@ -431,12 +1036,53 @@ var SseConnectionManager = class extends ConnectionManager {
|
|
|
431
1036
|
this.opts = opts;
|
|
432
1037
|
}
|
|
433
1038
|
/**
|
|
434
|
-
* Spawn a new `SSEClientTransport` and
|
|
1039
|
+
* Spawn a new `SSEClientTransport` and wrap it with 404 handling.
|
|
1040
|
+
* Per MCP spec, clients MUST re-initialize when receiving 404 for stale sessions.
|
|
435
1041
|
*/
|
|
436
1042
|
async establishConnection() {
|
|
437
|
-
|
|
1043
|
+
const transport = new SSEClientTransport(this.url, this.opts);
|
|
1044
|
+
const originalSend = transport.send.bind(transport);
|
|
1045
|
+
transport.send = async (message) => {
|
|
1046
|
+
const sendMessage = /* @__PURE__ */ __name(async (msg) => {
|
|
1047
|
+
if (Array.isArray(msg)) {
|
|
1048
|
+
for (const singleMsg of msg) {
|
|
1049
|
+
await originalSend(singleMsg);
|
|
1050
|
+
}
|
|
1051
|
+
} else {
|
|
1052
|
+
await originalSend(msg);
|
|
1053
|
+
}
|
|
1054
|
+
}, "sendMessage");
|
|
1055
|
+
try {
|
|
1056
|
+
await sendMessage(message);
|
|
1057
|
+
} catch (error) {
|
|
1058
|
+
if (error?.code === 404 && transport.sessionId && !this.reinitializing) {
|
|
1059
|
+
logger.warn(
|
|
1060
|
+
`[SSE] Session not found (404), re-initializing per MCP spec...`
|
|
1061
|
+
);
|
|
1062
|
+
this.reinitializing = true;
|
|
1063
|
+
try {
|
|
1064
|
+
transport.sessionId = void 0;
|
|
1065
|
+
await this.reinitialize(transport);
|
|
1066
|
+
logger.info(`[SSE] Re-initialization successful, retrying request`);
|
|
1067
|
+
await sendMessage(message);
|
|
1068
|
+
} finally {
|
|
1069
|
+
this.reinitializing = false;
|
|
1070
|
+
}
|
|
1071
|
+
} else {
|
|
1072
|
+
throw error;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
this._transport = transport;
|
|
438
1077
|
logger.debug(`${this.constructor.name} connected successfully`);
|
|
439
|
-
return
|
|
1078
|
+
return transport;
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Re-initialize the transport with a new session
|
|
1082
|
+
* This is called when the server returns 404 for a stale session
|
|
1083
|
+
*/
|
|
1084
|
+
async reinitialize(transport) {
|
|
1085
|
+
logger.debug(`[SSE] Re-initialization triggered`);
|
|
440
1086
|
}
|
|
441
1087
|
/**
|
|
442
1088
|
* Close the underlying transport and clean up resources.
|
|
@@ -465,6 +1111,7 @@ var HttpConnector = class extends BaseConnector {
|
|
|
465
1111
|
sseReadTimeout;
|
|
466
1112
|
clientInfo;
|
|
467
1113
|
preferSse;
|
|
1114
|
+
disableSseFallback;
|
|
468
1115
|
transportType = null;
|
|
469
1116
|
streamableTransport = null;
|
|
470
1117
|
constructor(baseUrl, opts = {}) {
|
|
@@ -481,6 +1128,7 @@ var HttpConnector = class extends BaseConnector {
|
|
|
481
1128
|
version: "1.0.0"
|
|
482
1129
|
};
|
|
483
1130
|
this.preferSse = opts.preferSse ?? false;
|
|
1131
|
+
this.disableSseFallback = opts.disableSseFallback ?? false;
|
|
484
1132
|
}
|
|
485
1133
|
/** Establish connection to the MCP implementation via HTTP (streamable or SSE). */
|
|
486
1134
|
async connect() {
|
|
@@ -537,6 +1185,13 @@ var HttpConnector = class extends BaseConnector {
|
|
|
537
1185
|
authError.code = 401;
|
|
538
1186
|
throw authError;
|
|
539
1187
|
}
|
|
1188
|
+
if (this.disableSseFallback) {
|
|
1189
|
+
logger.info("SSE fallback disabled - failing connection");
|
|
1190
|
+
await this.cleanupResources();
|
|
1191
|
+
throw new Error(
|
|
1192
|
+
`Streamable HTTP connection failed: ${fallbackReason}. SSE fallback is disabled.`
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
540
1195
|
logger.info("\u{1F504} Falling back to SSE transport...");
|
|
541
1196
|
try {
|
|
542
1197
|
await this.connectWithSse(baseUrl);
|
|
@@ -727,137 +1382,10 @@ var HttpConnector = class extends BaseConnector {
|
|
|
727
1382
|
}
|
|
728
1383
|
};
|
|
729
1384
|
|
|
730
|
-
// src/client/base.ts
|
|
731
|
-
var BaseMCPClient = class {
|
|
732
|
-
static {
|
|
733
|
-
__name(this, "BaseMCPClient");
|
|
734
|
-
}
|
|
735
|
-
config = {};
|
|
736
|
-
sessions = {};
|
|
737
|
-
activeSessions = [];
|
|
738
|
-
constructor(config) {
|
|
739
|
-
if (config) {
|
|
740
|
-
this.config = config;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
static fromDict(_cfg) {
|
|
744
|
-
throw new Error("fromDict must be implemented by concrete class");
|
|
745
|
-
}
|
|
746
|
-
addServer(name, serverConfig) {
|
|
747
|
-
this.config.mcpServers = this.config.mcpServers || {};
|
|
748
|
-
this.config.mcpServers[name] = serverConfig;
|
|
749
|
-
Tel.getInstance().trackClientAddServer(name, serverConfig);
|
|
750
|
-
}
|
|
751
|
-
removeServer(name) {
|
|
752
|
-
if (this.config.mcpServers?.[name]) {
|
|
753
|
-
delete this.config.mcpServers[name];
|
|
754
|
-
this.activeSessions = this.activeSessions.filter((n) => n !== name);
|
|
755
|
-
Tel.getInstance().trackClientRemoveServer(name);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
getServerNames() {
|
|
759
|
-
return Object.keys(this.config.mcpServers ?? {});
|
|
760
|
-
}
|
|
761
|
-
getServerConfig(name) {
|
|
762
|
-
return this.config.mcpServers?.[name];
|
|
763
|
-
}
|
|
764
|
-
getConfig() {
|
|
765
|
-
return this.config ?? {};
|
|
766
|
-
}
|
|
767
|
-
async createSession(serverName, autoInitialize = true) {
|
|
768
|
-
const servers = this.config.mcpServers ?? {};
|
|
769
|
-
if (Object.keys(servers).length === 0) {
|
|
770
|
-
logger.warn("No MCP servers defined in config");
|
|
771
|
-
}
|
|
772
|
-
if (!servers[serverName]) {
|
|
773
|
-
throw new Error(`Server '${serverName}' not found in config`);
|
|
774
|
-
}
|
|
775
|
-
const connector = this.createConnectorFromConfig(servers[serverName]);
|
|
776
|
-
const session = new MCPSession(connector);
|
|
777
|
-
if (autoInitialize) {
|
|
778
|
-
await session.initialize();
|
|
779
|
-
}
|
|
780
|
-
this.sessions[serverName] = session;
|
|
781
|
-
if (!this.activeSessions.includes(serverName)) {
|
|
782
|
-
this.activeSessions.push(serverName);
|
|
783
|
-
}
|
|
784
|
-
return session;
|
|
785
|
-
}
|
|
786
|
-
async createAllSessions(autoInitialize = true) {
|
|
787
|
-
const servers = this.config.mcpServers ?? {};
|
|
788
|
-
if (Object.keys(servers).length === 0) {
|
|
789
|
-
logger.warn("No MCP servers defined in config");
|
|
790
|
-
}
|
|
791
|
-
for (const name of Object.keys(servers)) {
|
|
792
|
-
await this.createSession(name, autoInitialize);
|
|
793
|
-
}
|
|
794
|
-
return this.sessions;
|
|
795
|
-
}
|
|
796
|
-
getSession(serverName) {
|
|
797
|
-
const session = this.sessions[serverName];
|
|
798
|
-
if (!session) {
|
|
799
|
-
return null;
|
|
800
|
-
}
|
|
801
|
-
return session;
|
|
802
|
-
}
|
|
803
|
-
requireSession(serverName) {
|
|
804
|
-
const session = this.sessions[serverName];
|
|
805
|
-
if (!session) {
|
|
806
|
-
throw new Error(
|
|
807
|
-
`Session '${serverName}' not found. Available sessions: ${this.activeSessions.join(", ") || "none"}`
|
|
808
|
-
);
|
|
809
|
-
}
|
|
810
|
-
return session;
|
|
811
|
-
}
|
|
812
|
-
getAllActiveSessions() {
|
|
813
|
-
return Object.fromEntries(
|
|
814
|
-
this.activeSessions.map((n) => [n, this.sessions[n]])
|
|
815
|
-
);
|
|
816
|
-
}
|
|
817
|
-
async closeSession(serverName) {
|
|
818
|
-
const session = this.sessions[serverName];
|
|
819
|
-
if (!session) {
|
|
820
|
-
logger.warn(
|
|
821
|
-
`No session exists for server ${serverName}, nothing to close`
|
|
822
|
-
);
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
|
-
try {
|
|
826
|
-
logger.debug(`Closing session for server ${serverName}`);
|
|
827
|
-
await session.disconnect();
|
|
828
|
-
} catch (e) {
|
|
829
|
-
logger.error(`Error closing session for server '${serverName}': ${e}`);
|
|
830
|
-
} finally {
|
|
831
|
-
delete this.sessions[serverName];
|
|
832
|
-
this.activeSessions = this.activeSessions.filter((n) => n !== serverName);
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
async closeAllSessions() {
|
|
836
|
-
const serverNames = Object.keys(this.sessions);
|
|
837
|
-
const errors = [];
|
|
838
|
-
for (const serverName of serverNames) {
|
|
839
|
-
try {
|
|
840
|
-
logger.debug(`Closing session for server ${serverName}`);
|
|
841
|
-
await this.closeSession(serverName);
|
|
842
|
-
} catch (e) {
|
|
843
|
-
const errorMsg = `Failed to close session for server '${serverName}': ${e}`;
|
|
844
|
-
logger.error(errorMsg);
|
|
845
|
-
errors.push(errorMsg);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
if (errors.length) {
|
|
849
|
-
logger.error(
|
|
850
|
-
`Encountered ${errors.length} errors while closing sessions`
|
|
851
|
-
);
|
|
852
|
-
} else {
|
|
853
|
-
logger.debug("All sessions closed successfully");
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
};
|
|
857
|
-
|
|
858
1385
|
export {
|
|
859
1386
|
MCPSession,
|
|
860
1387
|
BaseMCPClient,
|
|
1388
|
+
BaseConnector,
|
|
861
1389
|
ConnectionManager,
|
|
862
1390
|
HttpConnector
|
|
863
1391
|
};
|