How to Integrate MCP (Model Context Protocol) Servers with aisuite
aisuite exposes external tools to LLMs through MCP servers by passing a configuration dictionary with "type": "mcp" to the tools parameter in client.chat.completions.create(), which validate_mcp_config() processes before MCPClient handles the server lifecycle.
The aisuite library provides a unified interface for interacting with large language models across multiple providers. When you integrate MCP servers with aisuite, you can extend LLM capabilities with external tools without managing complex server boilerplate. The configuration follows the MCPConfig TypedDict defined in aisuite/mcp/config.py, enabling both stdio and HTTP transport methods.
Understanding the MCP Configuration Schema
The foundation of MCP integration lies in the configuration dictionary structure. In aisuite/mcp/config.py, the MCPConfig TypedDict defines the expected schema that aisuite uses to initialize tool connections. When a request is sent to client.chat.completions.create, the library examines each entry in the tools list. If an entry has "type": "mcp", aisuite passes it to validate_mcp_config() for processing.
Transport Type Detection
The configuration supports two mutually exclusive transport methods. At lines 95-100 of aisuite/mcp/config.py, validate_mcp_config() ensures exactly one transport is specified:
- stdio transport: Use the
"command"field to specify an executable that runs the MCP server locally - HTTP transport: Use the
"server_url"field to connect to a remote MCP server endpoint
Validating and Processing MCP Configurations
The validate_mcp_config() function in aisuite/mcp/config.py performs five critical validation steps:
- Type and name verification: Ensures the config type is
"mcp"and that a non-empty"name"is supplied - Transport detection: Identifies whether the configuration uses stdio (
"command"field) or HTTP ("server_url"field), validating that exactly one is present - Field validation: Verifies transport-specific requirements, such as ensuring
commandis a string orserver_urlstarts withhttp://orhttps:// - Default application: Applies default values for optional parameters including
timeout_seconds,response_bytes_cap,use_tool_prefix, andlazy_connect(defined at lines 42-46) - Normalization: Returns a normalized dictionary at line 86 that the MCP client can consume
MCPClient Lifecycle and Tool Discovery
After validation, the normalized configuration is instantiated via MCPClient.from_config() in aisuite/mcp/client.py. This client automatically:
- Starts the MCP server process for stdio transport or prepares the HTTP endpoint
- Discovers available tools through the
list_tools()method - Wraps each remote tool as a callable that the LLM can invoke via the standard tool-calling protocol
The following code from aisuite/client.py illustrates how configs are transformed into callable tools:
if isinstance(tool_entry, dict) and tool_entry.get("type") == "mcp":
cfg = validate_mcp_config(tool_entry) # aisuite/mcp/config.py
mcp = MCPClient.from_config(cfg) # aisuite/mcp/client.py
tools.extend(mcp.get_callable_tools())
For guidance on choosing between the config-dict shortcut versus explicit MCPClient instantiation, see the comparison in examples/mcp_config_dict_example.py lines 56-68.
Configuration Fields Reference
Required Fields
type: Must be"mcp"(string)name: Logical identifier for the server (string, required)
stdio Transport Fields
command: Executable that runs the MCP server (e.g.,"npx")args: Argument list for the command (e.g.,["@modelcontextprotocol/server-filesystem", "/path"])env: Environment variables for the process (optional)cwd: Working directory for the process (optional)
HTTP Transport Fields
server_url: Base URL of the HTTP MCP server (e.g.,"https://mcp.example.com/v1")headers: Additional HTTP headers (optional)
Security and Performance Options
allowed_tools: Whitelist of tool names the LLM may call for security restrictionsuse_tool_prefix: Prefix tool names with<name>__to avoid collisions when using multiple serverstimeout_seconds: Maximum wait time for tool responses (default: 30 seconds)response_bytes_cap: Upper bound on response size (default: 10 MiB)lazy_connect: Defers connection until the first tool call when set toTrue
Practical Implementation Examples
Basic stdio MCP Server Configuration
The following example from examples/mcp_config_dict_example.py (lines 23-38) demonstrates connecting to a filesystem MCP server using npx:
import aisuite as ai
import os
client = ai.Client()
response = client.chat.completions.create(
model="openai:gpt-4o",
messages=[{"role": "user", "content": "List all Python files here"}],
tools=[
{
"type": "mcp",
"name": "filesystem",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
os.getcwd(),
],
}
],
max_turns=2,
)
print(response.choices[0].message.content)
Restricting Available Tools for Security
Limit which tools the LLM can access using the allowed_tools field:
{
"type": "mcp",
"name": "filesystem",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", os.getcwd()],
"allowed_tools": ["read_file"], # only allow file reads
}
Running Multiple MCP Servers with Prefixing
Prevent tool name collisions when using multiple servers:
{
"type": "mcp",
"name": "temp_dir",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", temp_dir],
"use_tool_prefix": True, # tools become temp_dir__list_directory
}
Combining MCP Servers with Native Python Functions
Mix MCP configurations with regular Python functions in the same tools list:
def get_current_time():
return "Current time: 2024-01-01 12:00:00"
response = client.chat.completions.create(
model="openai:gpt-4o",
messages=[{"role": "user", "content": "What time is it?"}],
tools=[
get_current_time, # native Python function
{ # MCP config dict
"type": "mcp",
"name": "filesystem",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", os.getcwd()],
},
],
max_turns=3,
)
Summary
- aisuite/mcp/config.py defines the
MCPConfigschema andvalidate_mcp_config()function that processes server configurations - Transport methods are mutually exclusive: use either
commandfor stdio orserver_urlfor HTTP connections - The
MCPClient.from_config()method in aisuite/mcp/client.py handles server lifecycle management and tool discovery - Configuration options include security controls (
allowed_tools), performance limits (timeout_seconds,response_bytes_cap), and multi-server support (use_tool_prefix) - Refer to examples/mcp_config_dict_example.py for complete working implementations and tests/mcp/test_e2e.py for integration test patterns
Frequently Asked Questions
What is the difference between stdio and HTTP transport in MCP configuration?
The stdio transport launches a local subprocess using the command and args fields, suitable for running local MCP servers like the filesystem example. HTTP transport connects to remote servers via the server_url field. According to the validation logic in aisuite/mcp/config.py lines 95-100, you must specify exactly one transport method, not both.
How does aisuite validate MCP server configurations?
aisuite validates configurations through the validate_mcp_config() function in aisuite/mcp/config.py. This function checks for required fields (type, name), validates transport-specific parameters, applies default values for optional settings like timeout_seconds (default 30s), and ensures URL formats are correct for HTTP transport.
Can I use multiple MCP servers simultaneously in a single request?
Yes, you can include multiple MCP configuration dictionaries in the tools list. To avoid tool name collisions between servers, enable the use_tool_prefix option, which prefixes each tool name with the server name (e.g., servername__toolname). You can also mix MCP servers with native Python functions in the same tools array.
What security options are available when integrating MCP servers?
aisuite provides the allowed_tools field to whitelist specific tools, preventing the LLM from accessing potentially dangerous operations. For HTTP transport, you can specify custom headers for authentication. Additionally, response_bytes_cap (default 10 MiB) prevents memory exhaustion from oversized responses.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →