alibaba/open-code-review · error
call MCP tool %q: %w
Error message
call MCP tool %q: %w
What it means
CallTool wraps any error returned by the MCP session's CallTool request with 'call MCP tool %q: %w'. It covers transport/session failures (connection dropped, timeout, context cancelled, protocol-level errors) — tool-level failures reported inside a successful response are NOT this error; they come back as a string with result.IsError.
Source
Thrown at internal/mcp/client.go:166
resp.Body.Close()
return nil, fmt.Errorf("remote MCP server %q returned HTTP 403 Forbidden — your credentials may lack required permissions", t.serverName)
}
return resp, nil
}
func (c *Client) Name() string { return c.name }
func (c *Client) Tools() []*mcp.Tool { return c.tools }
// CallTool invokes a tool on the MCP server and returns the text result.
func (c *Client) CallTool(ctx context.Context, name string, args map[string]any) (string, error) {
params := &mcp.CallToolParams{
Name: name,
Arguments: args,
}
result, err := c.session.CallTool(ctx, params)
if err != nil {
return "", fmt.Errorf("call MCP tool %q: %w", name, err)
}
if result.IsError {
return fmt.Sprintf("MCP tool %q returned an error: %s", name, contentToText(result.Content)), nil
}
return contentToText(result.Content), nil
}
func (c *Client) Close() error {
return c.session.Close()
}
func contentToText(contents []mcp.Content) string {
var parts []string
for _, item := range contents {
switch v := item.(type) {
case *mcp.TextContent:View on GitHub (pinned to 5cf97d0d15)
Solutions
- Check the wrapped error (%w chain) to distinguish network/timeout vs protocol errors; re-connect the MCP client if the session is stale
- Verify the tool name against Client.Tools() before calling
- Increase the context deadline for slow tools, or re-invoke with a fresh context
- Confirm the remote MCP server is healthy and reachable
Example fix
// before
res, err := client.CallTool(ctx, "search_docs", args)
// after — guard with a fresh context and pre-check the tool
if !hasTool(client.Tools(), "search_docs") { return fmt.Errorf("tool search_docs unavailable") }
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
res, err := client.CallTool(ctx, "search_docs", args) Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check the tool exists on this client
toolNames := map[string]bool{}
for _, t := range client.Tools() { toolNames[t.Name] = true }
if !toolNames["search_docs"] { return fmt.Errorf("tool not offered by server") } Try / catch
res, err := client.CallTool(ctx, name, args)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
// retry with a longer deadline or smaller workload
} else {
// wrapped session/transport failure: reconnect the MCP client
}
// Note: tool-level errors arrive as res == "MCP tool %q returned an error: ...", err == nil
} Prevention
- Validate tool names against Client.Tools() before invoking
- Set generous context timeouts for long-running tools
- Recreate the client if the remote server may have restarted
- Treat in-band tool errors (result.IsError) separately from transport errors
When it happens
Trigger: c.session.CallTool returns a non-nil error: the remote MCP connection is down, the request timed out or the context was cancelled, the tool name is unknown at the server, or the session was closed.
Common situations: MCP server restarted mid-session leaving a stale connection; long-running tool exceeding the caller's context deadline; typo in the tool name (tool was listed but later removed); network interruption to the remote MCP endpoint.
Related errors
- MCP server %q not found
- invalid MCP server key %q: expected mcp_servers.<name>.<fiel
- invalid MCP server type %q: must be "stdio" or "remote"
- MCP server command cannot be empty
- invalid JSON array for %s: %w
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/6b25fafa6fda8c40.
Report an issue: GitHub.