Skip to content

Commit f77411a

Browse files
committed
fix: reject changed duplicate initialize
1 parent 161834d commit f77411a

2 files changed

Lines changed: 75 additions & 2 deletions

File tree

src/mcp/server/session.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,20 @@ async def _receive_loop(self) -> None:
165165
async def _received_request(self, responder: RequestResponder[types.ClientRequest, types.ServerResult]):
166166
match responder.request:
167167
case types.InitializeRequest(params=params):
168+
if self._client_params is not None and params != self._client_params:
169+
with responder:
170+
await responder.respond(
171+
types.ErrorData(
172+
code=types.INVALID_PARAMS,
173+
message="Session already initialized with different parameters",
174+
)
175+
)
176+
return
177+
168178
requested_version = params.protocol_version
169-
self._initialization_state = InitializationState.Initializing
170-
self._client_params = params
179+
if self._client_params is None:
180+
self._initialization_state = InitializationState.Initializing
181+
self._client_params = params
171182
with responder:
172183
await responder.respond(
173184
types.InitializeResult(

tests/server/test_session.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,68 @@ async def mock_client():
207207
assert received_protocol_version == "2024-11-05"
208208

209209

210+
@pytest.mark.anyio
211+
async def test_duplicate_initialize_with_changed_params_keeps_original_client_params():
212+
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](1)
213+
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage | Exception](1)
214+
215+
async with (
216+
client_to_server_send,
217+
client_to_server_receive,
218+
server_to_client_send,
219+
server_to_client_receive,
220+
):
221+
async with ServerSession(
222+
client_to_server_receive,
223+
server_to_client_send,
224+
InitializationOptions(
225+
server_name="mcp",
226+
server_version="0.1.0",
227+
capabilities=ServerCapabilities(),
228+
),
229+
) as session:
230+
first_params = types.InitializeRequestParams(
231+
protocol_version=types.LATEST_PROTOCOL_VERSION,
232+
capabilities=types.ClientCapabilities(),
233+
client_info=types.Implementation(name="first-client", version="1.0.0"),
234+
)
235+
second_params = types.InitializeRequestParams(
236+
protocol_version=types.LATEST_PROTOCOL_VERSION,
237+
capabilities=types.ClientCapabilities(),
238+
client_info=types.Implementation(name="second-client", version="1.0.0"),
239+
)
240+
241+
await client_to_server_send.send(
242+
SessionMessage(
243+
types.JSONRPCRequest(
244+
jsonrpc="2.0",
245+
id=1,
246+
method="initialize",
247+
params=first_params.model_dump(by_alias=True, mode="json", exclude_none=True),
248+
)
249+
)
250+
)
251+
first_response = await server_to_client_receive.receive()
252+
assert isinstance(first_response.message, types.JSONRPCResponse)
253+
assert session.client_params == first_params
254+
255+
await client_to_server_send.send(
256+
SessionMessage(
257+
types.JSONRPCRequest(
258+
jsonrpc="2.0",
259+
id=2,
260+
method="initialize",
261+
params=second_params.model_dump(by_alias=True, mode="json", exclude_none=True),
262+
)
263+
)
264+
)
265+
second_response = await server_to_client_receive.receive()
266+
267+
assert isinstance(second_response.message, types.JSONRPCError)
268+
assert second_response.message.error.code == types.INVALID_PARAMS
269+
assert session.client_params == first_params
270+
271+
210272
@pytest.mark.anyio
211273
async def test_ping_request_before_initialization():
212274
"""Test that ping requests are allowed before initialization is complete."""

0 commit comments

Comments
 (0)