({
client: { client, name, config },
tool,
args,
meta,
signal,
onProgress,
imageLimits,
hasResultSizeAnnotation = false,
}: {
client: ConnectedMCPServer
tool: string
args: Record<string, unknown>
meta?: Record<string, unknown>
signal: AbortSignal
onProgress?: (data: MCPProgress) => void
imageLimits?: ImageLimits
hasResultSizeAnnotation?: boolean
})
| 3115 | } |
| 3116 | |
| 3117 | async function callMCPTool({ |
| 3118 | client: { client, name, config }, |
| 3119 | tool, |
| 3120 | args, |
| 3121 | meta, |
| 3122 | signal, |
| 3123 | onProgress, |
| 3124 | imageLimits, |
| 3125 | hasResultSizeAnnotation = false, |
| 3126 | }: { |
| 3127 | client: ConnectedMCPServer |
| 3128 | tool: string |
| 3129 | args: Record<string, unknown> |
| 3130 | meta?: Record<string, unknown> |
| 3131 | signal: AbortSignal |
| 3132 | onProgress?: (data: MCPProgress) => void |
| 3133 | imageLimits?: ImageLimits |
| 3134 | hasResultSizeAnnotation?: boolean |
| 3135 | }): Promise<{ |
| 3136 | content: MCPToolResult |
| 3137 | _meta?: Record<string, unknown> |
| 3138 | structuredContent?: Record<string, unknown> |
| 3139 | }> { |
| 3140 | const toolStartTime = Date.now() |
| 3141 | let progressInterval: NodeJS.Timeout | undefined |
| 3142 | |
| 3143 | try { |
| 3144 | logMCPDebug(name, `Calling MCP tool: ${tool}`) |
| 3145 | |
| 3146 | // Set up progress logging for long-running tools (every 30 seconds) |
| 3147 | progressInterval = setInterval( |
| 3148 | (startTime, name, tool) => { |
| 3149 | const elapsed = Date.now() - startTime |
| 3150 | const elapsedSeconds = Math.floor(elapsed / 1000) |
| 3151 | const duration = `${elapsedSeconds}s` |
| 3152 | logMCPDebug(name, `Tool '${tool}' still running (${duration} elapsed)`) |
| 3153 | }, |
| 3154 | 30000, // Log every 30 seconds |
| 3155 | toolStartTime, |
| 3156 | name, |
| 3157 | tool, |
| 3158 | ) |
| 3159 | |
| 3160 | // Use Promise.race with our own timeout to handle cases where SDK's |
| 3161 | // internal timeout doesn't work (e.g., SSE stream breaks mid-request) |
| 3162 | const timeoutMs = getMcpToolTimeoutMs() |
| 3163 | let timeoutId: NodeJS.Timeout | undefined |
| 3164 | |
| 3165 | const timeoutPromise = new Promise<never>((_, reject) => { |
| 3166 | timeoutId = setTimeout( |
| 3167 | (reject, name, tool, timeoutMs) => { |
| 3168 | reject( |
| 3169 | new TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS( |
| 3170 | `MCP server "${name}" tool "${tool}" timed out after ${Math.floor(timeoutMs / 1000)}s`, |
| 3171 | 'MCP tool timeout', |
| 3172 | ), |
| 3173 | ) |
| 3174 | }, |
no test coverage detected