From b4b0bf54d2f003dd18ad38abb328d83039ddcb61 Mon Sep 17 00:00:00 2001 From: David Kaya Date: Sat, 28 Mar 2026 19:30:42 +0100 Subject: [PATCH] fix: improve MCP tool probing reliability - Increase default probe timeout from 10s to 30s to handle slow package managers (uvx, npx) that install on first run - Add console logging for probe success/failure to aid debugging - Probe manually configured MCP servers (not just discovered ones) so all servers with wildcard tools get their tools discovered Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/main/AryxAppService.ts | 28 ++++++++++++++++++++++++++++ src/main/services/mcpToolProber.ts | 7 +++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/main/AryxAppService.ts b/src/main/AryxAppService.ts index 1ff7097..875c89c 100644 --- a/src/main/AryxAppService.ts +++ b/src/main/AryxAppService.ts @@ -2130,10 +2130,14 @@ export class AryxAppService extends EventEmitter { } private async probeAllAcceptedMcpServers(workspace: WorkspaceState): Promise { + // Probe discovered MCP servers (from config files) await this.probeDiscoveredMcpServersFromState(workspace.settings.discoveredUserTooling); for (const project of workspace.projects) { await this.probeDiscoveredMcpServersFromState(project.discoveredTooling); } + + // Probe manually configured MCP servers that have empty tools arrays + await this.probeManualMcpServers(workspace); } private async probeDiscoveredMcpServersFromState( @@ -2185,6 +2189,30 @@ export class AryxAppService extends EventEmitter { } } + private async probeManualMcpServers(workspace: WorkspaceState): Promise { + const manualServers = workspace.settings.tooling.mcpServers.filter( + (server) => server.tools.length === 0 && (!server.probedTools || server.probedTools.length === 0), + ); + if (manualServers.length === 0) return; + + const tokenLookup = (url: string) => getStoredToken(url)?.accessToken; + const results = await probeServers(manualServers, tokenLookup); + + let changed = false; + for (const result of results) { + if (result.status !== 'success' || result.tools.length === 0) continue; + const server = workspace.settings.tooling.mcpServers.find((s) => s.id === result.serverId); + if (server) { + server.probedTools = result.tools; + changed = true; + } + } + + if (changed) { + await this.persistAndBroadcast(workspace); + } + } + private discoveredServerToDefinition(server: DiscoveredMcpServer): McpServerDefinition { if (server.transport === 'local') { return { diff --git a/src/main/services/mcpToolProber.ts b/src/main/services/mcpToolProber.ts index 61cccd6..14e6eab 100644 --- a/src/main/services/mcpToolProber.ts +++ b/src/main/services/mcpToolProber.ts @@ -19,7 +19,7 @@ export interface McpProbeResult { } const CLIENT_INFO = { name: 'aryx', version: '1.0.0' }; -const DEFAULT_TIMEOUT_MS = 10_000; +const DEFAULT_TIMEOUT_MS = 30_000; const MAX_CONCURRENCY = 5; export async function probeServers( @@ -65,6 +65,7 @@ export async function probeServer( `Probe timed out after ${timeoutMs}ms`, ); + console.log(`[aryx mcp-probe] ${server.name}: discovered ${tools.length} tool(s)`); return { serverId: server.id, serverName: server.name, @@ -72,12 +73,14 @@ export async function probeServer( status: 'success', }; } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[aryx mcp-probe] ${server.name}: failed — ${message}`); return { serverId: server.id, serverName: server.name, tools: [], status: 'failed', - error: error instanceof Error ? error.message : String(error), + error: message, }; } }