({
client: { client, name, config },
tool,
args,
meta,
signal,
onProgress,
}: {
client: ConnectedMCPServer
tool: string
args: Record<string, unknown>
meta?: Record<string, unknown>
signal: AbortSignal
onProgress?: (data: MCPProgress) => void
})
| 3027 | } |
| 3028 | |
| 3029 | async function callMCPTool({ |
| 3030 | client: { client, name, config }, |
| 3031 | tool, |
| 3032 | args, |
| 3033 | meta, |
| 3034 | signal, |
| 3035 | onProgress, |
| 3036 | }: { |
| 3037 | client: ConnectedMCPServer |
| 3038 | tool: string |
| 3039 | args: Record<string, unknown> |
| 3040 | meta?: Record<string, unknown> |
| 3041 | signal: AbortSignal |
| 3042 | onProgress?: (data: MCPProgress) => void |
| 3043 | }): Promise<{ |
| 3044 | content: MCPToolResult |
| 3045 | _meta?: Record<string, unknown> |
| 3046 | structuredContent?: Record<string, unknown> |
| 3047 | }> { |
| 3048 | const toolStartTime = Date.now() |
| 3049 | let progressInterval: NodeJS.Timeout | undefined |
| 3050 | |
| 3051 | try { |
| 3052 | logMCPDebug(name, `Calling MCP tool: ${tool}`) |
| 3053 | |
| 3054 | // Set up progress logging for long-running tools (every 30 seconds) |
| 3055 | progressInterval = setInterval( |
| 3056 | (startTime, name, tool) => { |
| 3057 | const elapsed = Date.now() - startTime |
| 3058 | const elapsedSeconds = Math.floor(elapsed / 1000) |
| 3059 | const duration = `${elapsedSeconds}s` |
| 3060 | logMCPDebug(name, `Tool '${tool}' still running (${duration} elapsed)`) |
| 3061 | }, |
| 3062 | 30000, // Log every 30 seconds |
| 3063 | toolStartTime, |
| 3064 | name, |
| 3065 | tool, |
| 3066 | ) |
| 3067 | |
| 3068 | // Use Promise.race with our own timeout to handle cases where SDK's |
| 3069 | // internal timeout doesn't work (e.g., SSE stream breaks mid-request) |
| 3070 | const timeoutMs = getMcpToolTimeoutMs() |
| 3071 | let timeoutId: NodeJS.Timeout | undefined |
| 3072 | |
| 3073 | const timeoutPromise = new Promise<never>((_, reject) => { |
| 3074 | timeoutId = setTimeout( |
| 3075 | (reject, name, tool, timeoutMs) => { |
| 3076 | reject( |
| 3077 | new TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS( |
| 3078 | `MCP server "${name}" tool "${tool}" timed out after ${Math.floor(timeoutMs / 1000)}s`, |
| 3079 | 'MCP tool timeout', |
| 3080 | ), |
| 3081 | ) |
| 3082 | }, |
| 3083 | timeoutMs, |
| 3084 | reject, |
| 3085 | name, |
| 3086 | tool, |
no test coverage detected