MCP (Model Context Protocol)
The mcp module defines configuration and execution classes for tool use via MCP (Model Context Protocol).
Configuration Classes
MCPProvider configures remote MCP servers via SSE transport. LocalStdioMCPProvider configures local MCP servers as subprocesses via stdio transport. ToolConfig defines which tools are available for LLM columns and how they are constrained.
For user-facing guides, see:
- MCP Providers - Configure local or remote MCP providers
- Tool Configs - Define tool permissions and limits
- Enabling Tools - Use tools in LLM columns
- Traces - Capture full conversation history
Internal Architecture
Parallel Structure
| Model Layer | MCP Layer | Purpose |
|---|---|---|
ModelProviderRegistry |
MCPProviderRegistry |
Holds provider configurations |
ModelRegistry |
MCPRegistry |
Manages configs by alias, lazy facade creation |
ModelFacade |
MCPFacade |
Lightweight facade scoped to specific config |
ModelConfig.alias |
ToolConfig.tool_alias |
Alias for referencing in column configs |
MCPProviderRegistry
Holds MCP provider configurations. Can be empty (MCP is optional). Created first during resource initialization.
MCPRegistry
The central registry for tool configurations:
- Holds
ToolConfiginstances bytool_alias - Lazily creates
MCPFacadeinstances viaget_mcp(tool_alias) - Manages shared connection pool and tool cache across all facades
- Validates that tool configs reference valid providers
MCPFacade
A lightweight facade scoped to a specific ToolConfig. Key methods:
| Method | Description |
|---|---|
tool_call_count(response) |
Count tool calls in a completion response |
has_tool_calls(response) |
Check if response contains tool calls |
get_tool_schemas() |
Get OpenAI-format tool schemas for this config |
process_completion_response(response) |
Execute tool calls and return messages |
refuse_completion_response(response) |
Refuse tool calls gracefully (budget exhaustion) |
Properties: tool_alias, providers, max_tool_call_turns, allow_tools, timeout_sec
I/O Layer (mcp/io.py)
The io.py module provides low-level MCP communication with performance optimizations:
Single event loop architecture: All MCP operations funnel through a dedicated background daemon thread running an asyncio event loop. This allows:
- Efficient concurrent I/O without per-thread event loop overhead
- Natural session sharing across all worker threads
- Clean async implementation for parallel tool calls
Session pooling: MCP sessions are created lazily and kept alive for the program's duration:
- One session per provider (keyed by serialized config)
- No per-call connection/handshake overhead
- Graceful cleanup on program exit via
atexithandler
Request coalescing:
The list_tools operation uses request coalescing to prevent thundering herd:
- When multiple workers request tools from the same provider simultaneously
- Only one request is made; others wait for the cached result
- Uses asyncio.Lock per provider key
Parallel tool execution:
The call_tools_parallel() function executes multiple tool calls concurrently via asyncio.gather(). This is used by MCPFacade when the model returns parallel tool calls in a single response.
Integration with ModelFacade.generate()
The ModelFacade.generate() method accepts an optional tool_alias parameter:
output, messages = model_facade.generate(
prompt="Search and answer...",
parser=my_parser,
tool_alias="my-tools", # Enables tool calling for this generation
)
When tool_alias is provided:
ModelFacadelooks up theMCPFacadefromMCPRegistry- Tool schemas are fetched and passed to the LLM
- After each completion,
MCPFacadeprocesses tool calls - Turn counting tracks iterations; refusal kicks in when budget exhausted
- Messages (including tool results) are returned for trace capture
Config Module
Classes:
| Name | Description |
|---|---|
LocalStdioMCPProvider |
Configuration for launching a local MCP server via stdio transport. |
MCPProvider |
Configuration for a remote MCP server connection. |
ToolConfig |
Configuration for permitting MCP tools on an LLM column. |
LocalStdioMCPProvider
Bases: ConfigBase
Configuration for launching a local MCP server via stdio transport.
LocalStdioMCPProvider is used to launch MCP servers as subprocesses using stdio for communication. For connecting to remote/pre-existing MCP servers, use MCPProvider instead.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Unique name used to reference this MCP provider. |
command |
str
|
Executable to launch the MCP server via stdio transport. |
args |
list[str]
|
Arguments passed to the MCP server executable. Defaults to []. |
env |
dict[str, str]
|
Environment variables passed to the MCP server subprocess. Defaults to {}. |
provider_type |
Literal['stdio']
|
Transport type discriminator, always "stdio". |
Examples:
Stdio (subprocess) transport:
>>> LocalStdioMCPProvider(
... name="demo-mcp",
... command="python",
... args=["-m", "data_designer_e2e_tests.mcp_demo_server"],
... env={"PYTHONPATH": "/path/to/project"},
... )
MCPProvider
Bases: ConfigBase
Configuration for a remote MCP server connection.
MCPProvider is used to connect to pre-existing MCP servers via SSE (Server-Sent Events) transport. For local subprocess-based MCP servers, use LocalStdioMCPProvider instead.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Unique name used to reference this MCP provider. |
endpoint |
str
|
SSE endpoint URL for connecting to the remote MCP server. |
api_key |
str | None
|
Optional API key for authentication. Defaults to None. |
provider_type |
Literal['sse']
|
Transport type discriminator, always "sse". |
Examples:
Remote SSE transport:
>>> MCPProvider(
... name="remote-mcp",
... endpoint="http://localhost:8080/sse",
... api_key="your-api-key",
... )
ToolConfig
Bases: ConfigBase
Configuration for permitting MCP tools on an LLM column.
ToolConfig defines which tools are available for use during LLM generation. It references one or more MCP providers by name and can optionally restrict which tools from those providers are permitted.
Attributes:
| Name | Type | Description |
|---|---|---|
tool_alias |
str
|
User-defined alias to reference this tool configuration in column configs. |
providers |
list[str]
|
Names of the MCP providers to use for tool calls. Tools can be drawn from multiple providers. |
allow_tools |
list[str] | None
|
Optional allowlist of tool names that restricts which tools are permitted. If None, all tools from the specified providers are allowed. Defaults to None. |
max_tool_call_turns |
int
|
Maximum number of tool-calling turns permitted in a single generation. A turn is one iteration where the LLM requests tool calls. With parallel tool calling, a single turn may execute multiple tools simultaneously. Defaults to 5. |
timeout_sec |
float | None
|
Timeout in seconds for MCP tool calls. Defaults to None (no timeout). |
Examples:
>>> ToolConfig(
... tool_alias="search-tools",
... providers=["doc-search-mcp", "web-search-mcp"],
... allow_tools=["search_docs", "list_docs"],
... max_tool_call_turns=10,
... timeout_sec=30.0,
... )