MCP interactions involve network communication, subprocess management, and protocol negotiation. Definable provides specific exception types for each failure mode so you can handle errors precisely.
Error Hierarchy
All MCP errors inherit from MCPError:
| Exception | Reason |
|---|
MCPConnectionError | Failed to connect to server |
MCPTimeoutError | Request or connection timed out |
MCPProtocolError | Invalid JSON-RPC or protocol violation |
MCPToolNotFoundError | Requested tool does not exist |
MCPServerNotFoundError | Server name not in configuration |
MCPResourceNotFoundError | Resource URI not found |
MCPPromptNotFoundError | Prompt name not found |
Handling Connection Errors
from definable.mcp import MCPToolkit, MCPConfig, MCPServerConfig
from definable.mcp.errors import MCPConnectionError, MCPTimeoutError
config = MCPConfig(servers=[
MCPServerConfig(name="my-server", transport="stdio", command="my-mcp-server"),
])
try:
async with MCPToolkit(config=config) as toolkit:
agent = Agent(model=model, toolkits=[toolkit])
output = await agent.arun("Do something")
except MCPConnectionError as e:
print(f"Could not connect to MCP server: {e}")
except MCPTimeoutError as e:
print(f"Connection timed out: {e}")
from definable.mcp.errors import MCPToolNotFoundError
try:
result = await client.call_tool("my-server", "nonexistent_tool", {})
except MCPToolNotFoundError as e:
print(f"Tool not found: {e}")
Handling Server Not Found
from definable.mcp.errors import MCPServerNotFoundError
try:
tools = await client.list_tools("unknown-server")
except MCPServerNotFoundError as e:
print(f"Server not configured: {e}")
Automatic Reconnection
By default, MCP connections automatically reconnect on failure:
MCPServerConfig(
name="my-server",
transport="stdio",
command="my-mcp-server",
reconnect_on_failure=True, # Default
max_reconnect_attempts=3, # Default
)
Reconnection uses exponential backoff. If all attempts fail, an MCPConnectionError is raised.
Timeout Configuration
Set timeouts at the server level:
MCPServerConfig(
name="slow-server",
transport="http",
url="https://mcp.example.com/mcp",
connect_timeout=60.0, # Time to establish connection
request_timeout=120.0, # Time for each request
)
Graceful Degradation
When using multiple MCP servers, handle failures for individual servers:
config = MCPConfig(servers=[
MCPServerConfig(name="primary", transport="stdio", command="server-a"),
MCPServerConfig(name="fallback", transport="stdio", command="server-b"),
])
client = MCPClient(config)
await client.connect()
# Connect to servers individually for resilience
for server_name in ["primary", "fallback"]:
try:
await client.connect_server(server_name)
print(f"Connected to {server_name}")
except MCPConnectionError:
print(f"Failed to connect to {server_name}, skipping")
Protocol Errors
Protocol errors indicate a bug in the MCP server or an incompatible protocol version:
from definable.mcp.errors import MCPProtocolError
try:
result = await client.call_tool("server", "tool", {"arg": "value"})
except MCPProtocolError as e:
print(f"Protocol error: {e}")
# This usually means the server returned an invalid JSON-RPC response
If you encounter MCPProtocolError consistently, check that the MCP server is using a compatible version of the protocol and that the transport type matches the server’s expectations.