Skip to content

feat: expand InitializationState with explicit lifecycle state machine#1

Open
dgenio wants to merge 137 commits intomainfrom
feat/session-lifecycle-state-machine
Open

feat: expand InitializationState with explicit lifecycle state machine#1
dgenio wants to merge 137 commits intomainfrom
feat/session-lifecycle-state-machine

Conversation

@dgenio
Copy link
Owner

@dgenio dgenio commented Feb 19, 2026

Summary

Addresses #1691 — Phase 1: expand the InitializationState enum with an explicit lifecycle state machine and add centralized transition validation.

Problem

The current ServerSession lifecycle management uses a simple three-state enum (NotInitialized, Initializing, Initialized) with direct state assignment. This makes it difficult to reason about session lifecycle, provides no protection against invalid transitions, and lacks visibility into shutdown states. Stateless sessions were handled by jumping directly to Initialized, conflating two conceptually different modes.

Solution

Expanded InitializationState enum

  • Stateless — sessions that skip the initialization handshake (previously mapped to Initialized)
  • Closing — session is shutting down, entered during __aexit__
  • Closed — terminal state after shutdown completes
  • Error — unrecoverable failure, with recovery paths to Closing/Closed

Centralized transition validation

  • _VALID_TRANSITIONS dict — maps each state to its valid target states, documenting the state machine in one place
  • _transition_state() method — validates transitions and raises RuntimeError on invalid ones, with debug logging
  • Re-initialization (Initialized → Initializing) is explicitly allowed for backward compatibility

New properties

  • initialization_state — read-only access to current state
  • is_initialized — returns True for both Initialized and Stateless (replaces direct comparisons)

__aexit__ override

  • Transitions through Closing → Closed on session exit
  • Gracefully handles edge cases (already closing, error states)

Updated handlers

  • _received_request and _received_notification now use _transition_state() instead of direct assignment
  • _received_notification guards against redundant InitializedNotification in stateless mode

Tests

20 new tests in tests/server/test_session_lifecycle.py covering:

  • Enum completeness and value uniqueness
  • Transition table correctness (all states have entries, Closed is terminal, Error allows recovery)
  • Valid and invalid state transitions via _transition_state()
  • is_initialized property for all states
  • __aexit__ lifecycle transitions
  • Full client/server handshake integration test

All 474 existing server tests pass with no regressions.

crondinini-ant and others added 30 commits December 1, 2025 17:48
…protocol#1663)

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Felix Weinberger <3823880+felixweinberger@users.noreply.github.com>
* Auto-enable DNS rebinding protection for localhost servers

When a FastMCP server is created with host="127.0.0.1" or "localhost"
and no explicit transport_security is provided, automatically enable
DNS rebinding protection. Both 127.0.0.1 and localhost are allowed
as valid hosts/origins since clients may use either to connect.

* Add tests for auto DNS rebinding protection on localhost

Tests verify that:
- Protection auto-enables for host=127.0.0.1
- Protection auto-enables for host=localhost
- Both 127.0.0.1 and localhost are in allowed hosts/origins
- Protection does NOT auto-enable for other hosts (e.g., 0.0.0.0)
- Explicit transport_security settings are not overridden

* Add IPv6 localhost (::1) support for DNS rebinding protection

Extend auto-enable DNS rebinding protection to also cover IPv6
localhost. When host="::1", protection is now auto-enabled with
appropriate allowed hosts ([::1]:*) and origins (http://[::1]:*).

* Fix import ordering in test file
…modelcontextprotocol#1669)

Co-authored-by: TheMailmans <tyler@example.com>
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
…elcontextprotocol#1384)

Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
Co-authored-by: ARJUN-TS1 <arjun.ts1@ibm.com>
Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Felix Weinberger <3823880+felixweinberger@users.noreply.github.com>
…d of `httpx_client_factory` (modelcontextprotocol#1177)

Co-authored-by: Felix Weinberger <fweinberger@anthropic.com>
…otocol#1782)

Signed-off-by: Ondrej Mosnáček <omosnacek@gmail.com>
…#1481)

Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
…col#1503)

Co-authored-by: Paul Carleton <paulcarletonjr@gmail.com>
…textprotocol#1808)

Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
Kludex and others added 25 commits February 7, 2026 14:12
…across 1 directory (modelcontextprotocol#2031)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
…ross 1 directory (modelcontextprotocol#2036)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
…delcontextprotocol#2038)

Co-authored-by: Lee Hubbard <hubbard.zlee@unknowncyber.com>
Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
Expand the InitializationState enum with new states (Stateless, Closing, Closed, Error) and add centralized transition validation via a _VALID_TRANSITIONS table and _transition_state() method.

Key changes:

- Add Stateless state for sessions that skip the initialization handshake

- Add Closing/Closed states for orderly shutdown tracking

- Add Error state for unrecoverable failures with recovery paths

- Add _transition_state() method that validates transitions against a table

- Add initialization_state property (read-only) and is_initialized property

- Override __aexit__ to transition through Closing -> Closed on exit

- Update _received_request and _received_notification to use new APIs

- Add comprehensive test suite (20 tests) covering all state transitions

Github-Issue: modelcontextprotocol#1691
@dgenio dgenio force-pushed the feat/session-lifecycle-state-machine branch from d443932 to cf1bbd2 Compare February 19, 2026 15:05
Add tests for __aexit__ when session is already in Closing or Closed
state, covering the 'if' False branch and the second except RuntimeError.
Mark the first except RuntimeError as pragma: no cover since it is
unreachable under the current transition table (all non-terminal states
can transition to Closing).
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.

Comments