-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Description
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
I could not determine if this may be design intent, but I ran into issue where ClientSession.initialize() hardcodes protocolVersion=types.LATEST_PROTOCOL_VERSION with no way for the caller to override it. When connecting to an MCP server that requires a specific protocol version (e.g. Snowflake's managed MCP server requires "2025-06-18"), the only workaround is to mutate the module-level constant before calling initialize() and restore it afterward. Please feel free me to provide guidance if this can be resolved differently.
Current behaviour (mcp/client/session.py, v1.26.0)
async def initialize(self) -> types.InitializeResult:
result = await self.send_request(
types.ClientRequest(
types.InitializeRequest(
params=types.InitializeRequestParams(
protocolVersion=types.LATEST_PROTOCOL_VERSION, # no override possible
...
)
)
),
types.InitializeResult,
)
ClientSession.init() accepts many optional parameters (sampling_callback, client_info, etc.) but has no protocol_version parameter.
Steps to reproduce
- Install mcp>=1.0
- Connect to any MCP server that requires a protocol version other than LATEST_PROTOCOL_VERSION
- Call session.initialize() — the server rejects the handshake
- Concrete example: Snowflake managed MCP server requires "2025-06-18". With mcp==1.26.0 (LATEST_PROTOCOL_VERSION = "2025-11-25"), the session is terminated immediately after initialize().
Proposed fix
Add an optional protocol_version parameter to ClientSession.init():
def __init__(
self,
read_stream: ...,
write_stream: ...,
...
protocol_version: str | None = None, # NEW — defaults to LATEST_PROTOCOL_VERSION
) -> None:
self._protocol_version = protocol_version or types.LATEST_PROTOCOL_VERSION
Then use it in initialize():
protocolVersion=self._protocol_version,
Non-breaking change; existing callers get the current default. Callers that need a specific version pass it explicitly without touching any globals.
Example Code
"""
ClientSession.initialize() hardcodes LATEST_PROTOCOL_VERSION
with no way to override it via the public API.
Tested with: Python 3.14.2, mcp==1.26.0
"""
import asyncio
import mcp.types as mcp_types
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamablehttp_client
MCP_URL = "https://<your-account>.snowflakecomputing.com/api/v2/databases/<DB>/schemas/<SCHEMA>/mcp-servers/<SERVER>"
HEADERS = {"Authorization": "Bearer <your-pat>", "X-Snowflake-Role": "<your-role>"}
# The version Snowflake's MCP server requires during initialize handshake.
# The library hardcodes "2025-11-25" — Snowflake rejects it with "Session terminated".
REQUIRED_VERSION = "2025-06-18"
async def main():
# Without the patch — Snowflake terminates the session:
async with streamablehttp_client(url=MCP_URL, headers=HEADERS) as (r, w, _):
async with ClientSession(r, w) as session:
await session.initialize() # raises: "Session terminated"
asyncio.run(main())Python & MCP Python SDK
Python: 3.14.2
MCP Python SDK: 1.26.0