From 7cf3cc96368a93191254edcbbcd7f57380dfd0a8 Mon Sep 17 00:00:00 2001 From: peter-luminova Date: Sun, 22 Feb 2026 14:59:24 +0530 Subject: [PATCH 1/7] feat: add SessionState model for serializable session state This adds a Pydantic BaseModel that can be serialized to JSON for storing session state in external storage (Redis, databases, etc.) Related: #2111 --- src/mcp/shared/session_state.py | 51 +++++++++++++++++ tests/shared/test_session_state.py | 90 ++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 src/mcp/shared/session_state.py create mode 100644 tests/shared/test_session_state.py diff --git a/src/mcp/shared/session_state.py b/src/mcp/shared/session_state.py new file mode 100644 index 000000000..8ab40baee --- /dev/null +++ b/src/mcp/shared/session_state.py @@ -0,0 +1,51 @@ +"""Serializable session state for distributed deployments. + +This module provides a SessionState dataclass that can be serialized to JSON +and stored in external storage (Redis, database, etc.) for distributed deployments. + +This enables session state to be shared across multiple server instances, +allowing MCP services to run behind load balancers or in horizontally-scaled +deployments. +""" + +from __future__ import annotations + +from typing import Any + +from pydantic import BaseModel, Field + + +class SessionState(BaseModel): + """A serializable snapshot of MCP session state. + + This contains the minimal state needed to reconstruct a session context + across process boundaries. Runtime objects (streams, callbacks) are NOT + included as they cannot be serialized and must be recreated. + + Attributes: + session_id: Unique identifier for this session + protocol_version: MCP protocol version being used + next_request_id: The next request ID to use (continues sequence) + server_capabilities: Server capabilities from initialization (as dict) + server_info: Server metadata from initialization (as dict) + initialized_sent: Whether the initialized notification was sent + """ + + session_id: str = Field(description="Unique identifier for this session") + protocol_version: str = Field(description="MCP protocol version being used") + next_request_id: int = Field( + description="Next request ID to use", + ge=0, + ) + server_capabilities: dict[str, Any] | None = Field( + default=None, + description="Server capabilities received during initialization", + ) + server_info: dict[str, Any] | None = Field( + default=None, + description="Server information metadata", + ) + initialized_sent: bool = Field( + default=False, + description="Whether the initialized notification was sent", + ) diff --git a/tests/shared/test_session_state.py b/tests/shared/test_session_state.py new file mode 100644 index 000000000..e8d3994ba --- /dev/null +++ b/tests/shared/test_session_state.py @@ -0,0 +1,90 @@ +"""Tests for SessionState serialization.""" + +from mcp.shared.session_state import SessionState +import pytest + + +def test_session_state_creation(): + """Test that SessionState can be created with all fields.""" + state = SessionState( + session_id="test-session-123", + protocol_version="2025-11-25", + next_request_id=5, + server_capabilities={"tools": {}, "resources": {}}, + server_info={"name": "test-server", "version": "1.0.0"}, + initialized_sent=True, + ) + + assert state.session_id == "test-session-123" + assert state.protocol_version == "2025-11-25" + assert state.next_request_id == 5 + assert state.server_capabilities is not None + assert state.server_info is not None + assert state.initialized_sent is True + + +def test_session_state_defaults(): + """Test that SessionState works with minimal required fields.""" + state = SessionState( + session_id="test-session-456", + protocol_version="2025-11-25", + next_request_id=0, + ) + + assert state.server_capabilities is None + assert state.server_info is None + assert state.initialized_sent is False + + +def test_session_state_json_serialization(): + """Test that SessionState can be serialized to JSON and back.""" + original = SessionState( + session_id="test-session-789", + protocol_version="2025-11-25", + next_request_id=10, + server_capabilities={"tools": {"listChanged": True}}, + server_info={"name": "test-server", "version": "2.0.0"}, + initialized_sent=True, + ) + + # Serialize to JSON + json_str = original.model_dump_json() + + # Deserialize from JSON + restored = SessionState.model_validate_json(json_str) + + # Verify all fields match + assert restored.session_id == original.session_id + assert restored.protocol_version == original.protocol_version + assert restored.next_request_id == original.next_request_id + assert restored.server_capabilities == original.server_capabilities + assert restored.server_info == original.server_info + assert restored.initialized_sent == original.initialized_sent + + +def test_session_state_dict_serialization(): + """Test that SessionState can be serialized to dict and back.""" + original = SessionState( + session_id="test-session-dict", + protocol_version="2025-11-25", + next_request_id=3, + ) + + # Serialize to dict + data_dict = original.model_dump() + + # Deserialize from dict + restored = SessionState.model_validate(data_dict) + + assert restored.session_id == original.session_id + assert restored.next_request_id == original.next_request_id + + +def test_session_state_validation(): + """Test that SessionState validates input data.""" + with pytest.raises(ValueError): # Pydantic validation error + SessionState( + session_id="test", + protocol_version="2025-11-25", + next_request_id=-1, # Invalid: must be >= 0 + ) From ddb29f50ddfaf84e7cb6088c4b58967a000e2be9 Mon Sep 17 00:00:00 2001 From: peter-luminova Date: Sun, 22 Feb 2026 15:11:47 +0530 Subject: [PATCH 2/7] feat: add get_session_state() method to ClientSession This method extracts serializable session state that can be stored in external storage for distributed deployments. Related: #2111 --- src/mcp/client/session.py | 35 ++++++++++++++++++ tests/client/test_session.py | 71 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/src/mcp/client/session.py b/src/mcp/client/session.py index a0ca751bd..7b8f30bbb 100644 --- a/src/mcp/client/session.py +++ b/src/mcp/client/session.py @@ -1,6 +1,7 @@ from __future__ import annotations import logging +import uuid from typing import Any, Protocol import anyio.lowlevel @@ -13,6 +14,7 @@ from mcp.shared._context import RequestContext from mcp.shared.message import SessionMessage from mcp.shared.session import BaseSession, ProgressFnT, RequestResponder +from mcp.shared.session_state import SessionState from mcp.shared.version import SUPPORTED_PROTOCOL_VERSIONS from mcp.types._types import RequestParamsMeta @@ -132,6 +134,9 @@ def __init__( self._message_handler = message_handler or _default_message_handler self._tool_output_schemas: dict[str, dict[str, Any] | None] = {} self._server_capabilities: types.ServerCapabilities | None = None + self._server_info: types.Implementation | None = None + self._initialized_sent: bool = False + self._session_id: str = str(uuid.uuid4()) self._experimental_features: ExperimentalClientFeatures | None = None # Experimental: Task handlers (use defaults if not provided) @@ -186,8 +191,10 @@ async def initialize(self) -> types.InitializeResult: raise RuntimeError(f"Unsupported protocol version from the server: {result.protocol_version}") self._server_capabilities = result.capabilities + self._server_info = result.server_info await self.send_notification(types.InitializedNotification()) + self._initialized_sent = True return result @@ -198,6 +205,34 @@ def get_server_capabilities(self) -> types.ServerCapabilities | None: """ return self._server_capabilities + def get_session_state(self) -> SessionState: + """Extract a serializable snapshot of the current session state. + + This allows the session state to be stored in external storage + (Redis, database, etc.) for distributed deployments. + + Returns: + A SessionState object containing the serializable state + """ + from mcp.shared.version import LATEST_PROTOCOL_VERSION + + return SessionState( + session_id=self._session_id, + protocol_version=LATEST_PROTOCOL_VERSION, + next_request_id=self._request_id, + server_capabilities=( + self._server_capabilities.model_dump(by_alias=True, mode="json", exclude_none=True) + if self._server_capabilities + else None + ), + server_info=( + self._server_info.model_dump(by_alias=True, mode="json", exclude_none=True) + if self._server_info + else None + ), + initialized_sent=self._initialized_sent, + ) + @property def experimental(self) -> ExperimentalClientFeatures: """Experimental APIs for tasks and other features. diff --git a/tests/client/test_session.py b/tests/client/test_session.py index d6d13e273..376df0bbb 100644 --- a/tests/client/test_session.py +++ b/tests/client/test_session.py @@ -706,3 +706,74 @@ async def mock_server(): await session.initialize() await session.call_tool(name=mocked_tool.name, arguments={"foo": "bar"}, meta=meta) + + +@pytest.mark.anyio +async def test_client_session_get_state(): + """Test that get_session_state() returns a valid SessionState.""" + from mcp.shared.session_state import SessionState + + client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage](1) + server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](1) + + async def mock_server(): + session_message = await client_to_server_receive.receive() + jsonrpc_request = session_message.message + assert isinstance(jsonrpc_request, JSONRPCRequest) + + result = InitializeResult( + protocol_version=LATEST_PROTOCOL_VERSION, + capabilities=ServerCapabilities( + logging=None, + resources=None, + tools=None, + experimental=None, + prompts=None, + ), + server_info=Implementation(name="mock-server", version="0.1.0"), + ) + + async with server_to_client_send: + await server_to_client_send.send( + SessionMessage( + JSONRPCResponse( + jsonrpc="2.0", + id=jsonrpc_request.id, + result=result.model_dump(by_alias=True, mode="json", exclude_none=True), + ) + ) + ) + await client_to_server_receive.receive() + + async with ( + ClientSession( + server_to_client_receive, + client_to_server_send, + ) as session, + anyio.create_task_group() as tg, + client_to_server_send, + client_to_server_receive, + server_to_client_send, + server_to_client_receive, + ): + tg.start_soon(mock_server) + + # Initialize the session + await session.initialize() + + # Get session state + state = session.get_session_state() + + # Verify the state + assert isinstance(state, SessionState) + assert state.session_id is not None + assert state.protocol_version == LATEST_PROTOCOL_VERSION + assert state.next_request_id == 1 # After initialize request + assert state.server_capabilities is not None + assert state.server_info is not None + assert state.initialized_sent is True + + # Verify it's serializable + json_str = state.model_dump_json() + assert json_str is not None + From 045462e401f751e2e8dbfc52476ad4665264166c Mon Sep 17 00:00:00 2001 From: peter-luminova Date: Sun, 22 Feb 2026 15:15:27 +0530 Subject: [PATCH 3/7] feat: add from_session_state() classmethod to ClientSession This classmethod creates a new ClientSession from a previously saved SessionState, enabling distributed deployments. Related: #2111 --- src/mcp/client/session.py | 61 ++++++++++++++++++++++++++++++++++++ tests/client/test_session.py | 52 ++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/src/mcp/client/session.py b/src/mcp/client/session.py index 7b8f30bbb..76aa7d2c0 100644 --- a/src/mcp/client/session.py +++ b/src/mcp/client/session.py @@ -233,6 +233,67 @@ def get_session_state(self) -> SessionState: initialized_sent=self._initialized_sent, ) + @classmethod + def from_session_state( + cls, + state: SessionState, + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], + write_stream: MemoryObjectSendStream[SessionMessage], + client_info: types.Implementation | None = None, + read_timeout_seconds: float | None = None, + sampling_callback: SamplingFnT | None = None, + elicitation_callback: ElicitationFnT | None = None, + list_roots_callback: ListRootsFnT | None = None, + logging_callback: LoggingFnT | None = None, + message_handler: MessageHandlerFnT | None = None, + *, + sampling_capabilities: types.SamplingCapability | None = None, + experimental_task_handlers: ExperimentalTaskHandlers | None = None, + ) -> ClientSession: + """Create a new ClientSession from a previously saved SessionState. + + This restores session context from external storage, allowing + distributed instances to continue a session. + + Args: + state: The SessionState to restore from + read_stream: The read stream for receiving messages + write_stream: The write stream for sending messages + client_info: Optional client info (defaults to DEFAULT_CLIENT_INFO) + read_timeout_seconds: Optional read timeout for this session + + Returns: + A new ClientSession instance with the restored state + """ + # Create session with default initialization + session = cls( + read_stream=read_stream, + write_stream=write_stream, + client_info=client_info, + read_timeout_seconds=read_timeout_seconds, + sampling_callback=sampling_callback, + elicitation_callback=elicitation_callback, + list_roots_callback=list_roots_callback, + logging_callback=logging_callback, + message_handler=message_handler, + sampling_capabilities=sampling_capabilities, + experimental_task_handlers=experimental_task_handlers, + ) + + # Restore the state + session._session_id = state.session_id + session._request_id = state.next_request_id + + if state.server_capabilities: + session._server_capabilities = types.ServerCapabilities.model_validate(state.server_capabilities) + + if state.server_info: + session._server_info = types.Implementation.model_validate(state.server_info) + + session._initialized_sent = state.initialized_sent + + return session + @property def experimental(self) -> ExperimentalClientFeatures: """Experimental APIs for tasks and other features. diff --git a/tests/client/test_session.py b/tests/client/test_session.py index 376df0bbb..24d745f89 100644 --- a/tests/client/test_session.py +++ b/tests/client/test_session.py @@ -777,3 +777,55 @@ async def mock_server(): json_str = state.model_dump_json() assert json_str is not None + +@pytest.mark.anyio +async def test_client_session_from_state(): + """Test that from_session_state() creates a valid session.""" + from mcp.shared.session_state import SessionState + + # Create a session state + state = SessionState( + session_id="test-session-from-state", + protocol_version=LATEST_PROTOCOL_VERSION, + next_request_id=5, + server_capabilities={ + "tools": {}, + "resources": {}, + "prompts": None, + "logging": None, + "experimental": None, + }, + server_info={"name": "test-server", "version": "1.0.0"}, + initialized_sent=True, + ) + + # Create streams + client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage](1) + server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](1) + + # Create session from state + session = ClientSession.from_session_state( + state, + server_to_client_receive, + client_to_server_send, + ) + + # Verify the session was created with the correct state + assert session._session_id == "test-session-from-state" + assert session._request_id == 5 # Continues from saved state + assert session._server_capabilities is not None + assert session._initialized_sent is True + assert session._server_info is not None + assert session._server_info.name == "test-server" + assert session._server_info.version == "1.0.0" + + # Clean up streams + async with ( + client_to_server_send, + client_to_server_receive, + server_to_client_send, + server_to_client_receive, + ): + pass + + From bd1883a92e30dcc64f4d28e3a410f693469e3f67 Mon Sep 17 00:00:00 2001 From: peter-luminova Date: Sun, 22 Feb 2026 15:16:10 +0530 Subject: [PATCH 4/7] test: add integration test for session state round-trip This test verifies that session state can be extracted, serialized to JSON, deserialized, and restored with all fields intact. Related: #2111 --- tests/client/test_session.py | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/client/test_session.py b/tests/client/test_session.py index 24d745f89..76f271562 100644 --- a/tests/client/test_session.py +++ b/tests/client/test_session.py @@ -829,3 +829,74 @@ async def test_client_session_from_state(): pass +@pytest.mark.anyio +async def test_client_session_state_roundtrip(): + """Test that session state can be serialized and restored.""" + from mcp.shared.session_state import SessionState + + client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage](1) + server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](1) + + async def mock_server(): + session_message = await client_to_server_receive.receive() + jsonrpc_request = session_message.message + assert isinstance(jsonrpc_request, JSONRPCRequest) + + result = InitializeResult( + protocol_version=LATEST_PROTOCOL_VERSION, + capabilities=ServerCapabilities( + logging=None, + resources=None, + tools=None, + experimental=None, + prompts=None, + ), + server_info=Implementation(name="mock-server", version="0.1.0"), + ) + + async with server_to_client_send: + await server_to_client_send.send( + SessionMessage( + JSONRPCResponse( + jsonrpc="2.0", + id=jsonrpc_request.id, + result=result.model_dump(by_alias=True, mode="json", exclude_none=True), + ) + ) + ) + await client_to_server_receive.receive() + + async with ( + ClientSession( + server_to_client_receive, + client_to_server_send, + ) as original_session, + anyio.create_task_group() as tg, + client_to_server_send, + client_to_server_receive, + server_to_client_send, + server_to_client_receive, + ): + tg.start_soon(mock_server) + + # Initialize the session + await original_session.initialize() + + # Extract state + original_state = original_session.get_session_state() + + # Verify it can be serialized to JSON + json_str = original_state.model_dump_json() + + # Verify it can be deserialized from JSON + restored_state = SessionState.model_validate_json(json_str) + + # Verify all fields match + assert restored_state.session_id == original_state.session_id + assert restored_state.protocol_version == original_state.protocol_version + assert restored_state.next_request_id == original_state.next_request_id + assert restored_state.server_capabilities == original_state.server_capabilities + assert restored_state.server_info == original_state.server_info + assert restored_state.initialized_sent == original_state.initialized_sent + + From 8c715af8674a186263fd7c9ba5cbf7e48b9d65a7 Mon Sep 17 00:00:00 2001 From: peter-luminova Date: Sun, 22 Feb 2026 15:17:06 +0530 Subject: [PATCH 5/7] feat: export SessionState from public API Make SessionState available via and . Related: #2111 --- src/mcp/__init__.py | 2 ++ src/mcp/shared/__init__.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/mcp/__init__.py b/src/mcp/__init__.py index 4b5caa9cc..3c56ecbd4 100644 --- a/src/mcp/__init__.py +++ b/src/mcp/__init__.py @@ -5,6 +5,7 @@ from .server.session import ServerSession from .server.stdio import stdio_server from .shared.exceptions import MCPError, UrlElicitationRequiredError +from .shared.session_state import SessionState from .types import ( CallToolRequest, ClientCapabilities, @@ -114,6 +115,7 @@ "SamplingMessageContentBlock", "SamplingRole", "SamplingToolsCapability", + "SessionState", "ServerCapabilities", "ServerNotification", "ServerRequest", diff --git a/src/mcp/shared/__init__.py b/src/mcp/shared/__init__.py index e69de29bb..931f3457d 100644 --- a/src/mcp/shared/__init__.py +++ b/src/mcp/shared/__init__.py @@ -0,0 +1,3 @@ +from .session_state import SessionState + +__all__ = ["SessionState"] From 33cc03ccc13feccef6179404a1cffdbca5d01dc3 Mon Sep 17 00:00:00 2001 From: peter-luminova Date: Sun, 22 Feb 2026 15:23:14 +0530 Subject: [PATCH 6/7] style: apply code formatting and linting fixes --- pyproject.toml | 1 + tests/client/test_session.py | 2 -- tests/shared/test_session_state.py | 3 ++- uv.lock | 16 ++++++++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 737839a23..f78c2e5f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,7 @@ dev = [ "coverage[toml]>=7.10.7,<=7.13", "pillow>=12.0", "strict-no-cover", + "pytest-cov>=7.0.0", ] docs = [ "mkdocs>=1.6.1", diff --git a/tests/client/test_session.py b/tests/client/test_session.py index 76f271562..77d9c54f4 100644 --- a/tests/client/test_session.py +++ b/tests/client/test_session.py @@ -898,5 +898,3 @@ async def mock_server(): assert restored_state.server_capabilities == original_state.server_capabilities assert restored_state.server_info == original_state.server_info assert restored_state.initialized_sent == original_state.initialized_sent - - diff --git a/tests/shared/test_session_state.py b/tests/shared/test_session_state.py index e8d3994ba..29f10a451 100644 --- a/tests/shared/test_session_state.py +++ b/tests/shared/test_session_state.py @@ -1,8 +1,9 @@ """Tests for SessionState serialization.""" -from mcp.shared.session_state import SessionState import pytest +from mcp.shared.session_state import SessionState + def test_session_state_creation(): """Test that SessionState can be created with all fields.""" diff --git a/uv.lock b/uv.lock index d01d510f1..0bad7294f 100644 --- a/uv.lock +++ b/uv.lock @@ -820,6 +820,7 @@ dev = [ { name = "pillow" }, { name = "pyright" }, { name = "pytest" }, + { name = "pytest-cov" }, { name = "pytest-examples" }, { name = "pytest-flakefinder" }, { name = "pytest-pretty" }, @@ -868,6 +869,7 @@ dev = [ { name = "pillow", specifier = ">=12.0" }, { name = "pyright", specifier = ">=1.1.400" }, { name = "pytest", specifier = ">=8.3.4" }, + { name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-examples", specifier = ">=0.0.14" }, { name = "pytest-flakefinder", specifier = ">=1.1.0" }, { name = "pytest-pretty", specifier = ">=1.2.0" }, @@ -1982,6 +1984,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, ] +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + [[package]] name = "pytest-examples" version = "0.0.18" From 6af150a95a35a66669968e793cdd84044222bbc6 Mon Sep 17 00:00:00 2001 From: peter-luminova Date: Sun, 22 Feb 2026 15:42:46 +0530 Subject: [PATCH 7/7] test: add coverage for None branches in from_session_state This test ensures the branches where server_capabilities and server_info are None are covered, achieving 100% branch coverage. Related: #2111 --- tests/client/test_session.py | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/client/test_session.py b/tests/client/test_session.py index 77d9c54f4..ce610a087 100644 --- a/tests/client/test_session.py +++ b/tests/client/test_session.py @@ -829,6 +829,49 @@ async def test_client_session_from_state(): pass +@pytest.mark.anyio +async def test_client_session_from_state_without_capabilities(): + """Test that from_session_state() handles None capabilities and server_info.""" + from mcp.shared.session_state import SessionState + + # Create a session state with None capabilities (before initialization) + state = SessionState( + session_id="test-session-minimal", + protocol_version=LATEST_PROTOCOL_VERSION, + next_request_id=0, + server_capabilities=None, + server_info=None, + initialized_sent=False, + ) + + # Create streams + client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage](1) + server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](1) + + # Create session from state + session = ClientSession.from_session_state( + state, + server_to_client_receive, + client_to_server_send, + ) + + # Verify the session was created with the correct state + assert session._session_id == "test-session-minimal" + assert session._request_id == 0 + assert session._server_capabilities is None + assert session._server_info is None + assert session._initialized_sent is False + + # Clean up streams + async with ( + client_to_server_send, + client_to_server_receive, + server_to_client_send, + server_to_client_receive, + ): + pass + + @pytest.mark.anyio async def test_client_session_state_roundtrip(): """Test that session state can be serialized and restored."""