crewAIInc/crewAI · error · ValueError

MCP server not started, run `mcp_server.start()` first befor

Error message

MCP server not started, run `mcp_server.start()` first before accessing `tools`

What it means

Raised by the `tools` property of MCPServerAdapt when the internal `self._tools` is still None, meaning `start()` was never called or did not complete. The constructor normally starts the server automatically, so this mainly surfaces after a failed init path or when the object was constructed in a state where start did not run.

Source

Thrown at lib/crewai-tools/src/crewai_tools/adapters/mcp_adapter.py:211

        """Start the MCP server and initialize the tools."""
        self._tools = self._adapter.__enter__()  # type: ignore[union-attr]

    def stop(self) -> None:
        """Stop the MCP server."""
        self._adapter.__exit__(None, None, None)  # type: ignore[union-attr]

    @property
    def tools(self) -> ToolCollection[BaseTool]:
        """The CrewAI tools available from the MCP server.

        Raises:
            ValueError: If the MCP server is not started.

        Returns:
            The CrewAI tools available from the MCP server.
        """
        if self._tools is None:
            raise ValueError(
                "MCP server not started, run `mcp_server.start()` first before accessing `tools`"
            )

        tools_collection = ToolCollection(self._tools)
        if self._tool_names:
            return tools_collection.filter_by_names(self._tool_names)
        return tools_collection

    def __enter__(self) -> ToolCollection[BaseTool]:
        """Enter the context manager.

        Note that `__init__()` already starts the MCP server,
        so tools should already be available.
        """
        return self.tools

    def __exit__(
        self,

View on GitHub (pinned to 754d7323be)

Solutions

  1. Call `mcp_server.start()` before reading `mcp_server.tools`.
  2. Prefer the context-manager form (`with MCPServerAdapt(...) as tools:`) so __enter__ guarantees a started server.
  3. If init previously failed, fix the underlying init error first (see 'Failed to initialize MCP Adapter') — a stopped server has no tools.

Example fix

# before
server = MCPServerAdapt(params)
print(server.tools)  # ValueError if not started

# after
server = MCPServerAdapt(params)
server.start()
print(server.tools)
Defensive patterns

Strategy: validation

Validate before calling

def get_tools(server):
    if getattr(server, "_tools", None) is None:
        server.start()  # idempotent enough via __enter__
    return server.tools

Type guard

def is_started(server) -> bool:
    return server._tools is not None

Try / catch

try:
    tools = server.tools
except ValueError:
    server.start()
    tools = server.tools

Prevention

When it happens

Trigger: Accessing `mcp_server.tools` before the server started — e.g. an object created when __init__ caught an exception path left _tools None, or a manually crafted/half-initialized instance where start() was skipped. The property checks `if self._tools is None` and raises ValueError.

Common situations: Using the adapter as a context manager but accessing `.tools` after an exception was swallowed, or subclassing/reconstructing MCPServerAdapt without calling start(). Also seen when init partially failed and the caller ignores the error then reads .tools.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/6ee156fa4ae658ea. Report an issue: GitHub.