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

  1. Reconnect: call Connect + Initialize again (check for ErrNotConnected / disconnected state) and retry ListTools
  2. Increase the AdvancedConfig.Timeout or use a shorter-lived context appropriate to the RPC
  3. Verify the server advertises the tools capability in its initialize response
  4. 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

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


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)