Overview
The Model Context Protocol (MCP) standardizes how applications provide context to LLMs. LiteLLM provides a client implementation for connecting to MCP servers and using their tools, prompts, and resources.What is MCP?
MCP enables:- Tools: External functions that LLMs can call (e.g., database queries, API calls)
- Prompts: Pre-configured prompt templates with variables
- Resources: Context data like files, database records, or API responses
Supported Transports
- HTTP: Connect to HTTP-based MCP servers
- SSE: Server-Sent Events for real-time updates
- Stdio: Process-based communication
Installation
pip install litellm mcp
Quick Start
1
Create MCP Client
Initialize a client for your MCP server:
from litellm.experimental_mcp_client import MCPClient
# HTTP transport
client = MCPClient(
server_url="http://localhost:8080",
transport_type="http",
auth_type="bearer_token",
auth_value="your-token"
)
2
List Available Tools
Discover tools provided by the server:
from litellm.experimental_mcp_client import load_mcp_tools
async def list_tools():
async def operation(session):
return await load_mcp_tools(session, format="openai")
tools = await client.run_with_session(operation)
for tool in tools:
print(f"Tool: {tool['function']['name']}")
print(f"Description: {tool['function']['description']}")
3
Call a Tool
Execute tools with parameters:
from mcp.types import CallToolRequestParams
async def call_tool():
async def operation(session):
from litellm.experimental_mcp_client import call_mcp_tool
request = CallToolRequestParams(
name="search_database",
arguments={"query": "SELECT * FROM users"}
)
return await call_mcp_tool(session, request)
result = await client.run_with_session(operation)
print(result)
Tool Integration
Load MCP Tools for LLM Use
Convert MCP tools to OpenAI-compatible format:from litellm.experimental_mcp_client import MCPClient, load_mcp_tools
import litellm
# Initialize MCP client
mcp_client = MCPClient(
server_url="http://localhost:8080",
transport_type="http"
)
async def get_tools_for_llm():
async def operation(session):
# Get tools in OpenAI format
return await load_mcp_tools(session, format="openai")
tools = await mcp_client.run_with_session(operation)
return tools
# Use with LiteLLM
async def main():
tools = await get_tools_for_llm()
response = await litellm.acompletion(
model="gpt-4",
messages=[{"role": "user", "content": "Search for active users"}],
tools=tools
)
print(response.choices[0].message)
Execute Tool Calls
Handle tool calls from LLM responses:from litellm.experimental_mcp_client import call_openai_tool
async def handle_tool_calls(response, mcp_client):
message = response.choices[0].message
if message.tool_calls:
for tool_call in message.tool_calls:
# Execute via MCP
async def operation(session):
return await call_openai_tool(session, tool_call)
result = await mcp_client.run_with_session(operation)
print(f"Tool: {tool_call.function.name}")
print(f"Result: {result}")
Transport Types
from litellm.experimental_mcp_client import MCPClient
client = MCPClient(
server_url="https://mcp-server.example.com",
transport_type="http",
auth_type="bearer_token",
auth_value="your-api-key",
timeout=30.0
)
client = MCPClient(
server_url="https://mcp-server.example.com/sse",
transport_type="sse",
auth_type="api_key",
auth_value="your-api-key",
timeout=60.0
)
from litellm.types.mcp import MCPStdioConfig
stdio_config = MCPStdioConfig(
command="npx",
args=["-y", "@modelcontextprotocol/server-memory"],
env={"NODE_ENV": "production"}
)
client = MCPClient(
transport_type="stdio",
stdio_config=stdio_config
)
Authentication
Bearer Token
client = MCPClient(
server_url="https://api.example.com",
auth_type="bearer_token",
auth_value="your-bearer-token"
)
Basic Auth
# Provide username:password format
client = MCPClient(
server_url="https://api.example.com",
auth_type="basic",
auth_value="username:password" # Automatically base64 encoded
)
API Key
client = MCPClient(
server_url="https://api.example.com",
auth_type="api_key",
auth_value="your-api-key" # Sent as X-API-Key header
)
Custom Headers
# For custom authentication schemes
client = MCPClient(
server_url="https://api.example.com",
auth_type="authorization",
auth_value="Custom scheme-value"
)
# Or use dictionary for multiple headers
client = MCPClient(
server_url="https://api.example.com",
auth_value={
"X-API-Key": "key123",
"X-Custom-Header": "value"
}
)
Working with Prompts
List Available Prompts
async def list_prompts(client):
async def operation(session):
return await session.list_prompts()
prompts = await client.run_with_session(operation)
for prompt in prompts.prompts:
print(f"Name: {prompt.name}")
print(f"Description: {prompt.description}")
print(f"Arguments: {prompt.arguments}")
Get a Prompt
from mcp.types import GetPromptRequestParams
async def get_prompt(client, prompt_name, variables):
async def operation(session):
request = GetPromptRequestParams(
name=prompt_name,
arguments=variables
)
return await session.get_prompt(
name=request.name,
arguments=request.arguments
)
result = await client.run_with_session(operation)
return result
# Use the prompt
prompt_result = await get_prompt(
client,
"code_review",
{"language": "python", "file": "main.py"}
)
print(prompt_result.description)
for message in prompt_result.messages:
print(message)
Working with Resources
List Resources
async def list_resources(client):
resources = await client.list_resources()
for resource in resources:
print(f"URI: {resource.uri}")
print(f"Name: {resource.name}")
print(f"Type: {resource.mimeType}")
Read a Resource
from pydantic import AnyUrl
async def read_resource(client, uri: str):
result = await client.read_resource(AnyUrl(uri))
for content in result.contents:
if content.type == "text":
print(content.text)
elif content.type == "blob":
print(f"Binary data: {len(content.blob)} bytes")
# Example
await read_resource(client, "file:///path/to/document.txt")
Resource Templates
async def list_templates(client):
templates = await client.list_resource_templates()
for template in templates:
print(f"URI Template: {template.uriTemplate}")
print(f"Name: {template.name}")
print(f"Description: {template.description}")
# Use a template
# Template: "file:///{path}"
await read_resource(client, "file:///documents/report.pdf")
Advanced Features
Tool Transformation
Manually transform between MCP and OpenAI formats:MCP to OpenAI Tool Format
MCP to OpenAI Tool Format
from litellm.experimental_mcp_client.tools import (
transform_mcp_tool_to_openai_tool
)
from mcp.types import Tool as MCPTool
mcp_tool = MCPTool(
name="search",
description="Search the database",
inputSchema={
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer"}
},
"required": ["query"]
}
)
openai_tool = transform_mcp_tool_to_openai_tool(mcp_tool)
print(openai_tool)
OpenAI to MCP Request Format
OpenAI to MCP Request Format
from litellm.experimental_mcp_client.tools import (
transform_openai_tool_call_request_to_mcp_tool_call_request
)
# From LLM response
tool_call = response.choices[0].message.tool_calls[0]
# Convert to MCP format
mcp_request = transform_openai_tool_call_request_to_mcp_tool_call_request(
openai_tool=tool_call
)
print(f"Tool: {mcp_request.name}")
print(f"Arguments: {mcp_request.arguments}")
SSL Configuration
import ssl
# Custom SSL context
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
client = MCPClient(
server_url="https://localhost:8443",
ssl_verify=ssl_context
)
# Or use CA bundle path
client = MCPClient(
server_url="https://api.example.com",
ssl_verify="/path/to/ca-bundle.crt"
)
# Disable SSL verification (not recommended)
client = MCPClient(
server_url="https://api.example.com",
ssl_verify=False
)
Progress Callbacks
Monitor long-running tool executions:async def my_progress_callback(progress: float, total: float | None):
percentage = (progress / total * 100) if total else 0
print(f"Progress: {percentage:.1f}%")
async def call_with_progress(client):
request = CallToolRequestParams(
name="long_running_task",
arguments={"data": "large_dataset"}
)
result = await client.call_tool(
call_tool_request_params=request,
host_progress_callback=my_progress_callback
)
return result
Complete Example
Full LLM + MCP Integration
Full LLM + MCP Integration
import asyncio
from litellm.experimental_mcp_client import (
MCPClient,
load_mcp_tools,
call_openai_tool
)
import litellm
async def main():
# Initialize MCP client
mcp_client = MCPClient(
server_url="http://localhost:8080",
transport_type="http",
auth_type="api_key",
auth_value="your-api-key"
)
# Load available tools
async def get_tools(session):
return await load_mcp_tools(session, format="openai")
tools = await mcp_client.run_with_session(get_tools)
print(f"Loaded {len(tools)} tools")
# Make LLM request with tools
response = await litellm.acompletion(
model="gpt-4",
messages=[
{"role": "user", "content": "Find all active users and export to CSV"}
],
tools=tools
)
message = response.choices[0].message
# Execute tool calls
if message.tool_calls:
tool_results = []
for tool_call in message.tool_calls:
print(f"Executing: {tool_call.function.name}")
async def execute(session):
return await call_openai_tool(session, tool_call)
result = await mcp_client.run_with_session(execute)
tool_results.append(result)
# Continue conversation with results
messages = [
{"role": "user", "content": "Find all active users and export to CSV"},
message,
*[
{
"role": "tool",
"tool_call_id": tc.id,
"content": str(result)
}
for tc, result in zip(message.tool_calls, tool_results)
]
]
final_response = await litellm.acompletion(
model="gpt-4",
messages=messages
)
print(final_response.choices[0].message.content)
if __name__ == "__main__":
asyncio.run(main())
Error Handling
import asyncio
from litellm.experimental_mcp_client import MCPClient
async def robust_mcp_call():
client = MCPClient(
server_url="http://localhost:8080",
timeout=30.0
)
try:
tools = await client.list_tools()
print(f"Found {len(tools)} tools")
except asyncio.CancelledError:
print("Operation cancelled")
raise
except asyncio.TimeoutError:
print("MCP server timeout")
return []
except Exception as e:
print(f"MCP error: {type(e).__name__}: {e}")
# Returns empty list on error for graceful degradation
return []
Best Practices
Session Management
Session Management
Always use
run_with_session to ensure proper cleanup:# Good: Automatic cleanup
async def operation(session):
return await session.list_tools()
result = await client.run_with_session(operation)
# Bad: Manual session management (error-prone)
# Don't do this unless you have a specific reason
Tool Validation
Tool Validation
Validate tool schemas before using with LLMs:
async def get_validated_tools(client):
async def operation(session):
tools = await load_mcp_tools(session, format="openai")
# Validate each tool has required fields
validated = []
for tool in tools:
func = tool.get("function", {})
if func.get("name") and func.get("parameters"):
validated.append(tool)
return validated
return await client.run_with_session(operation)
Error Recovery
Error Recovery
Implement graceful degradation:
async def get_tools_with_fallback(client):
try:
async def operation(session):
return await load_mcp_tools(session, format="openai")
return await client.run_with_session(operation)
except Exception as e:
print(f"MCP unavailable: {e}")
# Return empty list or fallback tools
return []
Reference
Source Code
- MCP Client:
litellm/experimental_mcp_client/client.py:53 - Tool utilities:
litellm/experimental_mcp_client/tools.py:18