Merge pull request #987 from alpiua/fix-mcp-null-payload
fix(mcp): handle null JSON-RPC request payloads safely
This commit is contained in:
@@ -1968,6 +1968,12 @@ SUPPORTED_PROTOCOL_VERSIONS = [
|
|||||||
|
|
||||||
|
|
||||||
def handle_request(request):
|
def handle_request(request):
|
||||||
|
if not isinstance(request, dict):
|
||||||
|
return {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": None,
|
||||||
|
"error": {"code": -32600, "message": "Invalid Request"},
|
||||||
|
}
|
||||||
method = request.get("method") or ""
|
method = request.get("method") or ""
|
||||||
params = request.get("params") or {}
|
params = request.get("params") or {}
|
||||||
req_id = request.get("id")
|
req_id = request.get("id")
|
||||||
@@ -2005,6 +2011,15 @@ def handle_request(request):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
elif method == "tools/call":
|
elif method == "tools/call":
|
||||||
|
if not isinstance(params, dict) or "name" not in params:
|
||||||
|
return {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": req_id,
|
||||||
|
"error": {
|
||||||
|
"code": -32602,
|
||||||
|
"message": "Invalid params: 'name' is required for tools/call",
|
||||||
|
},
|
||||||
|
}
|
||||||
tool_name = params.get("name")
|
tool_name = params.get("name")
|
||||||
tool_args = params.get("arguments") or {}
|
tool_args = params.get("arguments") or {}
|
||||||
if tool_name not in TOOLS:
|
if tool_name not in TOOLS:
|
||||||
|
|||||||
@@ -148,6 +148,20 @@ class TestHandleRequest:
|
|||||||
)
|
)
|
||||||
assert resp["error"]["code"] == -32601
|
assert resp["error"]["code"] == -32601
|
||||||
|
|
||||||
|
def test_tools_call_missing_params(self):
|
||||||
|
from mempalace.mcp_server import handle_request
|
||||||
|
|
||||||
|
for bad_params in [None, {}, {"arguments": {}}]:
|
||||||
|
resp = handle_request(
|
||||||
|
{
|
||||||
|
"method": "tools/call",
|
||||||
|
"id": 15,
|
||||||
|
"params": bad_params,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assert resp["error"]["code"] == -32602
|
||||||
|
assert "Invalid params" in resp["error"]["message"]
|
||||||
|
|
||||||
def test_unknown_method(self):
|
def test_unknown_method(self):
|
||||||
from mempalace.mcp_server import handle_request
|
from mempalace.mcp_server import handle_request
|
||||||
|
|
||||||
@@ -190,6 +204,17 @@ class TestHandleRequest:
|
|||||||
resp = handle_request({"method": None, "id": 99, "params": {}})
|
resp = handle_request({"method": None, "id": 99, "params": {}})
|
||||||
assert resp["error"]["code"] == -32601
|
assert resp["error"]["code"] == -32601
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("payload", [None, [], "plain", 42, True])
|
||||||
|
def test_handle_request_invalid_payload_returns_jsonrpc_error(self, payload):
|
||||||
|
from mempalace.mcp_server import handle_request
|
||||||
|
|
||||||
|
resp = handle_request(payload)
|
||||||
|
assert resp == {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": None,
|
||||||
|
"error": {"code": -32600, "message": "Invalid Request"},
|
||||||
|
}
|
||||||
|
|
||||||
def test_tools_call_dispatches(self, monkeypatch, config, palace_path, seeded_kg):
|
def test_tools_call_dispatches(self, monkeypatch, config, palace_path, seeded_kg):
|
||||||
_patch_mcp_server(monkeypatch, config, seeded_kg)
|
_patch_mcp_server(monkeypatch, config, seeded_kg)
|
||||||
from mempalace.mcp_server import handle_request
|
from mempalace.mcp_server import handle_request
|
||||||
|
|||||||
Reference in New Issue
Block a user