-
Notifications
You must be signed in to change notification settings - Fork 270
Open
Labels
bugSomething isn't workingSomething isn't workinghelp wantedExtra attention is neededExtra attention is neededmcp
Description
π Bug
MCP tools/call requests consistently fail with endpoint_handler() missing 1 required positional argument: 'request' while tools/list works perfectly. This makes MCP integration completely unusable.
Environment
- LitServe Version: 0.2.12
- MCP Version: 1.9.4
- Python Version: 3.12.3
- Operating System: Linux 5.15.167.4-microsoft-standard-WSL2 (WSL2)
- Platform: x86_64
Bug Details
What Works β
tools/listrequests work perfectly- Direct REST API calls to
/predictwork fine - Tool discovery and schema generation work correctly
What's Broken β
- All
tools/callrequests fail with identical error - Affects any LitAPI with MCP enabled
- 100% failure rate across all tested configurations
Error Message
LitServer._register_api_endpoints.<locals>.endpoint_handler() missing 1 required positional argument: 'request'
Root Cause Analysis
The bug is in /litserve/mcp.py at line 461:
# This line fails:
return await _call_handler(handler, **arguments)The issue:
handleris the FastAPIendpoint_handlerfunction which expects arequestparameter_call_handlertries to bind MCP arguments as kwargs to this function- FastAPI endpoint handlers require a positional
requestobject, not kwargs - The binding fails because no
requestargument is provided
The FastAPI endpoint signature is:
async def endpoint_handler(request: request_type) -> response_type:
return await handler.handle_request(request, request_type)Minimal Reproduction Case
1. Create Simple LitAPI with MCP
# minimal_mcp_repro.py
import litserve as ls
from litserve.mcp import MCP
from pydantic import BaseModel
class SimpleMCPAPI(ls.LitAPI):
def setup(self, device):
pass
def decode_request(self, request):
if isinstance(request, dict):
return request
return request.dict() if hasattr(request, 'dict') else {"message": str(request)}
def predict(self, inputs):
return {"response": f"Received: {inputs.get('message', 'unknown')}"}
def encode_response(self, output):
return output
if __name__ == "__main__":
api = SimpleMCPAPI(
mcp=MCP(
name="simple_test",
description="Simple test API",
input_schema={
"type": "object",
"properties": {
"message": {"type": "string"}
},
"required": ["message"]
}
)
)
server = ls.LitServer(api)
server.run(port=8000)2. Test MCP Endpoints
# test_mcp_bug.py
import requests
import json
def test_mcp_bug():
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream"
}
# This works β
tools_list = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
# This fails β
tools_call = {
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "simple_test",
"arguments": {"message": "test"}
}
}
print("Testing tools/list...")
response = requests.post("http://localhost:8000/mcp/", json=tools_list, headers=headers)
print(f"Status: {response.status_code}")
if response.status_code == 200:
print("β
tools/list works")
else:
print(f"β tools/list failed: {response.text}")
print("\nTesting tools/call...")
response = requests.post("http://localhost:8000/mcp/", json=tools_call, headers=headers)
print(f"Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
if result.get('result', {}).get('isError'):
print(f"β tools/call failed: {result['result']['content'][0]['text']}")
else:
print("β
tools/call works")
else:
print(f"β tools/call HTTP error: {response.text}")
if __name__ == "__main__":
test_mcp_bug()3. Run Reproduction
# Terminal 1: Start server
python minimal_mcp_repro.py
# Terminal 2: Test bug
python test_mcp_bug.pyExpected Output:
Testing tools/list...
Status: 200
β
tools/list works
Testing tools/call...
Status: 200
β tools/call failed: LitServer._register_api_endpoints.<locals>.endpoint_handler() missing 1 required positional argument: 'request'
Comprehensive Testing Evidence
We tested 11 different configurations:
- 4 different header combinations (standard, event-stream only, with session, explicit streaming)
- 3 different payload complexities
- 5 different endpoint paths
- All streaming formats and HTTP configurations
Additional Notes
- The bug appears to be in the design of how MCP integration calls FastAPI endpoints
tools/listworks because it doesn't go through the same code path- Direct REST API calls work fine, proving the LitAPI implementation is correct
- The error is consistent across all Python versions, operating systems, and configurations tested
Copilot
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workinghelp wantedExtra attention is neededExtra attention is neededmcp