huggingface/smolagents · error · ValueError

Couldn't retrieve tools from MCP server, run `mcp_client.con

Error message

Couldn't retrieve tools from MCP server, run `mcp_client.connect()` first before accessing `tools`

What it means

MCPClient.get_tools() returns the tools discovered from the MCP server, which are only populated after a successful connect(). If connect() was never called (or hasn't finished), self._tools is None and get_tools raises ValueError with an instruction to connect first. This typically surfaces as an attribute-style access `mcp_client.tools` since tools is a property delegating to get_tools.

Source

Thrown at src/smolagents/mcp_client.py:151

    ):
        """Disconnect from the MCP server"""
        self._adapter.__exit__(exc_type, exc_value, exc_traceback)

    def get_tools(self) -> list[Tool]:
        """The SmolAgents tools available from the MCP server.

        Note: for now, this always returns the tools available at the creation of the session,
        but it will in a future release return also new tools available from the MCP server if
        any at call time.

        Raises:
            ValueError: If the MCP server tools is None (usually assuming the server is not started).

        Returns:
            list[Tool]: The SmolAgents tools available from the MCP server.
        """
        if self._tools is None:
            raise ValueError(
                "Couldn't retrieve tools from MCP server, run `mcp_client.connect()` first before accessing `tools`"
            )
        return self._tools

    def __enter__(self) -> list[Tool]:
        """Connect to the MCP server and return the tools directly.

        Note that because of the `.connect` in the init, the mcp_client
        is already connected at this point.
        """
        return self._tools

    def __exit__(
        self,
        exc_type: type[BaseException] | None,
        exc_value: BaseException | None,
        exc_traceback: TracebackType | None,
    ):

View on GitHub (pinned to 30bb116109)

Solutions

  1. Use the context-manager form: `with MCPClient(params) as tools:` which connects and returns tools
  2. Or call mcp_client.connect() explicitly before accessing .tools
  3. Ensure connect() succeeded (no swallowed exceptions) before reading tools

Example fix

# before
client = MCPClient(params)
tools = client.tools  # ValueError

# after
client = MCPClient(params)
client.connect()
tools = client.tools
# or: with MCPClient(params) as tools: ...
Defensive patterns

Strategy: validation

Validate before calling

client = MCPClient(params)
client.connect()
assert client._tools is not None, 'connect() did not populate tools'
tools = client.tools

Type guard

def mcp_client_ready(client) -> bool:
    return getattr(client, "_tools", None) is not None

Try / catch

try:
    tools = client.tools
except ValueError as e:
    if 'run `mcp_client.connect()`' in str(e):
        client.connect()
        tools = client.tools

Prevention

When it happens

Trigger: Accessing mcp_client.tools before calling mcp_client.connect(), or constructing MCPClient and immediately reading .tools instead of using it as a context manager.

Common situations: Skipping the `with MCPClient(...) as tools:` pattern from the docs and calling connect()/tools manually in the wrong order; connect() failing silently in error handling paths.

Related errors


AI-assisted analysis of huggingface/smolagents@30bb116109 (2026-08-28). Data as JSON: /api/errors/3ed8e9f5704bc0b2. Report an issue: GitHub.