mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-26 11:14:04 +00:00
fix mcp import
This commit is contained in:
parent
df1789902d
commit
dcc2edbd4d
2 changed files with 95 additions and 86 deletions
|
@ -1062,7 +1062,6 @@ jobs:
|
||||||
pip install jinja2
|
pip install jinja2
|
||||||
pip install "tokenizers==0.20.0"
|
pip install "tokenizers==0.20.0"
|
||||||
pip install "uvloop==0.21.0"
|
pip install "uvloop==0.21.0"
|
||||||
pip install "mcp==1.5.0"
|
|
||||||
pip install jsonschema
|
pip install jsonschema
|
||||||
- run:
|
- run:
|
||||||
name: Run tests
|
name: Run tests
|
||||||
|
|
|
@ -3,43 +3,55 @@ LiteLLM MCP Server Routes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import logging
|
||||||
from typing import Any, Dict, List, Union
|
from typing import Any, Dict, List, Union
|
||||||
|
|
||||||
from anyio import BrokenResourceError
|
from anyio import BrokenResourceError
|
||||||
from fastapi import APIRouter, HTTPException, Request
|
from fastapi import APIRouter, HTTPException, Request
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
from mcp.server import NotificationOptions, Server
|
|
||||||
from mcp.server.models import InitializationOptions
|
|
||||||
from mcp.types import EmbeddedResource as MCPEmbeddedResource
|
|
||||||
from mcp.types import ImageContent as MCPImageContent
|
|
||||||
from mcp.types import TextContent as MCPTextContent
|
|
||||||
from mcp.types import Tool as MCPTool
|
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
from litellm._logging import verbose_logger
|
from litellm._logging import verbose_logger
|
||||||
from litellm.proxy._experimental.mcp_server.tool_registry import (
|
|
||||||
global_mcp_tool_registry,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .sse_transport import SseServerTransport
|
# Check if MCP is available
|
||||||
|
# "mcp" requires python 3.10 or higher, but several litellm users use python 3.8
|
||||||
|
# We're making this conditional import to avoid breaking users who use python 3.8.
|
||||||
|
try:
|
||||||
|
import mcp
|
||||||
|
|
||||||
########################################################
|
MCP_AVAILABLE = True
|
||||||
############ Initialize the MCP Server #################
|
except ImportError as e:
|
||||||
########################################################
|
verbose_logger.debug(f"MCP module not found: {e}")
|
||||||
router = APIRouter(
|
MCP_AVAILABLE = False
|
||||||
|
|
||||||
|
|
||||||
|
if MCP_AVAILABLE:
|
||||||
|
from mcp.server import NotificationOptions, Server
|
||||||
|
from mcp.server.models import InitializationOptions
|
||||||
|
from mcp.types import EmbeddedResource as MCPEmbeddedResource
|
||||||
|
from mcp.types import ImageContent as MCPImageContent
|
||||||
|
from mcp.types import TextContent as MCPTextContent
|
||||||
|
from mcp.types import Tool as MCPTool
|
||||||
|
|
||||||
|
from .sse_transport import SseServerTransport
|
||||||
|
from .tool_registry import global_mcp_tool_registry
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
############ Initialize the MCP Server #################
|
||||||
|
########################################################
|
||||||
|
router = APIRouter(
|
||||||
prefix="/mcp",
|
prefix="/mcp",
|
||||||
tags=["mcp"],
|
tags=["mcp"],
|
||||||
)
|
)
|
||||||
server: Server = Server("litellm-mcp-server")
|
server: Server = Server("litellm-mcp-server")
|
||||||
sse: SseServerTransport = SseServerTransport("/mcp/sse/messages")
|
sse: SseServerTransport = SseServerTransport("/mcp/sse/messages")
|
||||||
|
|
||||||
########################################################
|
########################################################
|
||||||
############### MCP Server Routes #######################
|
############### MCP Server Routes #######################
|
||||||
########################################################
|
########################################################
|
||||||
|
|
||||||
|
@server.list_tools()
|
||||||
@server.list_tools()
|
async def list_tools() -> list[MCPTool]:
|
||||||
async def list_tools() -> list[MCPTool]:
|
|
||||||
"""
|
"""
|
||||||
List all available tools
|
List all available tools
|
||||||
"""
|
"""
|
||||||
|
@ -55,11 +67,10 @@ async def list_tools() -> list[MCPTool]:
|
||||||
|
|
||||||
return tools
|
return tools
|
||||||
|
|
||||||
|
@server.call_tool()
|
||||||
@server.call_tool()
|
async def handle_call_tool(
|
||||||
async def handle_call_tool(
|
|
||||||
name: str, arguments: Dict[str, Any] | None
|
name: str, arguments: Dict[str, Any] | None
|
||||||
) -> List[Union[MCPTextContent, MCPImageContent, MCPEmbeddedResource]]:
|
) -> List[Union[MCPTextContent, MCPImageContent, MCPEmbeddedResource]]:
|
||||||
"""
|
"""
|
||||||
Call a specific tool with the provided arguments
|
Call a specific tool with the provided arguments
|
||||||
"""
|
"""
|
||||||
|
@ -67,7 +78,9 @@ async def handle_call_tool(
|
||||||
if not tool:
|
if not tool:
|
||||||
raise HTTPException(status_code=404, detail=f"Tool '{name}' not found")
|
raise HTTPException(status_code=404, detail=f"Tool '{name}' not found")
|
||||||
if arguments is None:
|
if arguments is None:
|
||||||
raise HTTPException(status_code=400, detail="Request arguments are required")
|
raise HTTPException(
|
||||||
|
status_code=400, detail="Request arguments are required"
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = tool.handler(**arguments)
|
result = tool.handler(**arguments)
|
||||||
|
@ -75,9 +88,8 @@ async def handle_call_tool(
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return [MCPTextContent(text=f"Error: {str(e)}", type="text")]
|
return [MCPTextContent(text=f"Error: {str(e)}", type="text")]
|
||||||
|
|
||||||
|
@router.get("/", response_class=StreamingResponse)
|
||||||
@router.get("/", response_class=StreamingResponse)
|
async def handle_sse(request: Request):
|
||||||
async def handle_sse(request: Request):
|
|
||||||
verbose_logger.info("new incoming SSE connection established")
|
verbose_logger.info("new incoming SSE connection established")
|
||||||
async with sse.connect_sse(request) as streams:
|
async with sse.connect_sse(request) as streams:
|
||||||
try:
|
try:
|
||||||
|
@ -92,19 +104,17 @@ async def handle_sse(request: Request):
|
||||||
raise
|
raise
|
||||||
await request.close()
|
await request.close()
|
||||||
|
|
||||||
|
@router.post("/sse/messages")
|
||||||
@router.post("/sse/messages")
|
async def handle_messages(request: Request):
|
||||||
async def handle_messages(request: Request):
|
|
||||||
verbose_logger.info("incoming SSE message received")
|
verbose_logger.info("incoming SSE message received")
|
||||||
await sse.handle_post_message(request.scope, request.receive, request._send)
|
await sse.handle_post_message(request.scope, request.receive, request._send)
|
||||||
await request.close()
|
await request.close()
|
||||||
|
|
||||||
|
options = InitializationOptions(
|
||||||
options = InitializationOptions(
|
|
||||||
server_name="litellm-mcp-server",
|
server_name="litellm-mcp-server",
|
||||||
server_version="0.1.0",
|
server_version="0.1.0",
|
||||||
capabilities=server.get_capabilities(
|
capabilities=server.get_capabilities(
|
||||||
notification_options=NotificationOptions(),
|
notification_options=NotificationOptions(),
|
||||||
experimental_capabilities={},
|
experimental_capabilities={},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue