Skip to content

Conversation

@aradyaron
Copy link
Contributor

@aradyaron aradyaron commented Oct 26, 2025

Description

Adds a new SessionIdManagerResolver interface to enable request-based session ID management strategies in the StreamableHTTP server. Replaces direct SessionIdManager usage with resolver pattern while maintaining full backward compatibility.

Fixes #625

Type of Change

  • New feature (non-breaking change that adds functionality)
  • Code refactoring (no functional changes)

Checklist

  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the documentation accordingly

Additional Information

New Interface:

type SessionIdManagerResolver interface {
    ResolveSessionIdManager(r *http.Request) SessionIdManager
}

Key Changes:

  • Added DefaultSessionIdManagerResolver implementation
  • Enhanced WithSessionIdManager and WithStateLess to use resolvers
  • Added new WithSessionIdManagerResolver configuration option
  • All existing APIs remain unchanged

Benefits:

  • Enables request-based session management (multi-tenant, per-endpoint, etc.)
  • Zero breaking changes
  • Comprehensive test coverage added

Summary by CodeRabbit

  • Refactor

    • Redesigned session ID management to support per-request resolution and pluggable resolvers, with a safe default preserving prior behavior and a new option to inject custom resolution logic.
  • Tests

    • Added comprehensive tests for resolver behavior, stateless/stateful modes, option precedence, defensive nil handling, and server integration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2025

Warning

Rate limit exceeded

@aradyaron has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 13 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between e82941f and 4877e74.

📒 Files selected for processing (2)
  • server/streamable_http.go (8 hunks)
  • server/streamable_http_test.go (1 hunks)

Walkthrough

Adds a per-request session ID manager resolver: new SessionIdManagerResolver interface, DefaultSessionIdManagerResolver implementation, WithSessionIdManagerResolver option, and replaces direct SessionIdManager usage with per-request resolver lookups across POST/DELETE/sampling handlers; tests added for resolver behavior and option precedence.

Changes

Cohort / File(s) Change Summary
Session ID Manager Resolver Implementation
server/streamable_http.go
Add SessionIdManagerResolver interface and DefaultSessionIdManagerResolver (constructor + Resolve method). Replace direct s.sessionIdManager usage with s.sessionIdManagerResolver.ResolveSessionIdManager(r) in handlePost, handleDelete, handleSamplingResponse, and related flows. Add WithSessionIdManagerResolver option; update WithSessionIdManager and WithStateLess to set a resolver; initialize server with a default resolver wrapping InsecureStatefulSessionIdManager in NewStreamableHTTPServer.
Test Coverage
server/streamable_http_test.go
Add TestDefaultSessionIdManagerResolver and TestSessionIdManagerResolver_Integration covering resolver resolution, stateless/stateful behavior, option precedence (WithSessionIdManagerResolver overrides WithSessionIdManager and WithStateLess), nil-resolver and nil-manager defensive handling, and multi-request consistency.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect all call sites in server/streamable_http.go to confirm Generate/Validate/Terminate are called on the resolved manager and that nil fallbacks are correct.
  • Verify options precedence logic (WithSessionIdManagerResolver vs WithSessionIdManager/WithStateLess) and default resolver initialization.
  • Review added tests in server/streamable_http_test.go for edge cases (nil resolver/manager, stateless behavior).

Possibly related PRs

Suggested labels

area: sdk

Suggested reviewers

  • ezynda3
  • rwjblue-glean
  • pottekkat

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "feat(mcp): Add SessionIdManagerResolver interface for request-based session management" clearly and concisely summarizes the main change. It specifically identifies what was added (SessionIdManagerResolver interface), explains its purpose (request-based session management), and uses the appropriate conventional commit prefix (feat). The title is neither vague nor overly broad, and directly corresponds to the primary objectives outlined in the linked issue #625.
Linked Issues Check ✅ Passed The pull request fully satisfies the requirements in linked issue #625. The issue requested the ability to pass HTTP request context to session management logic to enable verification that an MCP session ID serves a single user, proposing either extending SessionIdManager methods or introducing a SessionIdManagerResolver. The PR implements the proposed SessionIdManagerResolver pattern exactly as specified in Option 2, introducing the interface with ResolveSessionIdManager(r *http.Request), providing a DefaultSessionIdManagerResolver implementation, integrating it with configuration options (WithSessionIdManagerResolver, WithSessionIdManager, WithStateLess), and ensuring backward compatibility. Comprehensive test coverage validates resolver behavior, option precedence, and integration with the server.
Out of Scope Changes Check ✅ Passed All changes in the pull request are directly aligned with the objectives of linked issue #625. The modifications to server/streamable_http.go (SessionIdManagerResolver interface, DefaultSessionIdManagerResolver, WithSessionIdManagerResolver option, and resolver-based lookups in handler methods) are core to implementing the requested feature. The test additions in server/streamable_http_test.go comprehensively cover the new resolver functionality, option precedence, and integration scenarios. No extraneous changes, unrelated refactoring, or functionality outside the session management resolver pattern are present.
Description Check ✅ Passed The pull request description follows the repository template and includes all required sections: a clear description of changes, proper type of change selections (New feature and Code refactoring), a completed checklist with all items marked, and helpful additional information with code examples. The description links to the related issue, explains the benefits and non-breaking nature of the changes, and provides context about test coverage. The author appropriately removed the MCP Spec Compliance section as it was not applicable.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/streamable_http.go (1)

55-57: Fix stale doc and nil-guard manager → resolver

  • The comment references SimpleStatefulSessionIdGenerator; code uses InsecureStatefulSessionIdManager.
  • Passing a nil manager produces a resolver returning nil -> panic on Generate/Validate/Terminate.

Apply:

-// By default, the server will use SimpleStatefulSessionIdGenerator, which generates
-// session ids with uuid, and it's insecure.
+// By default, the server uses InsecureStatefulSessionIdManager (UUID-based; insecure).
 func WithSessionIdManager(manager SessionIdManager) StreamableHTTPOption {
   return func(s *StreamableHTTPServer) {
-    s.sessionIdManagerResolver = NewDefaultSessionIdManagerResolver(manager)
+    if manager == nil {
+      s.sessionIdManagerResolver = NewDefaultSessionIdManagerResolver(&InsecureStatefulSessionIdManager{})
+      return
+    }
+    s.sessionIdManagerResolver = NewDefaultSessionIdManagerResolver(manager)
   }
 }

Also applies to: 57-62

🧹 Nitpick comments (3)
server/streamable_http.go (2)

64-67: Clarify option precedence (last-wins) in docs

Current behavior is order-dependent. Make docs explicit to avoid surprises.

-// Notice: it will override both WithStateLess and WithSessionIdManager options.
+// Note: Options are applied in order; the last one wins. If combined with
+// WithStateLess or WithSessionIdManager, whichever is applied last takes effect.

1193-1197: Mitigate unbounded growth of terminated set

InsecureStatefulSessionIdManager.terminated grows without bounds. Consider TTL-based eviction or periodic compaction to avoid memory bloat under churn.

Also applies to: 1223-1233

server/streamable_http_test.go (1)

1772-1905: Integration coverage looks solid; add nil-guard cases

Add tests to ensure passing nil to WithSessionIdManager and WithSessionIdManagerResolver falls back safely (after implementing guards).

@@
 func TestSessionIdManagerResolver_Integration(t *testing.T) {
@@
   t.Run("Nil manager falls back safely", func(t *testing.T) {
     mcpServer := NewMCPServer("test-server", "1.0.0")
-    // requires nil-guard in WithSessionIdManager
+    // requires nil-guard in WithSessionIdManager
     srv := NewTestStreamableHTTPServer(mcpServer, WithSessionIdManager(nil))
     defer srv.Close()
     resp, err := postJSON(srv.URL, initRequest)
     if err != nil {
       t.Fatalf("init failed: %v", err)
     }
     if resp.StatusCode != http.StatusOK {
       t.Fatalf("expected 200, got %d", resp.StatusCode)
     }
     _ = resp.Body.Close()
   })
 
   t.Run("Nil resolver falls back safely", func(t *testing.T) {
     mcpServer := NewMCPServer("test-server", "1.0.0")
-    // requires nil-guard in WithSessionIdManagerResolver
+    // requires nil-guard in WithSessionIdManagerResolver
     srv := NewTestStreamableHTTPServer(mcpServer, WithSessionIdManagerResolver(nil))
     defer srv.Close()
     resp, err := postJSON(srv.URL, initRequest)
     if err != nil {
       t.Fatalf("init failed: %v", err)
     }
     if resp.StatusCode != http.StatusOK {
       t.Fatalf("expected 200, got %d", resp.StatusCode)
     }
     _ = resp.Body.Close()
   })
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5088c93 and ded7b91.

📒 Files selected for processing (2)
  • server/streamable_http.go (9 hunks)
  • server/streamable_http_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Order imports: standard library first, then third-party, then local packages (goimports enforces this)
Follow Go naming conventions: exported identifiers in PascalCase; unexported in camelCase; acronyms uppercase (HTTP, JSON, MCP)
Error handling: return sentinel errors, wrap with fmt.Errorf("context: %w", err), and check with errors.Is/As
Prefer explicit types and strongly-typed structs; avoid using any except where protocol flexibility is required (e.g., Arguments any)
All exported types and functions must have GoDoc comments starting with the identifier name; avoid inline comments unless necessary
Functions that are handlers or long-running must accept context.Context as the first parameter
Ensure thread safety for shared state using sync.Mutex and document thread-safety requirements in comments
For JSON: use json struct tags with omitempty for optional fields; use json.RawMessage for flexible/deferred parsing

Files:

  • server/streamable_http_test.go
  • server/streamable_http.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Testing: use testify/assert and testify/require
Write table-driven tests using a tests := []struct{ name, ... } pattern
Go test files must end with _test.go

Files:

  • server/streamable_http_test.go
🧬 Code graph analysis (2)
server/streamable_http_test.go (2)
server/streamable_http.go (8)
  • InsecureStatefulSessionIdManager (1194-1197)
  • NewDefaultSessionIdManagerResolver (1166-1168)
  • StatelessSessionIdManager (1176-1176)
  • NewStreamableHTTPServer (175-192)
  • WithSessionIdManagerResolver (67-71)
  • WithSessionIdManager (58-62)
  • DefaultSessionIdManagerResolver (1161-1163)
  • WithStateLess (46-52)
server/server.go (1)
  • NewMCPServer (337-365)
server/streamable_http.go (3)
server/http_transport_options.go (1)
  • HTTPContextFunc (11-11)
util/logger.go (1)
  • Logger (8-11)
server/constants.go (1)
  • HeaderKeySessionID (5-5)
🔇 Additional comments (2)
server/streamable_http.go (1)

319-336: Resolver usage is applied consistently across POST/DELETE/sampling paths

Per-request resolution looks correct and maintains stateless/stateful semantics. Nice.

Also applies to: 621-626, 672-675

server/streamable_http_test.go (1)

1696-1769: Good unit coverage for DefaultSessionIdManagerResolver

Covers basic resolution, stateless behavior, multi-call consistency, and nil request. LGTM.

@aradyaron aradyaron changed the title Add SessionIdManagerResolver interface for request-based session management feat(mcp): Add SessionIdManagerResolver interface for request-based session management Oct 26, 2025
@aradyaron aradyaron closed this Oct 26, 2025
@aradyaron aradyaron reopened this Oct 26, 2025
@ezynda3 ezynda3 merged commit da6f722 into mark3labs:main Oct 30, 2025
4 of 5 checks passed
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.

feature: Having the HTTP Request context for The Session Management

2 participants