Skip to content

[mcp/python-sdk] ClientSession has no way to specify protocolVersion #2307

Closed as not planned
Jah-yee/python-sdk
#3

Description

@tsingh2k15

Initial Checks

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

Activity

  1. added a commit that references this issue on Mar 19, 2026
    88111e7
  2. added 2 commits that reference this issue on Mar 19, 2026
    5fa31c3
    db9da1c
  3. goingforstudying-ctrl commented on Mar 20, 2026

    @goingforstudying-ctrl

    Submitted PR #2321 to implement this feature: #2321

    This adds the protocol_version parameter to ClientSession, allowing users to connect to servers that require a specific protocol version (like Snowflake). Please review when you have time. Thanks!

  4. tsingh2k15 commented on Mar 21, 2026

    @tsingh2k15
    Author

    Tested and confirmed working.

    I couldn't test PR #2321 directly, I applied the PR's two changes manually to the installed mcp==1.26.0 session.py:

    Added protocol_version: str | None = None to ClientSession.__init__()
    Stored as self._protocol_version = protocol_version or types.LATEST_PROTOCOL_VERSION
    Used self._protocol_version in initialize() instead of the hardcoded constant

    With those changes in place, I updated my code to pass protocol_version="2025-06-18" directly to ClientSession and removed my module-level global mutation workaround entirely. The smoke test against Snowflake's managed MCP server passed; data returned successfully.

    The fix is clean and non-breaking.

    Thanks @goingforstudying-ctrl for picking this up quickly.

  5. added a commit that references this issue on Mar 28, 2026
    132d8a2
  6. added a commit that references this issue on Apr 30, 2026
    b3e0468
  7. maxisbey commented on Aug 10, 2026

    @maxisbey
    Contributor

    The client offering its newest protocol version is the spec's negotiation model — a server that doesn't support that version responds with one it does, and the client accepts the counter-offer (e.g. 2025-06-18); on v2 the handshake version is deliberately not pinnable (docs/protocol-versions.md, "Pinning a version"). Closing this as part of a wider backlog cleanup following the v2 launch. Feel free to reopen if this is still relevant.

    AI Disclaimer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions