Tencent/WeKnora · error
failed to list tools
Error message
failed to list tools: %w
What it means
ListTools wraps errors from c.client.ListTools after a successful initialize. It indicates the tools/list RPC failed: the connection dropped, the server returned a JSON-RPC error, the request timed out, or the server does not support the tools capability. checkErrorAndDisconnectIfNeeded runs first and may mark the client disconnected on fatal errors.
Solutions
- Reconnect: call Connect + Initialize again (check for ErrNotConnected / disconnected state) and retry ListTools
- Increase the AdvancedConfig.Timeout or use a shorter-lived context appropriate to the RPC
- Verify the server advertises the tools capability in its initialize response
- Check proxy/LB idle timeouts that kill long-lived SSE/streamable sessions
Example fix
// before
tools, err := c.ListTools(ctx)
if err != nil { return nil, err }
// after
tools, err := c.ListTools(ctx)
if err != nil {
if rerr := reconnectAndInit(ctx, c); rerr != nil { return nil, rerr }
tools, err = c.ListTools(ctx)
if err != nil { return nil, err }
} Defensive patterns
Strategy: retry
Validate before calling
func listToolsWithReconnect(ctx context.Context, c MCPClient) ([]*types.MCPTool, error) {
tools, err := c.ListTools(ctx)
if err == nil { return tools, nil }
_ = c.Disconnect()
if err := c.Connect(ctx); err != nil { return nil, err }
if _, err := c.Initialize(ctx); err != nil { return nil, err }
return c.ListTools(ctx)
} Type guard
func isListToolsFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to list tools")
} Try / catch
tools, err := c.ListTools(ctx)
if err != nil {
if errors.Is(err, ErrNotConnected) || isListToolsFailure(err) {
return listToolsWithReconnect(ctx, c) // single reconnect+retry
}
return nil, err
} Prevention
- Keep clients short-lived or add periodic reconnects before server session expiry
- Set proxy/LB idle timeouts longer than the longest expected RPC
- Verify server tools capability in InitializeResult before listing
When it happens
Trigger: ListTools called on an initialized client whose session has since expired/been closed by the server, whose context deadline expired mid-RPC, or whose server replies with a JSON-RPC error (e.g. capability not implemented).
Common situations: Long-lived client reused past the server's session timeout; server restarted between initialize and list tools; calling ListTools against a server that doesn't advertise the tools capability; idle SSE connection severed by a proxy/load balancer.
Related errors
- failed to list resources
- failed to call tool
- failed to create HTTP streamable client
- failed to create SSE client
- failed to generate schema
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/91c42135f24cd4c6.
Report an issue: GitHub.
Appendix: source
Thrown at internal/mcp/client.go:426
Title: result.ServerInfo.Title,
Description: result.ServerInfo.Description,
},
}, nil
}
// ListTools retrieves the list of available tools
func (c *mcpGoClient) ListTools(ctx context.Context) ([]*types.MCPTool, error) {
if !c.initialized {
return nil, ErrNotConnected
}
req := mcp.ListToolsRequest{}
result, err := oauthCall(ctx, c, func() (*mcp.ListToolsResult, error) {
return c.client.ListTools(ctx, req)
})
if err != nil {
c.checkErrorAndDisconnectIfNeeded(err)
return nil, fmt.Errorf("failed to list tools: %w", err)
}
// Convert to our types
tools := make([]*types.MCPTool, len(result.Tools))
for i, tool := range result.Tools {
data, _ := json.Marshal(tool.InputSchema)
tools[i] = &types.MCPTool{
Name: tool.Name,
Description: tool.Description,
InputSchema: data,
}
}
return tools, nil
}
// ListResources retrieves the list of available resources
func (c *mcpGoClient) ListResources(ctx context.Context) ([]*types.MCPResource, error) {View on GitHub (pinned to 988cbb0330)