@elizaos/plugin-mcp 1.3.5 → 1.7.1

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/index.js CHANGED
@@ -667,6 +667,33 @@ async function handleMcpError(state, mcpProvider, error, runtime2, message, type
667
667
  };
668
668
  }
669
669
 
670
+ // src/utils/handler.ts
671
+ async function handleNoToolAvailable(callback, toolSelection) {
672
+ const responseText = "I don't have a specific tool that can help with that request. Let me try to assist you directly instead.";
673
+ const thoughtText = "No appropriate MCP tool available for this request. Falling back to direct assistance.";
674
+ if (callback && toolSelection?.noToolAvailable) {
675
+ await callback({
676
+ text: responseText,
677
+ thought: thoughtText,
678
+ actions: ["REPLY"]
679
+ });
680
+ }
681
+ return {
682
+ text: responseText,
683
+ values: {
684
+ success: true,
685
+ noToolAvailable: true,
686
+ fallbackToDirectAssistance: true
687
+ },
688
+ data: {
689
+ actionName: "CALL_MCP_TOOL",
690
+ noToolAvailable: true,
691
+ reason: toolSelection?.reasoning || "No appropriate tool available"
692
+ },
693
+ success: true
694
+ };
695
+ }
696
+
670
697
  // src/utils/processing.ts
671
698
  import {
672
699
  ContentType,
@@ -736,82 +763,54 @@ Your response (written as if directly to the user):
736
763
  `;
737
764
 
738
765
  // src/utils/mcp.ts
766
+ var NO_DESC = "No description";
739
767
  async function createMcpMemory(runtime2, message, type, serverName, content, metadata) {
740
768
  const memory = await runtime2.addEmbeddingToMemory({
741
769
  entityId: message.entityId,
742
770
  agentId: runtime2.agentId,
743
771
  roomId: message.roomId,
744
772
  content: {
745
- text: `Used the "${type}" from "${serverName}" server.
746
- Content: ${content}`,
747
- metadata: {
748
- ...metadata,
749
- serverName
750
- }
773
+ text: `Used "${type}" from "${serverName}". Content: ${content}`,
774
+ metadata: { ...metadata, serverName }
751
775
  }
752
776
  });
753
777
  await runtime2.createMemory(memory, type === "resource" ? "resources" : "tools", true);
754
778
  }
755
779
  function buildMcpProviderData(servers) {
756
- const mcpData = {};
757
- let textContent = "";
758
780
  if (servers.length === 0) {
759
- return {
760
- values: { mcp: {} },
761
- data: { mcp: {} },
762
- text: "No MCP servers are currently connected."
763
- };
781
+ return { values: { mcp: {} }, data: { mcp: {} }, text: "No MCP servers connected." };
764
782
  }
783
+ const mcpData = {};
784
+ const lines = [`# MCP Configuration
785
+ `];
765
786
  for (const server of servers) {
766
- mcpData[server.name] = {
767
- status: server.status,
768
- tools: {},
769
- resources: {}
770
- };
771
- textContent += `## Server: ${server.name} (${server.status})
772
-
773
- `;
774
- if (server.tools && server.tools.length > 0) {
775
- textContent += `### Tools:
776
-
777
- `;
778
- for (const tool of server.tools) {
779
- mcpData[server.name].tools[tool.name] = {
780
- description: tool.description || "No description available",
781
- inputSchema: tool.inputSchema || {}
782
- };
783
- textContent += `- **${tool.name}**: ${tool.description || "No description available"}
784
- `;
785
- }
786
- textContent += `
787
- `;
788
- }
789
- if (server.resources && server.resources.length > 0) {
790
- textContent += `### Resources:
791
-
792
- `;
793
- for (const resource of server.resources) {
794
- mcpData[server.name].resources[resource.uri] = {
795
- name: resource.name,
796
- description: resource.description || "No description available",
797
- mimeType: resource.mimeType
798
- };
799
- textContent += `- **${resource.name}** (${resource.uri}): ${resource.description || "No description available"}
800
- `;
801
- }
802
- textContent += `
803
- `;
804
- }
805
- }
806
- return {
807
- values: { mcp: mcpData, mcpText: `# MCP Configuration
808
-
809
- ${textContent}` },
810
- data: { mcp: mcpData },
811
- text: `# MCP Configuration
812
-
813
- ${textContent}`
814
- };
787
+ const tools = {};
788
+ const resources = {};
789
+ lines.push(`## ${server.name} (${server.status})
790
+ `);
791
+ if (server.tools?.length) {
792
+ lines.push(`### Tools
793
+ `);
794
+ for (const t of server.tools) {
795
+ tools[t.name] = { description: t.description || NO_DESC, inputSchema: t.inputSchema || {} };
796
+ lines.push(`- **${t.name}**: ${t.description || NO_DESC}`);
797
+ }
798
+ lines.push("");
799
+ }
800
+ if (server.resources?.length) {
801
+ lines.push(`### Resources
802
+ `);
803
+ for (const r of server.resources) {
804
+ resources[r.uri] = { name: r.name, description: r.description || NO_DESC, mimeType: r.mimeType };
805
+ lines.push(`- **${r.name}** (${r.uri}): ${r.description || NO_DESC}`);
806
+ }
807
+ lines.push("");
808
+ }
809
+ mcpData[server.name] = { status: server.status, tools, resources };
810
+ }
811
+ const text = lines.join(`
812
+ `);
813
+ return { values: { mcp: mcpData, mcpText: text }, data: { mcp: mcpData }, text };
815
814
  }
816
815
 
817
816
  // src/utils/processing.ts
@@ -1080,9 +1079,10 @@ ${JSON.stringify(parsedJson, null, 2)}`);
1080
1079
  }
1081
1080
  function getMaxRetries(runtime2) {
1082
1081
  try {
1083
- const settings = runtime2.getSetting("mcp");
1084
- if (settings && "maxRetries" in settings && settings.maxRetries !== undefined) {
1085
- const configValue = Number(settings.maxRetries);
1082
+ const rawSettings = runtime2.getSetting("mcp");
1083
+ const settings = rawSettings;
1084
+ if (settings && typeof settings.maxRetries === "number") {
1085
+ const configValue = settings.maxRetries;
1086
1086
  if (!Number.isNaN(configValue) && configValue >= 0) {
1087
1087
  logger3.debug(`[WITH-MODEL-RETRY] Using configured selection retries: ${configValue}`);
1088
1088
  return configValue;
@@ -1412,33 +1412,6 @@ function createFeedbackPrompt2(originalResponse, errorMessage, itemType, itemsDe
1412
1412
  User request: ${userMessage}`;
1413
1413
  }
1414
1414
 
1415
- // src/utils/handler.ts
1416
- async function handleNoToolAvailable(callback, toolSelection) {
1417
- const responseText = "I don't have a specific tool that can help with that request. Let me try to assist you directly instead.";
1418
- const thoughtText = "No appropriate MCP tool available for this request. Falling back to direct assistance.";
1419
- if (callback && toolSelection?.noToolAvailable) {
1420
- await callback({
1421
- text: responseText,
1422
- thought: thoughtText,
1423
- actions: ["REPLY"]
1424
- });
1425
- }
1426
- return {
1427
- text: responseText,
1428
- values: {
1429
- success: true,
1430
- noToolAvailable: true,
1431
- fallbackToDirectAssistance: true
1432
- },
1433
- data: {
1434
- actionName: "CALL_MCP_TOOL",
1435
- noToolAvailable: true,
1436
- reason: toolSelection?.reasoning || "No appropriate tool available"
1437
- },
1438
- success: true
1439
- };
1440
- }
1441
-
1442
1415
  // src/actions/callToolAction.ts
1443
1416
  var callToolAction = {
1444
1417
  name: "CALL_MCP_TOOL",
@@ -1500,7 +1473,7 @@ ${JSON.stringify(toolSelectionArgument, null, 2)}`);
1500
1473
  const result = await mcpService.callTool(serverName, toolName, toolSelectionArgument.toolArguments);
1501
1474
  const { toolOutput, hasAttachments, attachments } = processToolResult(result, serverName, toolName, runtime2, message.entityId);
1502
1475
  const replyMemory = await handleToolResponse(runtime2, message, serverName, toolName, toolSelectionArgument.toolArguments, toolOutput, hasAttachments, attachments, composedState, mcpProvider, callback);
1503
- return {
1476
+ const actionResult = {
1504
1477
  text: `Successfully called tool: ${serverName}/${toolName}. Reasoned response: ${replyMemory.content.text}`,
1505
1478
  values: {
1506
1479
  success: true,
@@ -1521,6 +1494,15 @@ ${JSON.stringify(toolSelectionArgument, null, 2)}`);
1521
1494
  },
1522
1495
  success: true
1523
1496
  };
1497
+ logger5.info({
1498
+ serverName,
1499
+ toolName,
1500
+ hasOutput: !!toolOutput,
1501
+ outputLength: toolOutput?.length || 0,
1502
+ hasAttachments,
1503
+ reasoning: toolSelectionName.reasoning
1504
+ }, `[CALL_MCP_TOOL] Action result`);
1505
+ return actionResult;
1524
1506
  } catch (error) {
1525
1507
  return await handleMcpError(composedState, mcpProvider, error, runtime2, message, "tool", callback);
1526
1508
  }
@@ -1762,19 +1744,20 @@ var readResourceAction = {
1762
1744
  };
1763
1745
 
1764
1746
  // src/provider.ts
1747
+ var createEmptyProvider = () => ({
1748
+ values: { mcp: {} },
1749
+ data: { mcp: {} },
1750
+ text: "No MCP servers available."
1751
+ });
1765
1752
  var provider = {
1766
1753
  name: "MCP",
1767
- description: "Information about connected MCP servers, tools, and resources",
1754
+ description: "Connected MCP servers, tools, and resources",
1768
1755
  get: async (runtime2, _message, _state) => {
1769
- const mcpService = runtime2.getService(MCP_SERVICE_NAME);
1770
- if (!mcpService) {
1771
- return {
1772
- values: { mcp: {} },
1773
- data: { mcp: {} },
1774
- text: "No MCP servers are available."
1775
- };
1776
- }
1777
- return mcpService.getProviderData();
1756
+ const svc = runtime2.getService(MCP_SERVICE_NAME);
1757
+ if (!svc)
1758
+ return createEmptyProvider();
1759
+ await svc.waitForInitialization();
1760
+ return svc.getProviderData();
1778
1761
  }
1779
1762
  };
1780
1763
 
@@ -1783,6 +1766,9 @@ import { Service, logger as logger7 } from "@elizaos/core";
1783
1766
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
1784
1767
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
1785
1768
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
1769
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
1770
+ var errMsg = (e) => e instanceof Error ? e.message : String(e);
1771
+
1786
1772
  class McpService extends Service {
1787
1773
  static serviceType = MCP_SERVICE_NAME;
1788
1774
  capabilityDescription = "Enables the agent to interact with MCP (Model Context Protocol) servers";
@@ -1799,7 +1785,6 @@ class McpService extends Service {
1799
1785
  initializationPromise = null;
1800
1786
  constructor(runtime2) {
1801
1787
  super(runtime2);
1802
- logger7.info("[McpService] Constructor called, starting initialization...");
1803
1788
  this.initializationPromise = this.initializeMcpServers();
1804
1789
  }
1805
1790
  static async start(runtime2) {
@@ -1815,115 +1800,70 @@ class McpService extends Service {
1815
1800
  }
1816
1801
  }
1817
1802
  async stop() {
1818
- for (const [name] of this.connections) {
1803
+ for (const name of this.connections.keys()) {
1819
1804
  await this.deleteConnection(name);
1820
1805
  }
1821
- this.connections.clear();
1822
- for (const state of this.connectionStates.values()) {
1806
+ for (const [name, state] of this.connectionStates.entries()) {
1823
1807
  if (state.pingInterval)
1824
1808
  clearInterval(state.pingInterval);
1825
1809
  if (state.reconnectTimeout)
1826
1810
  clearTimeout(state.reconnectTimeout);
1811
+ this.connectionStates.delete(name);
1827
1812
  }
1828
- this.connectionStates.clear();
1829
1813
  }
1830
1814
  async initializeMcpServers() {
1831
- logger7.info("[McpService] Starting MCP server initialization...");
1832
1815
  try {
1833
1816
  const mcpSettings = this.getMcpSettings();
1834
- const serverCount = mcpSettings?.servers ? Object.keys(mcpSettings.servers).length : 0;
1835
- const serverNames = mcpSettings?.servers ? Object.keys(mcpSettings.servers) : [];
1836
- logger7.info(`[McpService] Getting MCP settings... hasSettings=${!!mcpSettings} hasServers=${!!mcpSettings?.servers} serverCount=${serverCount} servers=${JSON.stringify(serverNames)}`);
1837
- if (!mcpSettings || !mcpSettings.servers) {
1838
- logger7.info("[McpService] No MCP servers configured.");
1839
- this.mcpProvider = buildMcpProviderData([]);
1840
- return;
1841
- }
1842
- if (Object.keys(mcpSettings.servers).length === 0) {
1843
- logger7.info("[McpService] MCP settings exist but no servers configured.");
1817
+ if (!mcpSettings?.servers || Object.keys(mcpSettings.servers).length === 0) {
1844
1818
  this.mcpProvider = buildMcpProviderData([]);
1845
1819
  return;
1846
1820
  }
1847
- logger7.info(`[McpService] Connecting to ${Object.keys(mcpSettings.servers).length} MCP servers: ${JSON.stringify(Object.keys(mcpSettings.servers))}`);
1848
1821
  const connectionStartTime = Date.now();
1849
1822
  await this.updateServerConnections(mcpSettings.servers);
1850
1823
  const connectionDuration = Date.now() - connectionStartTime;
1851
1824
  const servers = this.getServers();
1852
- const connectedServers = servers.filter((s) => s.status === "connected");
1853
- const failedServers = servers.filter((s) => s.status !== "connected");
1854
- if (connectedServers.length > 0) {
1855
- const toolCounts = connectedServers.map((s) => `${s.name}:${s.tools?.length || 0}tools`).join(", ");
1856
- logger7.info(`[McpService] ✓ Successfully connected ${connectedServers.length}/${servers.length} servers in ${connectionDuration}ms: ${toolCounts}`);
1825
+ const connected = servers.filter((s) => s.status === "connected");
1826
+ const failed = servers.filter((s) => s.status !== "connected");
1827
+ if (connected.length > 0) {
1828
+ logger7.info(`[MCP] Connected ${connected.length}/${servers.length} in ${connectionDuration}ms (${connected.map((s) => `${s.name}:${s.tools?.length || 0}`).join(", ")})`);
1857
1829
  }
1858
- if (failedServers.length > 0) {
1859
- const failedDetails = failedServers.map((s) => `${s.name}(${s.error || "unknown error"})`).join(", ");
1860
- logger7.warn(`[McpService] ⚠️ Failed to connect to ${failedServers.length}/${servers.length} servers: ${failedDetails}`);
1830
+ if (failed.length > 0) {
1831
+ logger7.warn(`[MCP] Failed: ${failed.map((s) => s.name).join(", ")}`);
1861
1832
  }
1862
- if (connectedServers.length === 0 && servers.length > 0) {
1863
- logger7.error(`[McpService] ALL MCP servers failed to connect! MCP tools will NOT be available.`);
1833
+ if (connected.length === 0 && servers.length > 0) {
1834
+ logger7.error(`[MCP] All servers failed`);
1864
1835
  }
1865
1836
  this.mcpProvider = buildMcpProviderData(servers);
1866
- const mcpDataKeys = Object.keys(this.mcpProvider.data?.mcp || {});
1867
- logger7.info(`[McpService] MCP provider data built: ${mcpDataKeys.length} server(s) available`);
1868
1837
  } catch (error) {
1869
- logger7.error({ error: error instanceof Error ? error.message : String(error) }, "❌ Failed to initialize MCP servers - MCP tools will NOT be available");
1838
+ logger7.error({ error: errMsg(error) }, "[MCP] Initialization failed");
1870
1839
  this.mcpProvider = buildMcpProviderData([]);
1871
1840
  }
1872
1841
  }
1873
1842
  getMcpSettings() {
1874
1843
  let settings = this.runtime.getSetting("mcp");
1875
- logger7.info(`[McpService] getSetting("mcp") result: type=${typeof settings} isNull=${settings === null} hasServers=${!!settings?.servers}`);
1876
1844
  if (!settings || typeof settings === "object" && !settings.servers) {
1877
- const characterSettings = this.runtime.character?.settings;
1878
- if (characterSettings?.mcp) {
1879
- logger7.info("[McpService] Found MCP settings in character.settings.mcp (fallback)");
1880
- settings = characterSettings.mcp;
1881
- }
1845
+ settings = this.runtime.character?.settings?.mcp;
1882
1846
  }
1883
1847
  if (!settings || typeof settings === "object" && !settings.servers) {
1884
- const runtimeSettings = this.runtime.settings;
1885
- if (runtimeSettings?.mcp) {
1886
- logger7.info("[McpService] Found MCP settings in runtime.settings.mcp (fallback)");
1887
- settings = runtimeSettings.mcp;
1888
- }
1848
+ settings = this.runtime.settings?.mcp;
1889
1849
  }
1890
- if (settings && typeof settings === "object" && settings.servers) {
1891
- logger7.info(`[McpService] MCP settings found with ${Object.keys(settings.servers).length} server(s)`);
1892
- return settings;
1893
- }
1894
- logger7.info("[McpService] No valid MCP settings found");
1895
- return;
1850
+ return settings && typeof settings === "object" && settings.servers ? settings : undefined;
1896
1851
  }
1897
1852
  async updateServerConnections(serverConfigs) {
1898
- const currentNames = new Set(this.connections.keys());
1899
1853
  const newNames = new Set(Object.keys(serverConfigs));
1900
- for (const name of currentNames) {
1901
- if (!newNames.has(name)) {
1854
+ for (const name of this.connections.keys()) {
1855
+ if (!newNames.has(name))
1902
1856
  await this.deleteConnection(name);
1903
- logger7.info(`Deleted MCP server: ${name}`);
1904
- }
1905
1857
  }
1906
- const connectionPromises = Object.entries(serverConfigs).map(async ([name, config]) => {
1907
- const currentConnection = this.connections.get(name);
1908
- if (!currentConnection) {
1909
- try {
1910
- await this.initializeConnection(name, config);
1911
- logger7.info(`✓ Connected to MCP server: ${name}`);
1912
- } catch (error) {
1913
- logger7.error({ error: error instanceof Error ? error.message : String(error), serverName: name }, `✗ Failed to connect to new MCP server ${name}`);
1914
- }
1915
- } else if (JSON.stringify(config) !== currentConnection.server.config) {
1916
- try {
1917
- await this.deleteConnection(name);
1918
- await this.initializeConnection(name, config);
1919
- logger7.info(`✓ Reconnected MCP server with updated config: ${name}`);
1920
- } catch (error) {
1921
- logger7.error({ error: error instanceof Error ? error.message : String(error), serverName: name }, `✗ Failed to reconnect MCP server ${name}`);
1922
- }
1858
+ await Promise.allSettled(Object.entries(serverConfigs).map(async ([name, config]) => {
1859
+ const current = this.connections.get(name);
1860
+ if (!current) {
1861
+ await this.initializeConnection(name, config).catch((e) => logger7.error({ error: errMsg(e), serverName: name }, `[MCP] Failed: ${name}`));
1862
+ } else if (JSON.stringify(config) !== current.server.config) {
1863
+ await this.deleteConnection(name);
1864
+ await this.initializeConnection(name, config).catch((e) => logger7.error({ error: errMsg(e), serverName: name }, `[MCP] Failed: ${name}`));
1923
1865
  }
1924
- });
1925
- await Promise.allSettled(connectionPromises);
1926
- logger7.info(`[McpService] All server connection attempts completed`);
1866
+ }));
1927
1867
  }
1928
1868
  async initializeConnection(name, config) {
1929
1869
  await this.deleteConnection(name);
@@ -1937,19 +1877,19 @@ class McpService extends Service {
1937
1877
  const client = new Client({ name: "ElizaOS", version: "1.0.0" }, { capabilities: {} });
1938
1878
  const transport = config.type === "stdio" ? await this.buildStdioClientTransport(name, config) : await this.buildHttpClientTransport(name, config);
1939
1879
  const connection = {
1940
- server: {
1941
- name,
1942
- config: JSON.stringify(config),
1943
- status: "connecting"
1944
- },
1880
+ server: { name, config: JSON.stringify(config), status: "connecting" },
1945
1881
  client,
1946
1882
  transport
1947
1883
  };
1948
1884
  this.connections.set(name, connection);
1949
1885
  this.setupTransportHandlers(name, connection, state);
1950
- await client.connect(transport);
1886
+ const connectPromise = client.connect(transport);
1887
+ connectPromise.catch(() => {});
1888
+ await Promise.race([
1889
+ connectPromise,
1890
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Timeout connecting to ${name}`)), 60000))
1891
+ ]);
1951
1892
  const capabilities = client.getServerCapabilities();
1952
- logger7.debug(`[${name}] Server capabilities:`, JSON.stringify(capabilities || {}));
1953
1893
  const tools = await this.fetchToolsList(name);
1954
1894
  const resources = capabilities?.resources ? await this.fetchResourcesList(name) : [];
1955
1895
  const resourceTemplates = capabilities?.resources ? await this.fetchResourceTemplatesList(name) : [];
@@ -1967,7 +1907,6 @@ class McpService extends Service {
1967
1907
  state.reconnectAttempts = 0;
1968
1908
  state.consecutivePingFailures = 0;
1969
1909
  this.startPingMonitoring(name);
1970
- logger7.info(`Successfully connected to MCP server: ${name}`);
1971
1910
  } catch (error) {
1972
1911
  state.status = "disconnected";
1973
1912
  state.lastError = error instanceof Error ? error : new Error(String(error));
@@ -1977,26 +1916,21 @@ class McpService extends Service {
1977
1916
  }
1978
1917
  setupTransportHandlers(name, connection, state) {
1979
1918
  const config = JSON.parse(connection.server.config);
1980
- const isHttpTransport = config.type !== "stdio";
1919
+ const isHttp = config.type !== "stdio";
1981
1920
  connection.transport.onerror = async (error) => {
1982
- const errorMessage = error?.message || String(error);
1983
- const isExpectedTimeout = isHttpTransport && (errorMessage === "undefined" || errorMessage === "" || errorMessage.includes("SSE error") || errorMessage.includes("timeout"));
1984
- if (isExpectedTimeout) {
1985
- logger7.debug({ serverName: name }, `SSE connection timeout for "${name}" (expected, will reconnect)`);
1986
- } else {
1987
- logger7.error({ error, serverName: name }, `Transport error for "${name}"`);
1921
+ const msg = error?.message || String(error);
1922
+ const isExpectedTimeout = isHttp && (!msg || msg === "undefined" || msg.includes("SSE") || msg.includes("timeout"));
1923
+ if (!isExpectedTimeout) {
1924
+ logger7.error({ error, serverName: name }, `Transport error: ${name}`);
1988
1925
  connection.server.status = "disconnected";
1989
- this.appendErrorMessage(connection, error.message);
1926
+ this.appendErrorMessage(connection, msg);
1990
1927
  }
1991
- if (!isHttpTransport) {
1928
+ if (!isHttp)
1992
1929
  this.handleDisconnection(name, error);
1993
- }
1994
1930
  };
1995
1931
  connection.transport.onclose = async () => {
1996
- if (isHttpTransport) {
1997
- logger7.debug({ serverName: name }, `SSE connection closed for "${name}" (stateless, will reconnect on demand)`);
1998
- } else {
1999
- logger7.warn({ serverName: name }, `Transport closed for "${name}"`);
1932
+ if (!isHttp) {
1933
+ logger7.warn({ serverName: name }, `Transport closed: ${name}`);
2000
1934
  connection.server.status = "disconnected";
2001
1935
  this.handleDisconnection(name, new Error("Transport closed"));
2002
1936
  }
@@ -2007,11 +1941,8 @@ class McpService extends Service {
2007
1941
  if (!connection)
2008
1942
  return;
2009
1943
  const config = JSON.parse(connection.server.config);
2010
- const isHttpTransport = config.type !== "stdio";
2011
- if (isHttpTransport) {
2012
- logger7.debug(`[McpService] Skipping ping monitoring for HTTP server: ${name}`);
1944
+ if (config.type !== "stdio")
2013
1945
  return;
2014
- }
2015
1946
  const state = this.connectionStates.get(name);
2016
1947
  if (!state || !this.pingConfig.enabled)
2017
1948
  return;
@@ -2019,7 +1950,7 @@ class McpService extends Service {
2019
1950
  clearInterval(state.pingInterval);
2020
1951
  state.pingInterval = setInterval(() => {
2021
1952
  this.sendPing(name).catch((err) => {
2022
- logger7.warn({ error: err instanceof Error ? err.message : String(err), serverName: name }, `Ping failed for ${name}`);
1953
+ logger7.warn({ error: errMsg(err), serverName: name }, `Ping failed: ${name}`);
2023
1954
  this.handlePingFailure(name, err);
2024
1955
  });
2025
1956
  }, this.pingConfig.intervalMs);
@@ -2027,7 +1958,7 @@ class McpService extends Service {
2027
1958
  async sendPing(name) {
2028
1959
  const connection = this.connections.get(name);
2029
1960
  if (!connection)
2030
- throw new Error(`No connection for ping: ${name}`);
1961
+ throw new Error(`No connection: ${name}`);
2031
1962
  await Promise.race([
2032
1963
  connection.client.listTools(),
2033
1964
  new Promise((_, reject) => setTimeout(() => reject(new Error("Ping timeout")), this.pingConfig.timeoutMs))
@@ -2069,7 +2000,7 @@ class McpService extends Service {
2069
2000
  try {
2070
2001
  await this.initializeConnection(name, JSON.parse(config));
2071
2002
  } catch (err) {
2072
- logger7.error({ error: err instanceof Error ? err.message : String(err), serverName: name }, `Reconnect attempt failed for ${name}`);
2003
+ logger7.error({ error: errMsg(err), serverName: name }, `Reconnect attempt failed for ${name}`);
2073
2004
  this.handleDisconnection(name, err);
2074
2005
  }
2075
2006
  }
@@ -2082,7 +2013,7 @@ class McpService extends Service {
2082
2013
  await connection.transport.close();
2083
2014
  await connection.client.close();
2084
2015
  } catch (error) {
2085
- logger7.error({ error: error instanceof Error ? error.message : String(error), serverName: name }, `Failed to close transport for ${name}`);
2016
+ logger7.error({ error: errMsg(error), serverName: name }, `Failed to close transport for ${name}`);
2086
2017
  }
2087
2018
  this.connections.delete(name);
2088
2019
  }
@@ -2095,9 +2026,6 @@ class McpService extends Service {
2095
2026
  this.connectionStates.delete(name);
2096
2027
  }
2097
2028
  }
2098
- getServerConnection(serverName) {
2099
- return this.connections.get(serverName);
2100
- }
2101
2029
  async buildStdioClientTransport(name, config) {
2102
2030
  if (!config.command) {
2103
2031
  throw new Error(`Missing command for stdio MCP server ${name}`);
@@ -2114,74 +2042,61 @@ class McpService extends Service {
2114
2042
  });
2115
2043
  }
2116
2044
  async buildHttpClientTransport(name, config) {
2117
- if (!config.url) {
2118
- throw new Error(`Missing URL for HTTP MCP server ${name}`);
2119
- }
2045
+ if (!config.url)
2046
+ throw new Error(`Missing URL for MCP server ${name}`);
2047
+ const url = new URL(config.url);
2048
+ const opts = config.headers ? { requestInit: { headers: config.headers } } : undefined;
2120
2049
  if (config.type === "sse") {
2121
- logger7.warn(`Server "${name}": "sse" transport type is deprecated. Use "streamable-http" or "http" instead for the modern Streamable HTTP transport.`);
2050
+ logger7.warn(`[MCP] "${name}": SSE requires Redis. Use "streamable-http" instead.`);
2051
+ return new SSEClientTransport(url, opts);
2122
2052
  }
2123
- return new SSEClientTransport(new URL(config.url));
2053
+ return new StreamableHTTPClientTransport(url, opts);
2124
2054
  }
2125
2055
  appendErrorMessage(connection, error) {
2126
- const newError = connection.server.error ? `${connection.server.error}
2056
+ connection.server.error = connection.server.error ? `${connection.server.error}
2127
2057
  ${error}` : error;
2128
- connection.server.error = newError;
2129
2058
  }
2130
2059
  async fetchToolsList(serverName) {
2060
+ const connection = this.connections.get(serverName);
2061
+ if (!connection)
2062
+ return [];
2131
2063
  try {
2132
- const connection = this.getServerConnection(serverName);
2133
- if (!connection) {
2134
- return [];
2135
- }
2136
2064
  const response = await connection.client.listTools();
2137
- const tools = (response?.tools || []).map((tool) => {
2138
- let processedTool = { ...tool };
2139
- if (tool.inputSchema) {
2140
- try {
2141
- if (!this.compatibilityInitialized) {
2142
- this.initializeToolCompatibility();
2143
- }
2144
- processedTool.inputSchema = this.applyToolCompatibility(tool.inputSchema);
2145
- logger7.debug(`Applied tool compatibility for: ${tool.name} on server: ${serverName}`);
2146
- } catch (error) {
2147
- logger7.warn({ error, toolName: tool.name, serverName }, `Tool compatibility failed for ${tool.name} on ${serverName}`);
2148
- }
2065
+ return (response?.tools || []).map((tool) => {
2066
+ if (!tool.inputSchema)
2067
+ return tool;
2068
+ if (!this.compatibilityInitialized)
2069
+ this.initializeToolCompatibility();
2070
+ try {
2071
+ return { ...tool, inputSchema: this.applyToolCompatibility(tool.inputSchema) };
2072
+ } catch {
2073
+ return tool;
2149
2074
  }
2150
- return processedTool;
2151
2075
  });
2152
- logger7.info(`Fetched ${tools.length} tools for ${serverName}`);
2153
- for (const tool of tools) {
2154
- logger7.info(`[${serverName}] ${tool.name}: ${tool.description}`);
2155
- }
2156
- return tools;
2157
2076
  } catch (error) {
2158
- logger7.error({ error: error instanceof Error ? error.message : String(error), serverName }, `Failed to fetch tools for ${serverName}`);
2077
+ logger7.error({ error: errMsg(error), serverName }, `Failed to fetch tools: ${serverName}`);
2159
2078
  return [];
2160
2079
  }
2161
2080
  }
2162
- async fetchResourcesList(serverName) {
2081
+ async fetchResourcesList(name) {
2082
+ const conn = this.connections.get(name);
2083
+ if (!conn)
2084
+ return [];
2163
2085
  try {
2164
- const connection = this.getServerConnection(serverName);
2165
- if (!connection) {
2166
- return [];
2167
- }
2168
- const response = await connection.client.listResources();
2169
- return response?.resources || [];
2086
+ return (await conn.client.listResources())?.resources || [];
2170
2087
  } catch (error) {
2171
- logger7.warn({ error: error instanceof Error ? error.message : String(error), serverName }, `No resources found for ${serverName}`);
2088
+ logger7.debug({ error: errMsg(error), serverName: name }, `No resources for ${name}`);
2172
2089
  return [];
2173
2090
  }
2174
2091
  }
2175
- async fetchResourceTemplatesList(serverName) {
2092
+ async fetchResourceTemplatesList(name) {
2093
+ const conn = this.connections.get(name);
2094
+ if (!conn)
2095
+ return [];
2176
2096
  try {
2177
- const connection = this.getServerConnection(serverName);
2178
- if (!connection) {
2179
- return [];
2180
- }
2181
- const response = await connection.client.listResourceTemplates();
2182
- return response?.resourceTemplates || [];
2097
+ return (await conn.client.listResourceTemplates())?.resourceTemplates || [];
2183
2098
  } catch (error) {
2184
- logger7.warn({ error: error instanceof Error ? error.message : String(error), serverName }, `No resource templates found for ${serverName}`);
2099
+ logger7.debug({ error: errMsg(error), serverName: name }, `No resource templates for ${name}`);
2185
2100
  return [];
2186
2101
  }
2187
2102
  }
@@ -2191,76 +2106,53 @@ ${error}` : error;
2191
2106
  getProviderData() {
2192
2107
  return this.mcpProvider;
2193
2108
  }
2194
- async callTool(serverName, toolName, toolArguments) {
2195
- const connection = this.connections.get(serverName);
2196
- if (!connection) {
2197
- throw new Error(`No connection found for server: ${serverName}`);
2198
- }
2199
- if (connection.server.disabled) {
2200
- throw new Error(`Server "${serverName}" is disabled`);
2201
- }
2202
- let timeout = DEFAULT_MCP_TIMEOUT_SECONDS;
2203
- try {
2204
- const config = JSON.parse(connection.server.config);
2205
- timeout = config.timeoutInMillis || DEFAULT_MCP_TIMEOUT_SECONDS;
2206
- } catch (error) {
2207
- logger7.error({ error: error instanceof Error ? error.message : String(error), serverName }, `Failed to parse timeout configuration for server ${serverName}`);
2208
- }
2209
- const result = await connection.client.callTool({ name: toolName, arguments: toolArguments }, undefined, { timeout });
2210
- if (!result.content) {
2211
- throw new Error("Invalid tool result: missing content array");
2212
- }
2109
+ async callTool(serverName, toolName, args) {
2110
+ const conn = this.connections.get(serverName);
2111
+ if (!conn)
2112
+ throw new Error(`No connection: ${serverName}`);
2113
+ if (conn.server.disabled)
2114
+ throw new Error(`Server disabled: ${serverName}`);
2115
+ const config = JSON.parse(conn.server.config);
2116
+ const timeout = (config.type === "stdio" ? config.timeoutInMillis : config.timeout) ?? DEFAULT_MCP_TIMEOUT_SECONDS;
2117
+ const result = await conn.client.callTool({ name: toolName, arguments: args }, undefined, {
2118
+ timeout
2119
+ });
2120
+ if (!result.content)
2121
+ throw new Error("Invalid tool result: missing content");
2213
2122
  return result;
2214
2123
  }
2215
2124
  async readResource(serverName, uri) {
2216
- const connection = this.connections.get(serverName);
2217
- if (!connection) {
2218
- throw new Error(`No connection found for server: ${serverName}`);
2219
- }
2220
- if (connection.server.disabled) {
2221
- throw new Error(`Server "${serverName}" is disabled`);
2222
- }
2223
- return await connection.client.readResource({ uri });
2125
+ const conn = this.connections.get(serverName);
2126
+ if (!conn)
2127
+ throw new Error(`No connection: ${serverName}`);
2128
+ if (conn.server.disabled)
2129
+ throw new Error(`Server disabled: ${serverName}`);
2130
+ return conn.client.readResource({ uri });
2224
2131
  }
2225
2132
  async restartConnection(serverName) {
2226
- const connection = this.connections.get(serverName);
2227
- const config = connection?.server.config;
2228
- if (config) {
2229
- logger7.info(`Restarting ${serverName} MCP server...`);
2230
- connection.server.status = "connecting";
2231
- connection.server.error = "";
2232
- try {
2233
- await this.deleteConnection(serverName);
2234
- await this.initializeConnection(serverName, JSON.parse(config));
2235
- logger7.info(`${serverName} MCP server connected`);
2236
- } catch (error) {
2237
- logger7.error({ error: error instanceof Error ? error.message : String(error), serverName }, `Failed to restart connection for ${serverName}`);
2238
- throw new Error(`Failed to connect to ${serverName} MCP server`);
2239
- }
2240
- }
2133
+ const conn = this.connections.get(serverName);
2134
+ if (!conn)
2135
+ throw new Error(`No connection: ${serverName}`);
2136
+ const config = conn.server.config;
2137
+ conn.server.status = "connecting";
2138
+ conn.server.error = "";
2139
+ await this.deleteConnection(serverName);
2140
+ await this.initializeConnection(serverName, JSON.parse(config));
2241
2141
  }
2242
2142
  initializeToolCompatibility() {
2243
2143
  if (this.compatibilityInitialized)
2244
2144
  return;
2245
2145
  this.toolCompatibility = createMcpToolCompatibilitySync(this.runtime);
2246
2146
  this.compatibilityInitialized = true;
2247
- if (this.toolCompatibility) {
2248
- logger7.info(`Tool compatibility enabled`);
2249
- } else {
2250
- logger7.info(`No tool compatibility needed`);
2251
- }
2252
2147
  }
2253
2148
  applyToolCompatibility(toolSchema) {
2254
- if (!this.compatibilityInitialized) {
2149
+ if (!this.compatibilityInitialized)
2255
2150
  this.initializeToolCompatibility();
2256
- }
2257
- if (!this.toolCompatibility || !toolSchema) {
2151
+ if (!this.toolCompatibility || !toolSchema)
2258
2152
  return toolSchema;
2259
- }
2260
2153
  try {
2261
2154
  return this.toolCompatibility.transformToolSchema(toolSchema);
2262
- } catch (error) {
2263
- logger7.warn({ error }, `Tool compatibility transformation failed`);
2155
+ } catch {
2264
2156
  return toolSchema;
2265
2157
  }
2266
2158
  }
@@ -2297,4 +2189,4 @@ export {
2297
2189
  BACKOFF_MULTIPLIER
2298
2190
  };
2299
2191
 
2300
- //# debugId=7FE3B98268562B6664756E2164756E21
2192
+ //# debugId=D6293B10B9AC06C464756E2164756E21