Skip to content

Commit d626174

Browse files
committed
types: Setting default value for jsonrpc
1 parent 07ae8c0 commit d626174

File tree

13 files changed

+32
-51
lines changed

13 files changed

+32
-51
lines changed

src/mcp/client/streamable_http.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,6 @@ async def _send_session_terminated_error(
356356
) -> None:
357357
"""Send a session terminated error response."""
358358
jsonrpc_error = JSONRPCError(
359-
jsonrpc="2.0",
360359
id=request_id,
361360
error=ErrorData(code=32600, message="Session terminated"),
362361
)

src/mcp/server/streamable_http.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ def _create_error_response(
195195

196196
# Return a properly formatted JSON error response
197197
error_response = JSONRPCError(
198-
jsonrpc="2.0",
199198
id="server-error", # We don't have a request ID for general errors
200199
error=ErrorData(
201200
code=error_code,
@@ -872,7 +871,7 @@ async def message_router():
872871
self._request_streams.pop(request_stream_id, None)
873872
else:
874873
logging.debug(
875-
f"""Request stream {request_stream_id} not found
874+
f"""Request stream {request_stream_id} not found
876875
for message. Still processing message as the client
877876
might reconnect and replay."""
878877
)

src/mcp/shared/session.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,6 @@ async def send_request(
253253

254254
try:
255255
jsonrpc_request = JSONRPCRequest(
256-
jsonrpc="2.0",
257256
id=request_id,
258257
**request_data,
259258
)
@@ -305,7 +304,6 @@ async def send_notification(
305304
# Some transport implementations may need to set the related_request_id
306305
# to attribute to the notifications to the request that triggered them.
307306
jsonrpc_notification = JSONRPCNotification(
308-
jsonrpc="2.0",
309307
**notification.model_dump(by_alias=True, mode="json", exclude_none=True),
310308
)
311309
session_message = SessionMessage(
@@ -316,12 +314,11 @@ async def send_notification(
316314

317315
async def _send_response(self, request_id: RequestId, response: SendResultT | ErrorData) -> None:
318316
if isinstance(response, ErrorData):
319-
jsonrpc_error = JSONRPCError(jsonrpc="2.0", id=request_id, error=response)
317+
jsonrpc_error = JSONRPCError(id=request_id, error=response)
320318
session_message = SessionMessage(message=JSONRPCMessage(jsonrpc_error))
321319
await self._write_stream.send(session_message)
322320
else:
323321
jsonrpc_response = JSONRPCResponse(
324-
jsonrpc="2.0",
325322
id=request_id,
326323
result=response.model_dump(by_alias=True, mode="json", exclude_none=True),
327324
)
@@ -363,7 +360,6 @@ async def _receive_loop(self) -> None:
363360
logging.warning(f"Failed to validate request: {e}")
364361
logging.debug(f"Message that failed validation: {message.message.root}")
365362
error_response = JSONRPCError(
366-
jsonrpc="2.0",
367363
id=message.message.root.id,
368364
error=ErrorData(
369365
code=INVALID_PARAMS,
@@ -428,7 +424,7 @@ async def _receive_loop(self) -> None:
428424
for id, stream in self._response_streams.items():
429425
error = ErrorData(code=CONNECTION_CLOSED, message="Connection closed")
430426
try:
431-
await stream.send(JSONRPCError(jsonrpc="2.0", id=id, error=error))
427+
await stream.send(JSONRPCError(id=id, error=error))
432428
await stream.aclose()
433429
except Exception:
434430
# Stream might already be closed

src/mcp/types.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@
3333
"""
3434
DEFAULT_NEGOTIATED_VERSION = "2025-03-26"
3535

36+
"""
37+
The JSON-RPC version (fixed at "2.0") to use for MCP messages.
38+
"""
39+
JSONRPCVersionType: TypeAlias = Literal["2.0"]
40+
JSON_RPC_VERSION: JSONRPCVersionType = "2.0"
41+
3642
ProgressToken = str | int
3743
Cursor = str
3844
Role = Literal["user", "assistant"]
@@ -124,7 +130,7 @@ class PaginatedResult(Result):
124130
class JSONRPCRequest(Request[dict[str, Any] | None, str]):
125131
"""A request that expects a response."""
126132

127-
jsonrpc: Literal["2.0"]
133+
jsonrpc: JSONRPCVersionType = JSON_RPC_VERSION
128134
id: RequestId
129135
method: str
130136
params: dict[str, Any] | None = None
@@ -133,14 +139,14 @@ class JSONRPCRequest(Request[dict[str, Any] | None, str]):
133139
class JSONRPCNotification(Notification[dict[str, Any] | None, str]):
134140
"""A notification which does not expect a response."""
135141

136-
jsonrpc: Literal["2.0"]
142+
jsonrpc: JSONRPCVersionType = JSON_RPC_VERSION
137143
params: dict[str, Any] | None = None
138144

139145

140146
class JSONRPCResponse(BaseModel):
141147
"""A successful (non-error) response to a request."""
142148

143-
jsonrpc: Literal["2.0"]
149+
jsonrpc: JSONRPCVersionType = JSON_RPC_VERSION
144150
id: RequestId
145151
result: dict[str, Any]
146152
model_config = ConfigDict(extra="allow")
@@ -182,7 +188,7 @@ class ErrorData(BaseModel):
182188
class JSONRPCError(BaseModel):
183189
"""A response to a request that indicates an error occurred."""
184190

185-
jsonrpc: Literal["2.0"]
191+
jsonrpc: JSONRPCVersionType = JSON_RPC_VERSION
186192
id: str | int
187193
error: ErrorData
188194
model_config = ConfigDict(extra="allow")

tests/client/test_session.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ async def mock_server():
6565
SessionMessage(
6666
JSONRPCMessage(
6767
JSONRPCResponse(
68-
jsonrpc="2.0",
6968
id=jsonrpc_request.root.id,
7069
result=result.model_dump(by_alias=True, mode="json", exclude_none=True),
7170
)
@@ -146,7 +145,6 @@ async def mock_server():
146145
SessionMessage(
147146
JSONRPCMessage(
148147
JSONRPCResponse(
149-
jsonrpc="2.0",
150148
id=jsonrpc_request.root.id,
151149
result=result.model_dump(by_alias=True, mode="json", exclude_none=True),
152150
)
@@ -207,7 +205,6 @@ async def mock_server():
207205
SessionMessage(
208206
JSONRPCMessage(
209207
JSONRPCResponse(
210-
jsonrpc="2.0",
211208
id=jsonrpc_request.root.id,
212209
result=result.model_dump(by_alias=True, mode="json", exclude_none=True),
213210
)
@@ -268,7 +265,6 @@ async def mock_server():
268265
SessionMessage(
269266
JSONRPCMessage(
270267
JSONRPCResponse(
271-
jsonrpc="2.0",
272268
id=jsonrpc_request.root.id,
273269
result=result.model_dump(by_alias=True, mode="json", exclude_none=True),
274270
)
@@ -327,7 +323,6 @@ async def mock_server():
327323
SessionMessage(
328324
JSONRPCMessage(
329325
JSONRPCResponse(
330-
jsonrpc="2.0",
331326
id=jsonrpc_request.root.id,
332327
result=result.model_dump(by_alias=True, mode="json", exclude_none=True),
333328
)
@@ -386,7 +381,6 @@ async def mock_server():
386381
SessionMessage(
387382
JSONRPCMessage(
388383
JSONRPCResponse(
389-
jsonrpc="2.0",
390384
id=jsonrpc_request.root.id,
391385
result=result.model_dump(by_alias=True, mode="json", exclude_none=True),
392386
)
@@ -464,7 +458,6 @@ async def mock_server():
464458
SessionMessage(
465459
JSONRPCMessage(
466460
JSONRPCResponse(
467-
jsonrpc="2.0",
468461
id=jsonrpc_request.root.id,
469462
result=result.model_dump(by_alias=True, mode="json", exclude_none=True),
470463
)

tests/client/test_stdio.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ async def test_stdio_client():
4141
async with stdio_client(server_parameters) as (read_stream, write_stream):
4242
# Test sending and receiving messages
4343
messages = [
44-
JSONRPCMessage(root=JSONRPCRequest(jsonrpc="2.0", id=1, method="ping")),
45-
JSONRPCMessage(root=JSONRPCResponse(jsonrpc="2.0", id=2, result={})),
44+
JSONRPCMessage(root=JSONRPCRequest(id=1, method="ping")),
45+
JSONRPCMessage(root=JSONRPCResponse(id=2, result={})),
4646
]
4747

4848
async with write_stream:
@@ -61,8 +61,8 @@ async def test_stdio_client():
6161
break
6262

6363
assert len(read_messages) == 2
64-
assert read_messages[0] == JSONRPCMessage(root=JSONRPCRequest(jsonrpc="2.0", id=1, method="ping"))
65-
assert read_messages[1] == JSONRPCMessage(root=JSONRPCResponse(jsonrpc="2.0", id=2, result={}))
64+
assert read_messages[0] == JSONRPCMessage(root=JSONRPCRequest(id=1, method="ping"))
65+
assert read_messages[1] == JSONRPCMessage(root=JSONRPCResponse(id=2, result={}))
6666

6767

6868
@pytest.mark.anyio

tests/issues/test_192_request_id.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ async def run_server():
6363
capabilities=ClientCapabilities(),
6464
clientInfo=Implementation(name="test-client", version="1.0.0"),
6565
).model_dump(by_alias=True, exclude_none=True),
66-
jsonrpc="2.0",
6766
)
6867

6968
await client_writer.send(SessionMessage(JSONRPCMessage(root=init_req)))
@@ -73,12 +72,11 @@ async def run_server():
7372
initialized_notification = JSONRPCNotification(
7473
method="notifications/initialized",
7574
params=NotificationParams().model_dump(by_alias=True, exclude_none=True),
76-
jsonrpc="2.0",
7775
)
7876
await client_writer.send(SessionMessage(JSONRPCMessage(root=initialized_notification)))
7977

8078
# Send ping request with custom ID
81-
ping_request = JSONRPCRequest(id=custom_request_id, method="ping", params={}, jsonrpc="2.0")
79+
ping_request = JSONRPCRequest(id=custom_request_id, method="ping", params={})
8280

8381
await client_writer.send(SessionMessage(JSONRPCMessage(root=ping_request)))
8482

tests/issues/test_malformed_input.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from mcp.shared.message import SessionMessage
1212
from mcp.types import (
1313
INVALID_PARAMS,
14+
JSON_RPC_VERSION,
1415
JSONRPCError,
1516
JSONRPCMessage,
1617
JSONRPCRequest,
@@ -31,7 +32,6 @@ async def test_malformed_initialize_request_does_not_crash_server():
3132
try:
3233
# Create a malformed initialize request (missing required params field)
3334
malformed_request = JSONRPCRequest(
34-
jsonrpc="2.0",
3535
id="f20fe86132ed4cd197f89a7134de5685",
3636
method="initialize",
3737
# params=None # Missing required params field
@@ -63,15 +63,14 @@ async def test_malformed_initialize_request_does_not_crash_server():
6363

6464
# Verify it's a proper JSON-RPC error response
6565
assert isinstance(response, JSONRPCError)
66-
assert response.jsonrpc == "2.0"
66+
assert response.jsonrpc == JSON_RPC_VERSION, f"jsonrpc should be set to '{JSON_RPC_VERSION}'"
6767
assert response.id == "f20fe86132ed4cd197f89a7134de5685"
6868
assert response.error.code == INVALID_PARAMS
6969
assert "Invalid request parameters" in response.error.message
7070

7171
# Verify the session is still alive and can handle more requests
7272
# Send another malformed request to confirm server stability
7373
another_malformed_request = JSONRPCRequest(
74-
jsonrpc="2.0",
7574
id="test_id_2",
7675
method="tools/call",
7776
# params=None # Missing required params
@@ -123,7 +122,6 @@ async def test_multiple_concurrent_malformed_requests():
123122
malformed_requests: list[SessionMessage] = []
124123
for i in range(10):
125124
malformed_request = JSONRPCRequest(
126-
jsonrpc="2.0",
127125
id=f"malformed_{i}",
128126
method="initialize",
129127
# params=None # Missing required params

tests/server/test_lifespan.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ async def run_server():
8484
SessionMessage(
8585
JSONRPCMessage(
8686
root=JSONRPCRequest(
87-
jsonrpc="2.0",
8887
id=1,
8988
method="initialize",
9089
params=TypeAdapter(InitializeRequestParams).dump_python(params),
@@ -100,7 +99,6 @@ async def run_server():
10099
SessionMessage(
101100
JSONRPCMessage(
102101
root=JSONRPCNotification(
103-
jsonrpc="2.0",
104102
method="notifications/initialized",
105103
)
106104
)
@@ -112,7 +110,6 @@ async def run_server():
112110
SessionMessage(
113111
JSONRPCMessage(
114112
root=JSONRPCRequest(
115-
jsonrpc="2.0",
116113
id=2,
117114
method="tools/call",
118115
params={"name": "check_lifespan", "arguments": {}},
@@ -190,7 +187,6 @@ async def run_server():
190187
SessionMessage(
191188
JSONRPCMessage(
192189
root=JSONRPCRequest(
193-
jsonrpc="2.0",
194190
id=1,
195191
method="initialize",
196192
params=TypeAdapter(InitializeRequestParams).dump_python(params),
@@ -206,7 +202,6 @@ async def run_server():
206202
SessionMessage(
207203
JSONRPCMessage(
208204
root=JSONRPCNotification(
209-
jsonrpc="2.0",
210205
method="notifications/initialized",
211206
)
212207
)
@@ -218,7 +213,6 @@ async def run_server():
218213
SessionMessage(
219214
JSONRPCMessage(
220215
root=JSONRPCRequest(
221-
jsonrpc="2.0",
222216
id=2,
223217
method="tools/call",
224218
params={"name": "check_lifespan", "arguments": {}},

tests/server/test_session.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ async def mock_client():
166166
SessionMessage(
167167
types.JSONRPCMessage(
168168
types.JSONRPCRequest(
169-
jsonrpc="2.0",
170169
id=1,
171170
method="initialize",
172171
params=types.InitializeRequestParams(
@@ -194,7 +193,6 @@ async def mock_client():
194193
SessionMessage(
195194
types.JSONRPCMessage(
196195
types.JSONRPCNotification(
197-
jsonrpc="2.0",
198196
method="notifications/initialized",
199197
)
200198
)

0 commit comments

Comments
 (0)