# How to Use MCP (Model Context Protocol) Servers with aisuite

> Learn how to integrate MCP servers with aisuite to extend LLM capabilities. This guide covers using MCPClient for standardized JSON-RPC protocols to enhance your AI applications.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: how-to-guide
- Published: 2026-06-15

---

**MCP servers integrate with aisuite as external tools that extend LLM capabilities through standardized JSON-RPC protocols, managed via the `MCPClient` class in [`aisuite/mcp/client.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/mcp/client.py).**

aisuite provides a unified interface for interacting with multiple large language model providers. The Model Context Protocol (MCP) integration allows you to connect external tool servers—whether local command-line utilities or remote HTTP services—as first-class citizens in your AI workflows, treating them exactly like native Python functions.

## MCP Architecture in aisuite

The integration relies on three core components that abstract the protocol complexity into aisuite's standard tool-calling interface.

### MCPClient: Connection Management

The `MCPClient` class in [`aisuite/mcp/client.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/mcp/client.py) handles the lifecycle of MCP server connections. It supports two transport mechanisms: **stdio** (spawning local processes) and **HTTP** (connecting to remote endpoints). The client automatically discovers available tools via the `list_tools()` method and generates Python-callable wrappers through `get_callable_tools()`. For resource management, the class implements `__enter__` and `__exit__` methods, enabling context-manager usage for automatic cleanup.

### MCPToolWrapper: Protocol Translation

Located in [`aisuite/mcp/tool_wrapper.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/mcp/tool_wrapper.py), the `MCPToolWrapper` class transforms MCP JSON-Schema tool definitions into proper Python callables. It constructs dynamic function signatures, docstrings, and type annotations that match aisuite's tool inspection requirements. This allows the `Tools` class to treat MCP-provided capabilities identically to native Python functions.

### Configuration and Validation

The [`aisuite/mcp/config.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/mcp/config.py) module defines `MCPConfig` and the `validate_mcp_config` function. This layer normalizes user-provided configuration dictionaries, auto-detects transport types based on provided parameters (detecting `command` for stdio versus `server_url` for HTTP), and applies sane defaults such as `timeout_seconds = 30`.

## Connecting to MCP Servers

aisuite supports both local stdio-based servers and persistent HTTP connections.

### Stdio Transport for Local Tools

Stdio transport launches an MCP server as a subprocess and communicates via standard input/output. This is ideal for local filesystem access or development tools distributed via npm or pip.

```python
import aisuite as ai

client = ai.Client()

response = client.chat.completions.create(
    model="openai:gpt-4o",
    messages=[{"role": "user", "content": "List the files in the current directory"}],
    tools=[{
        "type": "mcp",
        "name": "filesystem",
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
    }],
    max_turns=3,
)
print(response.choices[0].message.content)

```

### HTTP Transport for Remote Services

HTTP transport connects to running MCP endpoints using `httpx` under the hood. This suits microservices or cloud-hosted tools that persist beyond a single invocation.

```python
from aisuite.mcp import MCPClient
import aisuite as ai

mcp = MCPClient(
    server_url="http://localhost:8000/mcp/v1",
    name="weather-api",
    timeout=30.0,
)

client = ai.Client()
response = client.chat.completions.create(
    model="openai:gpt-4o",
    messages=[{"role": "user", "content": "Give me the current weather"}],
    tools=mcp.get_callable_tools(),
    max_turns=3,
)
print(response.choices[0].message.content)

mcp.close()

```

## Implementation Patterns

### Reusable Client Instances

For production applications requiring multiple interactions, instantiate `MCPClient` directly rather than using inline configuration. This maintains persistent connections and avoids the overhead of repeated process spawning.

```python
from aisuite.mcp import MCPClient
import aisuite as ai

mcp = MCPClient(
    command="npx",
    args=["-y", "@modelcontextprotocol/server-filesystem", "."],
    name="filesystem",
)

client = ai.Client()
response = client.chat.completions.create(
    model="openai:gpt-4o",
    messages=[{"role": "user", "content": "What files exist?"}],
    tools=mcp.get_callable_tools(),
    max_turns=2,
)
print(response.choices[0].message.content)

mcp.close()

```

### Automatic Resource Management

Use Python's context manager protocol to ensure connections close properly, particularly critical for HTTP clients holding network sockets or stdio processes requiring termination signals.

```python
from aisuite.mcp import MCPClient
import aisuite as ai

with MCPClient(server_url="http://localhost:8000/mcp/v1", name="api-server") as mcp:
    client = ai.Client()
    resp = client.chat.completions.create(
        model="openai:gpt-4o",
        messages=[{"role": "user", "content": "List available data"}],
        tools=mcp.get_callable_tools(),
        max_turns=2,
    )
    print(resp.choices[0].message.content)

# Connection closes automatically via mcp.__exit__

```

### Hybrid Tool Sets

MCP tools coexist seamlessly with native Python functions. Pass both types in the same `tools` list, and aisuite's execution loop handles dispatching to the appropriate backend.

```python
from aisuite.mcp import MCPClient
import aisuite as ai

def get_current_time() -> str:
    """Return the ISO-formatted current time."""
    from datetime import datetime
    return datetime.now().isoformat()

mcp = MCPClient(
    command="npx",
    args=["-y", "@modelcontextprotocol/server-filesystem", "."],
    name="filesystem",
)

client = ai.Client()
response = client.chat.completions.create(
    model="anthropic:claude-sonnet-4",
    messages=[{"role": "user", "content": "What time is it? Also list files."}],
    tools=[get_current_time, *mcp.get_callable_tools()],
    max_turns=3,
)
print(response.choices[0].message.content)
mcp.close()

```

## Security Controls and Tool Filtering

### Whitelisting Specific Tools

Restrict which capabilities an MCP server exposes using the `allowed_tools` parameter. This whitelist is enforced in `validate_mcp_config` within [`aisuite/mcp/config.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/mcp/config.py) before the tools reach the LLM.

```python
from aisuite.mcp import MCPClient
import aisuite as ai

mcp = MCPClient(
    command="npx",
    args=["-y", "@modelcontextprotocol/server-filesystem", "."],
    name="filesystem",
)

client = ai.Client()
response = client.chat.completions.create(
    model="openai:gpt-4o",
    messages=[{"role": "user", "content": "Read the secret file"}],
    tools=[
        {
            "type": "mcp",
            "name": "filesystem",
            "allowed_tools": ["read_file"],  # Only expose read_file, not write_file

        }
    ],
    max_turns=2,
)
print(response.choices[0].message.content)
mcp.close()

```

### Tool Namespacing

For deployments using multiple MCP servers with potentially overlapping tool names, enable `use_tool_prefix` in the configuration. This prefixes each tool name with the server identifier, preventing collisions while maintaining clarity in the model's tool-selection process.

## Summary

- **MCPClient** in [`aisuite/mcp/client.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/mcp/client.py) manages stdio and HTTP connections, exposing `get_callable_tools()` for integration with aisuite's chat completion interface.
- **MCPToolWrapper** automatically converts JSON-Schema MCP tool definitions into Python callables with proper signatures and docstrings.
- **Transport flexibility** allows local subprocess execution via stdio or persistent HTTP connections to remote services.
- **Security controls** include `allowed_tools` whitelisting and `use_tool_prefix` namespacing, validated through [`aisuite/mcp/config.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/mcp/config.py).
- **Hybrid execution** enables mixing MCP servers with native Python functions in the same tool list.
- **Resource management** is handled via context managers (`with` statements) that automatically close connections and terminate subprocesses.

## Frequently Asked Questions

### What transport protocols does aisuite support for MCP servers?

aisuite supports **stdio** and **HTTP** transports. Stdio launches the MCP server as a subprocess (ideal for local CLI tools like `@modelcontextprotocol/server-filesystem`), while HTTP connects to existing endpoints via `httpx` (suitable for microservices). The `MCPClient` auto-detects the transport based on whether you provide a `command` (stdio) or `server_url` (HTTP) parameter.

### How do I restrict which tools an MCP server can execute?

Use the `allowed_tools` configuration field to specify a whitelist of permitted tool names. This is enforced by `validate_mcp_config` in [`aisuite/mcp/config.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/mcp/config.py) before tools are exposed to the LLM. Only listed tools appear in `get_callable_tools()`, preventing the model from invoking sensitive operations like file deletion or unauthorized API calls.

### Can MCP tools be combined with native Python functions?

Yes. aisuite's tool execution loop accepts heterogeneous tool lists. You can pass a list containing both `MCPToolWrapper` instances (from `mcp.get_callable_tools()`) and regular Python functions to the `tools` parameter in `client.chat.completions.create()`. The framework dispatches calls correctly based on the tool type.

### How does aisuite handle connection cleanup for MCP servers?

The `MCPClient` class implements `__enter__` and `__exit__` methods, making it compatible with Python's `with` statement. For stdio transports, exiting the context manager terminates the subprocess. For HTTP transports, it closes the underlying `httpx` client, releasing network resources. Explicit `close()` calls are also supported for non-context-manager usage patterns.