Skip to content

Conversation

@Anko59
Copy link
Contributor

@Anko59 Anko59 commented Nov 21, 2025

  • Add clientInfo and clientCapabilities fields to streamableHttpSession struct
  • Implement GetClientInfo, SetClientInfo, GetClientCapabilities, SetClientCapabilities methods
  • Add SessionWithClientInfo interface declaration
  • Enable client capability checking for StreamableHTTP transport in stateful mode

Description

This PR implements the missing SessionWithClientInfo interface for streamableHttpSession, enabling servers using StreamableHTTP transport to check client capabilities before performing operations like sampling.

The streamableHttpSession struct was missing the implementation of the SessionWithClientInfo interface, creating an inconsistency with sseSession and preventing servers from accessing client capabilities in stateful mode.

Fixes #639

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • MCP spec compatibility implementation
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Performance improvement
  • Tests only (no functional changes)
  • Other (please describe):

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

MCP Spec Compliance

  • This PR implements a feature defined in the MCP specification
  • Link to relevant spec section: Client capabilities
  • Implementation follows the specification exactly

Additional Information

Problem

The original issue occurred when servers using StreamableHTTP transport with stateful sessions (WithStateLess(false)) could not access client capabilities that were set during initialization. This prevented proper capability checking before operations like RequestSampling().

Solution

The implementation follows the exact same pattern as sseSession for consistency:

  • Uses atomic.Value for thread-safe storage
  • Implements all four required methods of SessionWithClientInfo
  • Maintains backward compatibility (no breaking changes)

Testing

  • Added comprehensive test covering interface implementation and functionality
  • Verified client capabilities persist across requests in stateful mode
  • All existing tests pass (no regressions)
  • Race condition tests pass

This enables the use case described in the original issue:

if clientSession, ok := session.(SessionWithClientInfo); ok {
    clientCapabilities := clientSession.GetClientCapabilities()
    return clientCapabilities.Sampling != nil, nil
}```

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added capability to store and retrieve client information and capabilities per session.

* **Tests**
  * Added test coverage for client information and capabilities storage and retrieval functionality.

<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

- Add clientInfo and clientCapabilities fields to streamableHttpSession struct
- Implement GetClientInfo, SetClientInfo, GetClientCapabilities, SetClientCapabilities methods
- Add SessionWithClientInfo interface declaration
- Enable client capability checking for StreamableHTTP transport in stateful mode

Fixes mark3labs#639
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

Walkthrough

Added client information and capabilities storage to streamableHttpSession with getter and setter methods. Implemented the SessionWithClientInfo interface by adding clientInfo and clientCapabilities atomic.Value fields, along with four public accessor methods to retrieve and update stored values.

Changes

Cohort / File(s) Summary
Session Client Info Implementation
server/streamable_http.go
Added clientInfo and clientCapabilities atomic.Value fields to store per-session client data. Implemented four public methods (GetClientInfo(), SetClientInfo(), GetClientCapabilities(), SetClientCapabilities()) and registered interface compliance via type assertion for SessionWithClientInfo.
Client Info Tests
server/streamable_http_client_info_test.go
New test file verifying that streamableHttpSession correctly implements the SessionWithClientInfo interface. Tests cover initial empty state retrieval and proper value persistence after setter calls for both client info and capabilities.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Verify atomic.Value usage patterns are consistent with existing code
  • Confirm interface compliance assertion aligns with SessionWithClientInfo contract
  • Validate test coverage for getter/setter round-trip behavior and initial states

Possibly related PRs

Suggested labels

area: sdk, type: bug

Suggested reviewers

  • ezynda3
  • pottekkat
  • robert-jackson-glean

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 title clearly and concisely describes the main change: implementing SessionWithClientInfo interface for streamableHttpSession.
Description check ✅ Passed The PR description follows the template with all required sections completed, including a clear problem statement, solution overview, testing details, and spec compliance reference.
Linked Issues check ✅ Passed The PR fully addresses issue #639 by implementing all four required methods (GetClientInfo, SetClientInfo, GetClientCapabilities, SetClientCapabilities) for streamableHttpSession using thread-safe atomic.Value storage.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the SessionWithClientInfo interface for streamableHttpSession as specified in issue #639; no unrelated modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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: 0

🧹 Nitpick comments (1)
server/streamable_http_client_info_test.go (1)

9-60: LGTM! Comprehensive test coverage.

The test properly verifies that streamableHttpSession implements SessionWithClientInfo, checks initial empty values, and validates the Set/Get roundtrips for both client info and capabilities.

As per coding guidelines, consider using testify/assert for more concise assertions:

+import (
+	"github.com/stretchr/testify/assert"
+)

 func TestStreamableHttpSessionImplementsSessionWithClientInfo(t *testing.T) {
 	// Create the session stores
 	toolStore := newSessionToolsStore()
 	resourceStore := newSessionResourcesStore()
 	templatesStore := newSessionResourceTemplatesStore()
 	logStore := newSessionLogLevelsStore()
 	
 	// Create a streamable HTTP session
 	session := newStreamableHttpSession("test-session", toolStore, resourceStore, templatesStore, logStore)
 	
 	// Verify it implements SessionWithClientInfo
 	var clientSession ClientSession = session
 	clientInfoSession, ok := clientSession.(SessionWithClientInfo)
-	if !ok {
-		t.Fatal("streamableHttpSession should implement SessionWithClientInfo")
-	}
+	assert.True(t, ok, "streamableHttpSession should implement SessionWithClientInfo")
 	
 	// Test GetClientInfo with no data set (should return empty)
 	clientInfo := clientInfoSession.GetClientInfo()
-	if clientInfo.Name != "" || clientInfo.Version != "" {
-		t.Errorf("expected empty client info, got %+v", clientInfo)
-	}
+	assert.Empty(t, clientInfo.Name)
+	assert.Empty(t, clientInfo.Version)
 	
 	// Test SetClientInfo and GetClientInfo
 	expectedClientInfo := mcp.Implementation{
 		Name:    "test-client",
 		Version: "1.0.0",
 	}
 	clientInfoSession.SetClientInfo(expectedClientInfo)
 	
 	actualClientInfo := clientInfoSession.GetClientInfo()
-	if actualClientInfo.Name != expectedClientInfo.Name || actualClientInfo.Version != expectedClientInfo.Version {
-		t.Errorf("expected client info %+v, got %+v", expectedClientInfo, actualClientInfo)
-	}
+	assert.Equal(t, expectedClientInfo.Name, actualClientInfo.Name)
+	assert.Equal(t, expectedClientInfo.Version, actualClientInfo.Version)
 	
 	// Test GetClientCapabilities with no data set (should return empty)
 	capabilities := clientInfoSession.GetClientCapabilities()
-	if capabilities.Sampling != nil || capabilities.Roots != nil {
-		t.Errorf("expected empty client capabilities, got %+v", capabilities)
-	}
+	assert.Nil(t, capabilities.Sampling)
+	assert.Nil(t, capabilities.Roots)
 	
 	// Test SetClientCapabilities and GetClientCapabilities
 	expectedCapabilities := mcp.ClientCapabilities{
 		Sampling: &struct{}{},
 	}
 	clientInfoSession.SetClientCapabilities(expectedCapabilities)
 	
 	actualCapabilities := clientInfoSession.GetClientCapabilities()
-	if actualCapabilities.Sampling == nil {
-		t.Errorf("expected sampling capability to be set")
-	}
+	assert.NotNil(t, actualCapabilities.Sampling)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ecc6d8f and fbc079e.

📒 Files selected for processing (2)
  • server/streamable_http.go (2 hunks)
  • server/streamable_http_client_info_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_client_info_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_client_info_test.go
🧠 Learnings (2)
📓 Common learnings
Learnt from: ezynda3
Repo: mark3labs/mcp-go PR: 461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.
📚 Learning: 2025-06-30T07:13:17.052Z
Learnt from: ezynda3
Repo: mark3labs/mcp-go PR: 461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.

Applied to files:

  • server/streamable_http_client_info_test.go
🧬 Code graph analysis (2)
server/streamable_http_client_info_test.go (2)
server/session.go (2)
  • ClientSession (12-21)
  • SessionWithClientInfo (66-76)
mcp/types.go (2)
  • Implementation (531-535)
  • ClientCapabilities (482-494)
server/streamable_http.go (2)
mcp/types.go (2)
  • Implementation (531-535)
  • ClientCapabilities (482-494)
server/session.go (1)
  • SessionWithClientInfo (66-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: coverage
🔇 Additional comments (3)
server/streamable_http.go (3)

979-980: LGTM! Thread-safe storage for client metadata.

The use of atomic.Value for clientInfo and clientCapabilities ensures thread-safe access across concurrent requests, which is essential for session data in HTTP transport handlers.


1058-1082: LGTM! Correct implementation of SessionWithClientInfo methods.

The getter methods properly handle uninitialized state by returning empty structs, and the use of type assertions provides defensive programming against potential type mismatches. The setter methods correctly use atomic.Value.Store() for thread-safe updates.


1089-1089: LGTM! Compile-time interface validation.

The interface assertion ensures that streamableHttpSession correctly implements SessionWithClientInfo at compile time, preventing accidental breakage of the interface contract.

@ezynda3 ezynda3 merged commit a27a793 into mark3labs:main Nov 22, 2025
6 of 8 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.

bug: streamableHttpSession missing GetClientCapabilities() implementation from SessionWithClientInfo interface

2 participants