Skip to content

feat(client): store InitializeResult on ClientSession, decompose on Client#2300

Draft
maxisbey wants to merge 2 commits intomainfrom
feat/server-params
Draft

feat(client): store InitializeResult on ClientSession, decompose on Client#2300
maxisbey wants to merge 2 commits intomainfrom
feat/server-params

Conversation

@maxisbey
Copy link
Contributor

@maxisbey maxisbey commented Mar 17, 2026

ClientSession now stores the full InitializeResult via an initialize_result property. The high-level Client exposes it as three decomposed, non-nullable properties.

Closes #1018. Supersedes #1565 and #2211.

Motivation and Context

Previously, ClientSession destructured only result.capabilities and discarded server_info, instructions, and protocol_version — users had to manually capture the return value of initialize(), which Client.__aenter__ throws away.

ClientSession.initialize_result

Stores the whole InitializeResult, returns InitializeResult | None. The | None is honest here — users who manage ClientSession directly can observe the pre-init state.

The name matches the type and the method that populates it (initialize()initialize_result). Go's SDK calls this InitializeResult(); FastMCP calls it initialize_result. The earlier candidate name server_params collided with the established server_params = StdioServerParameters(...) idiom used throughout README, examples, tests, and ClientSessionGroup's ServerParameters type alias.

Client.server_capabilities / server_info / server_instructions

Inside async with Client(...) as client, initialization is guaranteed — __aenter__ calls initialize() before returning. So Client captures the result and exposes it as three non-nullable properties:

  • server_capabilities: ServerCapabilities — same name as v1, now non-nullable instead of | None
  • server_info: Implementation — the server's name/version
  • server_instructions: str | NoneNone means the server didn't provide any (spec marks instructions optional)

Each raises RuntimeError if accessed outside the context manager, matching the existing session property.

The negotiated protocol_version is not exposed on Client — it's transport plumbing. Power users can reach it via client.session.initialize_result.protocol_version.

How Has This Been Tested?

  • test_initialize_result asserts None before init and all four fields after
  • test_client_is_initialized asserts all three Client properties
  • test_client_server_properties_before_enter covers the RuntimeError paths
  • ./scripts/test — 100% coverage, strict-no-cover clean
  • pyright — 0 errors

Breaking Changes

  • ClientSession.get_server_capabilities() removed → use session.initialize_result.capabilities
  • Client.server_capabilities return type narrowed from ServerCapabilities | None to ServerCapabilities (raises RuntimeError outside context instead of returning None)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

AI Disclaimer

ClientSession now stores the complete InitializeResult via a server_params
property, mirroring ServerSession.client_params. This provides access to
server_info, capabilities, instructions, and the negotiated protocol_version
through a single, future-proof property.

Previously, only capabilities were stored (via _server_capabilities) and
users had no access to server_info, instructions, or protocol_version after
initialize() returned — they had to manually capture the return value.

get_server_capabilities() and Client.server_capabilities have been removed.

Github-Issue: #1018
…rties

- ClientSession.server_params -> initialize_result (avoids collision with
  StdioServerParameters idiom; matches Go SDK and FastMCP)
- Client: replace server_params proxy with non-nullable server_capabilities,
  server_info, server_instructions (init is guaranteed inside the context
  manager, so | None was unreachable)
- Client.server_capabilities is preserved from v1 with a better type

Github-Issue: #1018
@maxisbey maxisbey force-pushed the feat/server-params branch from 915a21c to 3455447 Compare March 18, 2026 10:11
@maxisbey maxisbey changed the title feat(client): store full InitializeResult as server_params feat(client): store InitializeResult on ClientSession, decompose on Client Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update _client_info on the ClientSession upon initialization with serverInfo

1 participant