REST API endpoint for MCP

This commit is contained in:
Ishaan Jaff 2025-03-29 13:35:46 -07:00
parent a1ec0dd0e2
commit 1cf5cbab50
4 changed files with 100 additions and 8 deletions

View file

@ -50,6 +50,7 @@ class MCPServerManager:
MCPSSEServer(
name=server_name,
url=server_config["url"],
mcp_info=server_config.get("mcp_info", None),
)
)
verbose_logger.debug(

View file

@ -6,11 +6,15 @@ import asyncio
from typing import Any, Dict, List, Union
from anyio import BrokenResourceError
from fastapi import APIRouter, HTTPException, Request
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import StreamingResponse
from pydantic import ValidationError
from litellm._logging import verbose_logger
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.types.mcp_server.mcp_server_manager import (
ListMCPToolsRestAPIResponseObject,
)
# Check if MCP is available
# "mcp" requires python 3.10 or higher, but several litellm users use python 3.8
@ -53,9 +57,14 @@ if MCP_AVAILABLE:
########################################################
############### MCP Server Routes #######################
########################################################
@server.list_tools()
async def list_tools() -> list[MCPTool]:
"""
List all available tools
"""
return await _list_mcp_tools()
async def _list_mcp_tools() -> List[MCPTool]:
"""
List all available tools
"""
@ -95,6 +104,18 @@ if MCP_AVAILABLE:
HTTPException: If tool not found or arguments missing
"""
# Validate arguments
response = await call_mcp_tool(
name=name,
arguments=arguments,
)
return response
async def call_mcp_tool(
name: str, arguments: Dict[str, Any] | None
) -> List[Union[MCPTextContent, MCPImageContent, MCPEmbeddedResource]]:
"""
Call a specific tool with the provided arguments
"""
if arguments is None:
raise HTTPException(
status_code=400, detail="Request arguments are required"
@ -154,6 +175,63 @@ if MCP_AVAILABLE:
await sse.handle_post_message(request.scope, request.receive, request._send)
await request.close()
########################################################
############ MCP Server REST API Routes #################
########################################################
@router.get("/tools/list", dependencies=[Depends(user_api_key_auth)])
async def list_tool_rest_api() -> (
List[Dict[str, ListMCPToolsRestAPIResponseObject]]
):
"""
List all available tools with information about the server they belong to.
Example response:
Tools:
[
"zapier": {
"tools": [
{
"name": "create_zap",
"description": "Create a new zap",
"inputSchema": "tool_input_schema",
}
],
"mcp_info": {
"logo_url": "https://www.zapier.com/logo.png",
}
},
"fetch": {
"tools": [
{
"name": "fetch_data",
"description": "Fetch data from a URL",
}
],
"mcp_info": {
"logo_url": "https://www.fetch.com/logo.png",
}
}
"""
list_tools_result: List[Dict[str, ListMCPToolsRestAPIResponseObject]] = []
for server in global_mcp_server_manager.mcp_servers:
tools = await global_mcp_server_manager._get_tools_from_server(server)
list_tools_result.append(
{
server.name: ListMCPToolsRestAPIResponseObject(
tools=tools,
mcp_info=server.mcp_info,
)
}
)
return list_tools_result
@router.post("/tools/call", dependencies=[Depends(user_api_key_auth)])
async def call_tool_rest_api(name: str, arguments: Dict[str, Any]):
return await call_mcp_tool(
name=name,
arguments=arguments,
)
options = InitializationOptions(
server_name="litellm-mcp-server",
server_version="0.1.0",

View file

@ -5,9 +5,10 @@ model_list:
mcp_servers:
{
"Zapier MCP": {
"url": "os.environ/ZAPIER_MCP_SERVER_URL",
},
"Zapier MCP": {
"url": "os.environ/ZAPIER_MCP_SERVER_URL",
"mcp_info": {
"logo_url": "https://www.zapier.com/logo.png",
}
}
}
}

View file

@ -1,6 +1,7 @@
from typing import Optional
from typing import Any, Dict, List, Optional
from mcp import ClientSession
from mcp.types import Tool as MCPTool
from pydantic import BaseModel, ConfigDict
@ -8,4 +9,15 @@ class MCPSSEServer(BaseModel):
name: str
url: str
client_session: Optional[ClientSession] = None
mcp_info: Optional[Dict[str, Any]] = None
model_config = ConfigDict(arbitrary_types_allowed=True)
class ListMCPToolsRestAPIResponseObject(BaseModel):
"""
Object returned by the /tools/list REST API route.
"""
tools: List[MCPTool]
mcp_info: Optional[Dict[str, Any]] = None
model_config = ConfigDict(arbitrary_types_allowed=True)