# MCP Toolbox (/tools/mcp/mcp-toolbox)



<Badge icon="code-branch" color="orange">
  <Tooltip tip="Introduced in v2.0.9" cta="View release notes" href="https://github.com/agno-agi/agno/releases/tag/v2.0.9">
    v2.0.9
  </Tooltip>
</Badge>

**MCPToolbox** enables Agents to connect to Google's [MCP Toolbox for Databases](https://googleapis.github.io/genai-toolbox/getting-started/introduction/) with advanced filtering capabilities. It extends Agno's `MCPTools` functionality to filter tools by toolset or tool name, allowing agents to load only the specific database tools they need.

## Prerequisites [#prerequisites]

You'll need the following to use MCPToolbox:

```bash
uv pip install "agno[mcp]" toolbox-core
```

Our default setup will also require you to have Docker or Podman installed, to run the MCP Toolbox server and database for the examples.

## Quick Start [#quick-start]

Clone the reviewed source and use a separate environment with the current MCP extra. The demo project's older lockfile does not include FastMCP.

```bash
# Clone the repo and navigate to the demo folder
git clone https://github.com/agno-agi/agno.git
cd agno
git checkout 8f36eaf2d18e91afa7b327eec66a3cd3685dcb87
cd cookbook/91_tools/mcp/mcp_toolbox_demo

# Start the database and MCP Toolbox servers

# With Docker and Docker Compose (or use podman compose)
docker compose up -d

# Install in an activated environment without synchronizing the old project lock.
uv venv --python 3.13 .venv
source .venv/bin/activate
uv pip install -e "../../../../libs/agno[os,mcp,openai]" sqlalchemy toolbox-core

# Set your API key and run the basic agent
export OPENAI_API_KEY="your_openai_api_key"
python agent.py
```

This starts a PostgreSQL database with sample hotel data and an MCP Toolbox server that exposes database operations as filtered tools.

## Verification [#verification]

To verify that your docker/podman setup is working correctly, you can check the database connection:

```bash
# Using Docker Compose
docker compose exec db psql -U toolbox_user -d toolbox_db -c "SELECT COUNT(*) FROM hotels;"

# Using Podman
podman compose exec db psql -U toolbox_user -d toolbox_db -c "SELECT COUNT(*) FROM hotels;"
```

## Basic Example [#basic-example]

Here's the simplest way to use MCPToolbox (after running the Quick Start setup):

```python
import asyncio
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.tools.mcp_toolbox import MCPToolbox

async def main():
    # Connect to the running MCP Toolbox server and filter to hotel tools only
    async with MCPToolbox(
        url="http://127.0.0.1:5001",
        toolsets=["hotel-management"]  # Only load hotel search tools
    ) as toolbox:
        agent = Agent(
            model=OpenAIResponses(id="gpt-5.2"),
            tools=[toolbox],
            instructions="You help users find hotels. Always mention hotel ID, name, location, and price tier."
        )

        # Ask the agent to find hotels
        await agent.aprint_response("Find luxury hotels in Zurich")

# Run the example
asyncio.run(main())
```

## How MCPToolbox Works [#how-mcptoolbox-works]

The demo server exposes six tools across two toolsets. `MCPToolbox` discovers the MCP tools, loads the selected toolset's names through toolbox-core, and exposes the matching MCP functions to the agent.

```python
# Expose the three tools in the demo's hotel-management toolset.
tools = MCPToolbox(url="http://127.0.0.1:5001", toolsets=["hotel-management"])
```

## Advanced Usage [#advanced-usage]

### Multiple Toolsets [#multiple-toolsets]

Load tools from multiple related toolsets:

```python
import asyncio
from textwrap import dedent
from agno.agent import Agent
from agno.tools.mcp_toolbox import MCPToolbox

url = "http://127.0.0.1:5001"

async def run_agent(message: str = None) -> None:
    """Run an interactive CLI for the Hotel agent with the given message."""

    async with MCPToolbox(
        url=url, toolsets=["hotel-management", "booking-system"]
    ) as db_tools:
        print(db_tools.functions)  # Print available tools for debugging
        agent = Agent(
            tools=[db_tools],
            instructions=dedent(
                """ \
                You're a helpful hotel assistant. You handle hotel searching, booking and
                cancellations. When the user searches for a hotel, mention it's name, id,
                location and price tier. Always mention hotel ids while performing any
                searches. This is very important for any operations. For any bookings or
                cancellations, please provide the appropriate confirmation. Be sure to
                update checkin or checkout dates if mentioned by the user.
                Don't ask for confirmations from the user.
            """
            ),
            markdown=True,
            add_history_to_context=True,
            debug_mode=True,
        )

        await agent.acli_app(input=message, stream=True)

if __name__ == "__main__":
    asyncio.run(run_agent(message=None))
```

### Custom Authentication and Parameters [#custom-authentication-and-parameters]

The current adapter's `auth_token_getters` and `bound_params` are passed to toolbox-core discovery, but the returned Agno functions remain the previously registered MCP functions. These settings do not bind authentication or hidden arguments to those functions' later execution. Configure and verify authorization at the actual MCP server boundary before using protected data.

Calling `load_tool` or `load_toolset` after connecting an unfiltered `MCPToolbox(url=...)` also lacks an initialized toolbox-core client. Select `toolsets` or `tool_name` in the constructor, as in the examples above. These are current adapter limitations.

### Manual Connection Management [#manual-connection-management]

For explicit control over connections:

```python
async def manual_connection_example():
    # Initialize without auto-connection
    toolbox = MCPToolbox(url=url, toolsets=["hotel-management"])

    try:
        await toolbox.connect()
        agent = Agent(
            tools=[toolbox],
            instructions="Hotel search assistant.",
            markdown=True
        )
        await agent.aprint_response("Show me hotels in Basel")
    finally:
        await toolbox.close()  # Always clean up
```

## Toolkit Params [#toolkit-params]

| Parameter           | Type                       | Default             | Description                                                                                           |
| ------------------- | -------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------- |
| `url`               | `str`                      | -                   | Base URL for the toolbox service (automatically appends "/mcp" if missing)                            |
| `toolsets`          | `Optional[List[str]]`      | `None`              | List of toolset names to filter tools by. Cannot be used with `tool_name`.                            |
| `tool_name`         | `Optional[str]`            | `None`              | Single tool name to load. Cannot be used with `toolsets`.                                             |
| `headers`           | `Optional[Dict[str, Any]]` | `None`              | HTTP headers for toolbox-core discovery requests; not forwarded to the underlying MCPTools connection |
| `transport`         | `str`                      | `"streamable-http"` | MCP transport protocol. Options: `"stdio"`, `"sse"`, `"streamable-http"`                              |
| `append_mcp_to_url` | `bool`                     | `True`              | Append "/mcp" to the URL if it doesn't end with it                                                    |

<Note>
  Only one of `toolsets` or `tool_name` can be specified. The implementation validates this and raises a `ValueError` if both are provided.
</Note>

## Toolkit Functions [#toolkit-functions]

| Function                                                                                            | Description                                                                                        |
| --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `async connect()`                                                                                   | Initialize and connect to both MCP server and toolbox client                                       |
| `async load_tool(tool_name, auth_token_getters={}, bound_params={})`                                | Discover a named tool and return its registered MCP function; see authentication limitations above |
| `async load_toolset(toolset_name, auth_token_getters={}, bound_params={}, strict=False)`            | Load all tools from a specific toolset                                                             |
| `async load_multiple_toolsets(toolset_names, auth_token_getters={}, bound_params={}, strict=False)` | Load tools from multiple toolsets                                                                  |
| `async load_toolset_safe(toolset_name)`                                                             | Safely load a toolset and return tool names for error handling                                     |
| `get_client()`                                                                                      | Get the underlying ToolboxClient instance                                                          |
| `async close()`                                                                                     | Close both toolbox client and MCP client connections                                               |

## Demo Examples [#demo-examples]

The demo source includes these patterns. Apply the environment setup and adapter limitations above when exploring them:

* **[Basic Agent](https://github.com/agno-agi/agno/blob/main/cookbook/91_tools/mcp/mcp_toolbox_demo/agent.py)**: Simple hotel assistant with toolset filtering
* **[AgentOS Integration](https://github.com/agno-agi/agno/blob/main/cookbook/91_tools/mcp/mcp_toolbox_demo/agent_os.py)**: Integration with AgentOS control plane
* **[Workflow Integration](https://github.com/agno-agi/agno/blob/main/cookbook/91_tools/mcp/mcp_toolbox_demo/hotel_management_workflows.py)**: Using MCPToolbox in Agno workflows
* **[Type-Safe Agent](https://github.com/agno-agi/agno/blob/main/cookbook/91_tools/mcp/mcp_toolbox_demo/hotel_management_typesafe.py)**: Implementation with Pydantic models

You can use `include_tools` or `exclude_tools` to modify the list of tools the agent has access to. Learn more about [selecting tools](/tools/selecting-tools).

## Developer Resources [#developer-resources]

* [Tools](https://github.com/agno-agi/agno/blob/main/libs/agno/agno/tools/mcp_toolbox.py)
* [Cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/91_tools/mcp/mcp_toolbox_demo)

See the [MCP Toolbox for Databases documentation](https://googleapis.github.io/genai-toolbox/getting-started/introduction/).

Stop the local demo services with `docker compose down` (or `podman compose down`) when finished.
