conductor-oss/conductor · error · RuntimeException
Failed to call MCP tool '{toolName}' on {serverUrl}: {messag
Error message
Failed to call MCP tool '{toolName}' on {serverUrl}: {message} What it means
Catch-all wrapper thrown by callToolDirectHttp's outer catch (Exception). Wraps ANY exception from the tool-call flow (165/166/167, SSE parse 169/170, redirect 171-173, payload limit 175/176, or network IOException) with toolName, serverUrl, original message, and the cause. This is the exception callers of callTool see for almost every failure.
Source
Thrown at ai/src/main/java/org/conductoross/conductor/ai/mcp/MCPService.java:289
// Process the result JSON to parse text content as JSON where applicable
processResultJson(resultNode);
// Return as Map to preserve parsed field
Map<String, Object> result = objectMapper.convertValue(resultNode, Map.class);
ExternalDataLimits.validateStructure(result);
log.debug(
"Successfully called tool '{}' via direct JSON-RPC on {}", toolName, serverUrl);
return result;
} catch (Exception e) {
log.error(
"Failed to call tool '{}' via direct JSON-RPC on {}: {}",
toolName,
serverUrl,
e.getMessage());
throw new RuntimeException(
"Failed to call MCP tool '"
+ toolName
+ "' on "
+ serverUrl
+ ": "
+ e.getMessage(),
e);
}
}
/**
* Processes a CallToolResult JSON node to parse JSON strings in text content.
*
* <p>Modifies the JSON response before deserialization to convert JSON strings to objects.
*/
private void processResultJson(JsonNode resultNode) {
if (resultNode == null || !resultNode.has("content")) {
return;View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Inspect e.getCause() for the real failure; the wrapper text alone is insufficient.
- Map the cause to its specific error (165-167, 169-170, 171-176) and apply that fix.
- For transient network causes, retry with backoff.
- Log the unwrapped cause chain so dashboards show root reasons.
Defensive patterns
Strategy: try-catch
Try / catch
try {
Map<String,Object> r = mcpService.callTool(serverUrl, toolName, arguments, headers);
} catch (RuntimeException e) {
Throwable root = e;
while (root.getCause() != null && root.getCause() != root) root = root.getCause();
log.error("callTool '{}' failed for {}: rootCause={}", toolName, serverUrl, root.toString());
throw e;
} Prevention
- Unwrap the cause to find the real failure class.
- Route root-cause info to monitoring, not the wrapper prefix.
- Retry only on transient root causes (network/5xx), never on protocol/security causes.
When it happens
Trigger: Any uncaught exception inside callToolDirectHttp's try: network timeout, SSL/DNS failure, JSON-RPC protocol error, redirect/credential/payload violation, or one of errors 165-167/169/170.
Common situations: Server unreachable; auth expired; tool crashed; arguments invalid. The wrapper hides the root cause behind a generic prefix — operators must read getCause().
Related errors
- Failed to list MCP tools from {serverUrl}: {message}
- HTTP %d error from MCP server: %s
- {error}
- MCP server returned a redirect without a valid Location
- MCP server exceeded the redirect limit
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/25dd036505d3ed3f.
Report an issue: GitHub.