{"record":{"id":"6b25fafa6fda8c40","repo":"alibaba/open-code-review","slug":"call-mcp-tool-q-w","errorCode":null,"errorMessage":"call MCP tool %q: %w","messagePattern":"call MCP tool %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/client.go","lineNumber":166,"sourceCode":"\t\tresp.Body.Close()\n\t\treturn nil, fmt.Errorf(\"remote MCP server %q returned HTTP 403 Forbidden — your credentials may lack required permissions\", t.serverName)\n\t}\n\treturn resp, nil\n}\n\nfunc (c *Client) Name() string       { return c.name }\nfunc (c *Client) Tools() []*mcp.Tool { return c.tools }\n\n// CallTool invokes a tool on the MCP server and returns the text result.\nfunc (c *Client) CallTool(ctx context.Context, name string, args map[string]any) (string, error) {\n\tparams := &mcp.CallToolParams{\n\t\tName:      name,\n\t\tArguments: args,\n\t}\n\n\tresult, err := c.session.CallTool(ctx, params)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"call MCP tool %q: %w\", name, err)\n\t}\n\n\tif result.IsError {\n\t\treturn fmt.Sprintf(\"MCP tool %q returned an error: %s\", name, contentToText(result.Content)), nil\n\t}\n\n\treturn contentToText(result.Content), nil\n}\n\nfunc (c *Client) Close() error {\n\treturn c.session.Close()\n}\n\nfunc contentToText(contents []mcp.Content) string {\n\tvar parts []string\n\tfor _, item := range contents {\n\t\tswitch v := item.(type) {\n\t\tcase *mcp.TextContent:","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/mcp/client.go#L148-L184","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nres, err := client.CallTool(ctx, \"search_docs\", args)\n// after — guard with a fresh context and pre-check the tool\nif !hasTool(client.Tools(), \"search_docs\") { return fmt.Errorf(\"tool search_docs unavailable\") }\nctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)\ndefer cancel()\nres, err := client.CallTool(ctx, \"search_docs\", args)","handlingStrategy":"try-catch","validationCode":"// pre-check the tool exists on this client\ntoolNames := map[string]bool{}\nfor _, t := range client.Tools() { toolNames[t.Name] = true }\nif !toolNames[\"search_docs\"] { return fmt.Errorf(\"tool not offered by server\") }","typeGuard":null,"tryCatchPattern":"res, err := client.CallTool(ctx, name, args)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        // retry with a longer deadline or smaller workload\n    } else {\n        // wrapped session/transport failure: reconnect the MCP client\n    }\n    // Note: tool-level errors arrive as res == \"MCP tool %q returned an error: ...\", err == nil\n}","preventionTips":["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"],"tags":["mcp","rpc","network","tool-invocation"],"backgroundTag":"mcp-tool-call-failed","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}