summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/cli/src/ui/commands/mcpCommand.test.ts4
-rw-r--r--packages/cli/src/ui/commands/mcpCommand.ts17
-rw-r--r--packages/core/src/tools/mcp-client.ts71
3 files changed, 65 insertions, 27 deletions
diff --git a/packages/cli/src/ui/commands/mcpCommand.test.ts b/packages/cli/src/ui/commands/mcpCommand.test.ts
index 2a6401b3..ad04cb69 100644
--- a/packages/cli/src/ui/commands/mcpCommand.test.ts
+++ b/packages/cli/src/ui/commands/mcpCommand.test.ts
@@ -212,9 +212,9 @@ describe('mcpCommand', () => {
);
expect(message).toContain('server2_tool1');
- // Server 3 - Disconnected
+ // Server 3 - Disconnected but with cached tools, so shows as Ready
expect(message).toContain(
- '🔴 \u001b[1mserver3\u001b[0m - Disconnected (1 tools cached)',
+ '🟢 \u001b[1mserver3\u001b[0m - Ready (1 tool)',
);
expect(message).toContain('server3_tool1');
diff --git a/packages/cli/src/ui/commands/mcpCommand.ts b/packages/cli/src/ui/commands/mcpCommand.ts
index dc5442cc..11c71f1a 100644
--- a/packages/cli/src/ui/commands/mcpCommand.ts
+++ b/packages/cli/src/ui/commands/mcpCommand.ts
@@ -94,7 +94,15 @@ const getMcpStatus = async (
const promptRegistry = await config.getPromptRegistry();
const serverPrompts = promptRegistry.getPromptsByServer(serverName) || [];
- const status = getMCPServerStatus(serverName);
+ const originalStatus = getMCPServerStatus(serverName);
+ const hasCachedItems = serverTools.length > 0 || serverPrompts.length > 0;
+
+ // If the server is "disconnected" but has prompts or cached tools, display it as Ready
+ // by using CONNECTED as the display status.
+ const status =
+ originalStatus === MCPServerStatus.DISCONNECTED && hasCachedItems
+ ? MCPServerStatus.CONNECTED
+ : originalStatus;
// Add status indicator with descriptive text
let statusIndicator = '';
@@ -260,11 +268,14 @@ const getMcpStatus = async (
message += ' No tools or prompts available\n';
} else if (serverTools.length === 0) {
message += ' No tools available';
- if (status === MCPServerStatus.DISCONNECTED && needsAuthHint) {
+ if (originalStatus === MCPServerStatus.DISCONNECTED && needsAuthHint) {
message += ` ${COLOR_GREY}(type: "/mcp auth ${serverName}" to authenticate this server)${RESET_COLOR}`;
}
message += '\n';
- } else if (status === MCPServerStatus.DISCONNECTED && needsAuthHint) {
+ } else if (
+ originalStatus === MCPServerStatus.DISCONNECTED &&
+ needsAuthHint
+ ) {
// This case is for when serverTools.length > 0
message += ` ${COLOR_GREY}(type: "/mcp auth ${serverName}" to authenticate this server)${RESET_COLOR}\n`;
}
diff --git a/packages/core/src/tools/mcp-client.ts b/packages/core/src/tools/mcp-client.ts
index f9ccc380..00f2197a 100644
--- a/packages/core/src/tools/mcp-client.ts
+++ b/packages/core/src/tools/mcp-client.ts
@@ -366,33 +366,47 @@ export async function connectAndDiscover(
): Promise<void> {
updateMCPServerStatus(mcpServerName, MCPServerStatus.CONNECTING);
+ let mcpClient: Client | undefined;
try {
- const mcpClient = await connectToMcpServer(
+ mcpClient = await connectToMcpServer(
mcpServerName,
mcpServerConfig,
debugMode,
);
- try {
- updateMCPServerStatus(mcpServerName, MCPServerStatus.CONNECTED);
- mcpClient.onerror = (error) => {
- console.error(`MCP ERROR (${mcpServerName}):`, error.toString());
- updateMCPServerStatus(mcpServerName, MCPServerStatus.DISCONNECTED);
- };
- await discoverPrompts(mcpServerName, mcpClient, promptRegistry);
- const tools = await discoverTools(
- mcpServerName,
- mcpServerConfig,
- mcpClient,
- );
- for (const tool of tools) {
- toolRegistry.registerTool(tool);
- }
- } catch (error) {
- mcpClient.close();
- throw error;
+ mcpClient.onerror = (error) => {
+ console.error(`MCP ERROR (${mcpServerName}):`, error.toString());
+ updateMCPServerStatus(mcpServerName, MCPServerStatus.DISCONNECTED);
+ };
+
+ // Attempt to discover both prompts and tools
+ const prompts = await discoverPrompts(
+ mcpServerName,
+ mcpClient,
+ promptRegistry,
+ );
+ const tools = await discoverTools(
+ mcpServerName,
+ mcpServerConfig,
+ mcpClient,
+ );
+
+ // If we have neither prompts nor tools, it's a failed discovery
+ if (prompts.length === 0 && tools.length === 0) {
+ throw new Error('No prompts or tools found on the server.');
+ }
+
+ // If we found anything, the server is connected
+ updateMCPServerStatus(mcpServerName, MCPServerStatus.CONNECTED);
+
+ // Register any discovered tools
+ for (const tool of tools) {
+ toolRegistry.registerTool(tool);
}
} catch (error) {
+ if (mcpClient) {
+ mcpClient.close();
+ }
console.error(
`Error connecting to MCP server '${mcpServerName}': ${getErrorMessage(
error,
@@ -423,7 +437,8 @@ export async function discoverTools(
const tool = await mcpCallableTool.tool();
if (!Array.isArray(tool.functionDeclarations)) {
- throw new Error(`Server did not return valid function declarations.`);
+ // This is a valid case for a prompt-only server
+ return [];
}
const discoveredTools: DiscoveredMCPTool[] = [];
@@ -454,7 +469,17 @@ export async function discoverTools(
}
return discoveredTools;
} catch (error) {
- throw new Error(`Error discovering tools: ${error}`);
+ if (
+ error instanceof Error &&
+ !error.message?.includes('Method not found')
+ ) {
+ console.error(
+ `Error discovering tools from ${mcpServerName}: ${getErrorMessage(
+ error,
+ )}`,
+ );
+ }
+ return [];
}
}
@@ -469,7 +494,7 @@ export async function discoverPrompts(
mcpServerName: string,
mcpClient: Client,
promptRegistry: PromptRegistry,
-): Promise<void> {
+): Promise<Prompt[]> {
try {
const response = await mcpClient.request(
{ method: 'prompts/list', params: {} },
@@ -484,6 +509,7 @@ export async function discoverPrompts(
invokeMcpPrompt(mcpServerName, mcpClient, prompt.name, params),
});
}
+ return response.prompts;
} catch (error) {
// It's okay if this fails, not all servers will have prompts.
// Don't log an error if the method is not found, which is a common case.
@@ -497,6 +523,7 @@ export async function discoverPrompts(
)}`,
);
}
+ return [];
}
}