> ## Documentation Index
> Fetch the complete documentation index at: https://amd-gaia.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Client

> Connect GAIA agents to external MCP servers and use their tools

<Info>
  **Source Code:**

  * [`src/gaia/mcp/mixin.py`](https://github.com/amd/gaia/blob/main/src/gaia/mcp/mixin.py)
  * [`src/gaia/mcp/client/`](https://github.com/amd/gaia/blob/main/src/gaia/mcp/client)
</Info>

<Note>
  **Import:** `from gaia.mcp import MCPClientMixin, MCPClient, MCPClientManager`
</Note>

**See also:** [API Specification](/docs/spec/mcp-client) · [Windows System Health Agent](/docs/guides/mcp/windows-system-health)

***

## What is MCP?

**MCP (Model Context Protocol)** is a universal connector that lets any AI application talk to any tool — a standard created by Anthropic. Instead of building custom integrations for each service, agents connect to MCP servers that expose tools like `read_file`, `create_issue`, or `query_database`.

```
Without MCP:  Agent → Custom Code → GitHub API
              Agent → Custom Code → Filesystem API
              Agent → Custom Code → Database API

With MCP:     Agent → MCP → Any Tool
```

GAIA agents act as **MCP clients** that connect to **MCP servers**. The `MCPClientMixin` adds this capability to any GAIA agent — mix it in, point it at a server, and that server's tools become available automatically.

<Tip>
  **Learn More:** Visit [modelcontextprotocol.io](https://modelcontextprotocol.io/) for the full specification and ecosystem.
</Tip>

### Architecture

```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#E2A33E', 'primaryTextColor':'#1a1a1a', 'primaryBorderColor':'#A87B2D', 'lineColor':'#E2A33E', 'secondaryColor':'#2d2d2d', 'tertiaryColor':'#f5f5f5', 'fontFamily': 'system-ui, -apple-system, sans-serif'}, 'flowchart': {'curve': 'basis'}}}%%
flowchart TB
    User(["User Query"])
    YourAgent(["Your Agent"])
    LLM(["Language Model"])

    subgraph GAIASDK ["GAIA SDK"]
        AgentBase(["Agent"])
        subgraph MCPSDK ["GAIA MCP"]
            Mixin(["MCPClientMixin"])
            Manager(["MCPClientManager"])
            Transport(["Transport"])
        end
    end

    subgraph ExtServers ["External Servers"]
        FS(["Filesystem"])
        GH(["GitHub"])
        DB(["Database"])
        More(["..."])
    end

    User --> YourAgent
    YourAgent --> Mixin
    YourAgent --> AgentBase
    AgentBase --> LLM
    Mixin --> Manager
    Manager --> Transport
    Transport --> FS
    Transport --> GH
    Transport --> DB
    Transport --> More

    style User fill:#2d2d2d,stroke:#1a1a1a,stroke-width:2px,color:#fff
    style YourAgent fill:#E2A33E,stroke:#A87B2D,stroke-width:3px,color:#1a1a1a
    style Mixin fill:#555555,stroke:#A87B2D,stroke-width:2px,color:#fff
    style AgentBase fill:#555555,stroke:#A87B2D,stroke-width:2px,color:#fff
    style Manager fill:#444444,stroke:#A87B2D,stroke-width:2px,color:#fff
    style Transport fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style LLM fill:#1565C0,stroke:#0D47A1,stroke-width:2px,color:#fff
    style FS fill:#2d2d2d,stroke:#1a1a1a,stroke-width:2px,color:#fff
    style GH fill:#2d2d2d,stroke:#1a1a1a,stroke-width:2px,color:#fff
    style DB fill:#2d2d2d,stroke:#1a1a1a,stroke-width:2px,color:#fff
    style More fill:#666,stroke:#999,stroke-width:2px,color:#ccc,stroke-dasharray:3
    style GAIASDK fill:none,stroke:#E2A33E,stroke-width:2px,stroke-dasharray:5,color:#E2A33E
    style MCPSDK fill:none,stroke:#888,stroke-width:2px,stroke-dasharray:5,color:#999
    style ExtServers fill:none,stroke:#2d2d2d,stroke-width:2px,stroke-dasharray:5,color:#2d2d2d

    linkStyle default stroke:#E2A33E,stroke-width:2px
```

***

## Quick Start

<Steps>
  <Step title="Initialize MCP configuration">
    ```bash theme={null}
    gaia init --profile mcp
    ```

    This creates `~/.gaia/mcp_servers.json` with an empty configuration.
  </Step>

  <Step title="Add an MCP server">
    Add a server entry to `~/.gaia/mcp_servers.json`:

    ```json theme={null}
    {
      "mcpServers": {
        "time": { "command": "uvx", "args": ["mcp-server-time"] }
      }
    }
    ```

    <Note>
      `gaia mcp add` / `gaia mcp remove` were removed in #977 — MCP servers are
      now configured through the connectors framework (`gaia connectors --help`)
      or by editing `mcp_servers.json` directly.
    </Note>
  </Step>

  <Step title="Use in your agent">
    ```python theme={null}
    from gaia.agents.base.agent import Agent
    from gaia.mcp import MCPClientMixin

    class MyAgent(Agent, MCPClientMixin):
        def __init__(self, **kwargs):
            Agent.__init__(self, **kwargs)
            MCPClientMixin.__init__(self)  # Config auto-loaded

        def _get_system_prompt(self) -> str:
            return "You are a helpful assistant with access to MCP tools."

        def _register_tools(self) -> None:
            pass  # MCP tools are auto-registered by the mixin

    agent = MyAgent()
    result = agent.process_query("What time is it in Tokyo?")
    print(result.get("result", "No response"))
    ```
  </Step>

  <Step title="Test interactively">
    ```bash theme={null}
    uv run examples/mcp_config_based_agent.py
    ```

    ```
    Connected to MCP servers: time
    Try: 'What time is it in Tokyo?' | Type 'quit' to exit.

    You: What time is it in Tokyo?
    Agent: The current time in Tokyo is 11:59 PM on Wednesday, January 28, 2026 (JST).
    ```
  </Step>
</Steps>

***

## Connect Multiple Servers

Connect to as many servers as needed. GAIA prefixes each tool with the server name (e.g., `mcp_filesystem_read_file`, `mcp_github_create_issue`) so tools from different servers never collide.

```python theme={null}
class MultiToolAgent(Agent, MCPClientMixin):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.connect_mcp_server("filesystem", {
            "command": "npx",
            "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
        })
        self.connect_mcp_server("github", {
            "command": "npx",
            "args": ["-y", "@modelcontextprotocol/server-github"],
            "env": {"GITHUB_TOKEN": "ghp_xxx"}
        })

agent = MultiToolAgent()
response = agent.process_query("List files in /tmp, then create a GitHub issue")
```

***

## Load from Config

A configuration file lets you manage MCP servers without changing agent code. On startup, GAIA automatically stacks two config files — one global default, one project-specific — so you never have to choose between them.

### Config stacking

GAIA loads configs in order of increasing priority:

| Priority     | File                       | Purpose                                     |
| ------------ | -------------------------- | ------------------------------------------- |
| 1 (base)     | `~/.gaia/mcp_servers.json` | Global defaults — shared across all agents  |
| 2 (override) | `./mcp_servers.json`       | Project-specific — wins on any key conflict |

Both files are merged at startup. Servers defined in the local file override same-named entries from the global file. Servers defined only in one file are always included.

### Config file format

```json theme={null}
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "ghp_xxx"
      }
    }
  }
}
```

<Tip>
  The config format follows the [MCP client configuration](https://modelcontextprotocol.io/docs/develop/build-client#mcp-client-configuration) standard.
  If you already have an MCP config from another client (e.g. Claude Desktop), you can copy it directly.
</Tip>

### Using config in your agent

By default, `MCPClientMixin.__init__()` auto-loads both config files:

```python theme={null}
class ConfigAgent(Agent, MCPClientMixin):
    def __init__(self, **kwargs):
        Agent.__init__(self, **kwargs)
        MCPClientMixin.__init__(self)  # auto-loads global + local config

agent = ConfigAgent()
servers = agent.list_mcp_servers()
```

To load a specific config file instead (skips stacking):

```python theme={null}
MCPClientMixin.__init__(self, config_file="/path/to/mcp_servers.json")
```

When `config_file` is provided, only that file is loaded — global and local stacking are disabled. Loading is always triggered when `config_file` is set, regardless of the `auto_load_config` flag.

### Popular Servers

<Tabs>
  <Tab title="Filesystem">
    ```python theme={null}
    agent.connect_mcp_server("filesystem", {
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/directory"]
    })
    ```
  </Tab>

  <Tab title="GitHub">
    ```python theme={null}
    agent.connect_mcp_server("github", {
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-github"],
        "env": {"GITHUB_TOKEN": "ghp_your_token_here"}
    })
    ```
  </Tab>

  <Tab title="Python Servers">
    ```python theme={null}
    agent.connect_mcp_server("time", {
        "command": "uvx",
        "args": ["mcp-server-time"]
    })
    ```
  </Tab>
</Tabs>

<Tip>
  **Finding servers:** Browse the [MCP Server Hub on glama.ai](https://glama.ai/mcp/servers) or the [official MCP servers list](https://github.com/modelcontextprotocol/servers).
</Tip>

***

## Direct Client Usage

`MCPClient` is the lower-level building block for use outside of agents — in standalone scripts, test suites, or custom pipelines.

```python theme={null}
from gaia.mcp.client import MCPClient

client = MCPClient.from_config("filesystem", {
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
})

if client.connect():
    tools = client.list_tools()
    result = client.call_tool("read_file", {"path": "/tmp/example.txt"})
    client.disconnect()
```

<Note>
  `MCPClient` only supports **stdio** transport (subprocess-based). HTTP and SSE transports are not supported at this time.
</Note>

***

## Error Handling

GAIA's MCP client uses a **return-value** error model rather than raising exceptions for expected failures.

```python theme={null}
success = agent.connect_mcp_server("server", {
    "command": "npx",
    "args": ["-y", "@mcp/server"]
})
if not success:
    print("Connection failed")

client = agent.get_mcp_client("server")
result = client.call_tool("tool", {"arg": "value"})
if "error" in result:
    print(f"Tool failed: {result['error']}")
```

***

## API Reference

### MCPClientMixin

| Method                             | Description                                         |
| ---------------------------------- | --------------------------------------------------- |
| `connect_mcp_server(name, config)` | Connect and register tools. Returns `bool`.         |
| `disconnect_mcp_server(name)`      | Disconnect and unregister                           |
| `list_mcp_servers()`               | List connected server names. Returns `list[str]`.   |
| `get_mcp_client(name)`             | Get client instance. Returns `MCPClient` or `None`. |
| `load_mcp_servers_from_config()`   | Load from config file. Returns `int` (count).       |

### MCPClient

| Method                        | Description                                             |
| ----------------------------- | ------------------------------------------------------- |
| `from_config(name, config)`   | Create client from config dict                          |
| `from_command(name, command)` | Create client (legacy, shell string)                    |
| `connect()`                   | Connect to server. Returns `bool`.                      |
| `disconnect()`                | Disconnect                                              |
| `list_tools()`                | List available tools (cached). Returns `list[MCPTool]`. |
| `call_tool(name, args)`       | Execute a tool. Returns `dict`.                         |

***

## CLI Commands

```bash theme={null}
gaia mcp list                    # List configured servers
gaia mcp tools <name>            # List tools from server
gaia mcp test-client <name>      # Test connection
```

<Note>
  `gaia mcp add` and `gaia mcp remove` were removed in #977. MCP servers are now
  managed through the connectors framework (`gaia connectors --help`) or by editing
  `~/.gaia/mcp_servers.json` directly.
</Note>

***

## Security

<Warning>
  **Vet MCP servers before connecting.** Each server runs as a subprocess with access to your system.
</Warning>

1. **Review the source** — Only use servers from trusted sources with public repositories
2. **Check permissions** — Understand what system access the server requires
3. **Limit scope** — Restrict filesystem servers to specific directories rather than `/`
4. **Audit environment variables** — Never pass secrets to servers you haven't reviewed

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Connection fails with 'command not found'">
    The MCP server command (like `npx` or `uvx`) isn't in your PATH.

    ```bash theme={null}
    # Check if npx is available
    which npx

    # If not, install Node.js via NVM
    # See Setup guide for instructions
    ```
  </Accordion>

  <Accordion title="Config file not found">
    `load_mcp_servers_from_config()` returns 0 servers. GAIA merges two config files at startup:

    1. `~/.gaia/mcp_servers.json` — global config, always checked
    2. `./mcp_servers.json` — local config, checked in the current working directory

    Verify the files exist:

    ```bash theme={null}
    cat ~/.gaia/mcp_servers.json  # Global config
    cat ./mcp_servers.json        # Local config (CWD)
    ```

    To use a specific config file instead, pass it explicitly — this loads only
    that file and skips the global and local configs entirely:

    ```python theme={null}
    MCPClientMixin.__init__(self, config_file="/path/to/mcp_servers.json")
    ```
  </Accordion>

  <Accordion title="Tools not appearing in agent">
    1. Verify connection: `print(agent.list_mcp_servers())`
    2. List tools: `gaia mcp tools <server-name>`
    3. Enable debug: `import logging; logging.basicConfig(level=logging.DEBUG)`
  </Accordion>

  <Accordion title="Server process hangs or times out">
    Requests time out after 30s by default. For servers that need a longer
    timeout, use the lower-level `MCPClient`, which accepts `timeout` (seconds):

    ```python theme={null}
    from gaia.mcp.client import MCPClient

    client = MCPClient.from_config("server", config, timeout=60)
    client.connect()
    ```

    Test directly: `gaia mcp test-client <server-name>`
  </Accordion>
</AccordionGroup>

***

## Related

* [API Specification](/docs/spec/mcp-client) — Complete API reference
* [Windows System Health Agent](/docs/guides/mcp/windows-system-health) — Example MCP agent
* [CLI Reference](/docs/reference/cli#mcp-client) — CLI commands

***

<small style="color: #666;">
  Copyright(C) 2024-2026 Advanced Micro Devices, Inc. All rights reserved.

  SPDX-License-Identifier: MIT
</small>
