openhands/sdk/mcp/
Core Responsibilities
The MCP Integration system has four primary responsibilities:- MCP Client Management - Connect to and communicate with MCP servers
- Tool Discovery - Enumerate available tools from MCP servers
- Schema Adaptation - Convert MCP tool schemas to SDK tool definitions
- Execution Bridge - Execute MCP tool calls from agent actions
Architecture
Key Components
MCP Client
Sync/Async Bridge
The SDK’sMCPClient extends FastMCP’s async client with synchronous wrappers:
Bridge Pattern:
- Problem: MCP protocol is async, but agent tools run synchronously
- Solution: Background event loop that executes async code from sync contexts
- Benefit: Agents use MCP tools without async/await in tool definitions
- Lifecycle Management:
__enter__/__exit__for context manager - Timeout Support: Configurable timeouts for MCP operations
- Error Handling: Wraps MCP errors in observations
- Connection Reuse: Tools share their connected MCP client
MCP Server Configuration
MCP servers are configured using the FastMCP format:- command: Executable to spawn (e.g.,
uvx,npx,node) - args: Arguments to pass to command
- env: Environment variables (optional)
Tool Discovery and Conversion
Discovery Flow
Discovery Steps:- Connect: Launch a stdio server or connect to a configured HTTP server
- List Tools: Call
tools/listMCP endpoint - Parse Schemas: Extract tool names, descriptions, parameters
- Generate Models: Create Pydantic models from input schemas for argument validation
- Create Definitions: Wrap in
ToolDefinitionobjects - Register: Add to agent’s tool registry
Schema Conversion
MCPToolDefinition keeps the original MCP tool metadata and input schema. The
LLM-facing schema is built from that input schema, preserving nested properties.
A separate Pydantic model derived from Schema validates the arguments.
MCPToolAction is a wrapper with a data dictionary. Its fields do not change for
each discovered tool. action_from_arguments() validates the arguments, removes
null values and internal fields, and stores the sanitized result in data.
The definition validates action.data again before execution.
For a discovered fetch_url tool whose input schema accepts a string url and a
numeric timeout, argument conversion looks like this:
MCPToolDefinition
for schema generation and argument validation.
Tool Execution
Execution Flow
Execution Steps:- Action Creation: LLM generates tool call, parsed into
MCPToolAction - Executor Lookup: Find
MCPToolExecutorfor tool name - Format Conversion: Read the argument dictionary using
action.to_mcp_arguments() - MCP Call: Execute
call_toolvia MCP client - Result Parsing: Convert text and image blocks; log and skip unsupported blocks, including resources
- Observation Creation: Wrap in
MCPToolObservation - Error Handling: Catch exceptions, return error observations
MCPToolExecutor
Executors bridge SDK actions to MCP calls: Executor Responsibilities:- Client Management: Hold reference to MCP client
- Tool Identification: Know which MCP tool to call
- Argument Conversion: Forward the action’s
datadictionary as MCP arguments - Result Handling: Parse MCP responses
- Error Recovery: Handle connection errors, timeouts, server failures
MCP Tool Lifecycle
From Configuration to Execution
Lifecycle Phases:MCP Annotations
MCP tool annotations are copied into the SDK’sToolAnnotations model:
When
readOnlyHint is true, the MCP schema adapter omits the additional
security_risk prediction field from the LLM-facing schema. These annotations
are hints, not enforcement guarantees. destructiveHint does not by itself
require confirmation: confirmation depends on the configured security analyzer
and confirmation policy. See Security.
The SDK’s ToolAnnotations model does not define progressEnabled.
Component Relationships
How MCP Integrates
Relationship Characteristics:- Skills → MCP: Repository skills can embed MCP configurations
- MCP → Tools: MCP tools registered alongside native tools
- Agent → Tools: Agents use MCP tools like any other tool
- MCP → Security: Read-only hints affect risk-prediction schema generation; the configured policy governs confirmation
- Transparent Integration: Agent doesn’t distinguish MCP from native tools
Design Rationale
Async Bridge Pattern: MCP protocol requires async, but synchronous tool execution simplifies agent implementation. Background event loop bridges the gap without exposing async complexity to tool users. Dynamic Model Generation: Creating Pydantic models at runtime from MCP schemas enables type-safe tool calls without manual model definitions. This supports arbitrary MCP servers without SDK code changes. Unified Tool Interface: Wrapping MCP tools inToolDefinition makes them indistinguishable from native tools. Agents use the same interface regardless of tool source.
FastMCP Foundation: Building on FastMCP (MCP SDK for Python) provides battle-tested client implementation, protocol compliance, and ongoing updates as MCP evolves.
Annotation Support: MCP hints are preserved as tool metadata. Read-only hints affect risk-prediction schema generation, while confirmation is controlled by the configured policy.
Lifecycle Management: Automatic spawn/cleanup of MCP servers in conversation lifecycle ensures resources are properly managed without manual bookkeeping.
See Also
- Tool System - How MCP tools integrate with tool framework
- Skill Architecture - Embedding MCP configs in repository skills
- Security - How MCP annotations inform risk assessment
- MCP Guide - Using MCP tools in applications
- FastMCP Documentation - Underlying MCP client library

