Tencent/WeKnora · error

failed to list tools: %w

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.

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)

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.