fix(mcp): set session manager on non-OAuth HTTP MCP clients#793
fix(mcp): set session manager on non-OAuth HTTP MCP clients#793nick-stebbings wants to merge 2 commits intonearai:stagingfrom
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request resolves an issue where non-OAuth HTTP MCP clients were not correctly configured with a session manager, leading to a loss of per-session state on servers. By ensuring that a session manager is consistently applied during client initialization, this change guarantees that Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
The pull request introduces a set_session_manager method to the McpClient struct, enabling the attachment of a session manager for Streamable HTTP session tracking, and integrates this method into McpClient instantiation across src/app.rs, src/cli/mcp.rs, and src/extensions/manager.rs, along with a new unit test. Review comments suggest refactoring the set_session_manager into a builder-style with_session_manager method for more idiomatic Rust, which would simplify client instantiation at call sites and require updating the corresponding unit test.
Note: Security Review did not run due to the size of the PR.
nick-stebbings
left a comment
There was a problem hiding this comment.
All four review comments addressed in 3f7753c: changed set_session_manager(&mut self, ...) to with_session_manager(mut self, ...) -> Self builder pattern. All call sites updated to use chained builder syntax, test renamed to test_with_session_manager.
zmanian
left a comment
There was a problem hiding this comment.
Review: fix(mcp): set session manager on non-OAuth HTTP MCP clients
Clean bug fix. Non-OAuth MCP clients were missing Mcp-Session-Id tracking, causing stateful servers to silently lose session context between calls.
Strengths:
- Fix applied consistently to all three non-OAuth paths (app.rs, cli/mcp.rs, extensions/manager.rs)
- Good commit progression: initial fix with
set_session_manager()-> refactored to idiomaticwith_session_manager()builder pattern - Unit test added for the new method
No concerns. LGTM -- approve.
3f7753c to
7e14b01
Compare
The new `create_client_from_config()` factory correctly wires `session_manager` via `new_authenticated()` for OAuth paths, but the two non-OAuth fallbacks call `new_with_config()` without attaching a session manager. This means Streamable HTTP servers that don't require OAuth never get `Mcp-Session-Id` header tracking. Add `with_session_manager()` builder method to `McpClient` and call it in both non-OAuth branches of the factory. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7e14b01 to
4b054c4
Compare
zmanian
left a comment
There was a problem hiding this comment.
Re-review: fix(mcp): wire session manager on non-OAuth HTTP MCP clients
The latest commit (4b054c4) consolidates the fix into create_client_from_config() in factory.rs, which is the right approach since app.rs and extensions/manager.rs both go through the factory now. The with_session_manager() builder pattern is clean and idiomatic.
However, one call site was missed:
Missed call site: cli/mcp.rs
src/cli/mcp.rs line ~509 still creates a bare McpClient::new_with_config(server.clone()) without attaching a session manager in the non-OAuth else branch of ironclaw mcp test. This path does not go through create_client_from_config(). The session_manager local variable is created on line 489 but only used in the has_tokens branch. This is the same bug the PR is fixing, just in a different call site.
// cli/mcp.rs ~line 509 -- missing session manager
} else {
McpClient::new_with_config(server.clone()) // should chain .with_session_manager(session_manager)
};The PR description explicitly lists cli/mcp.rs as a fixed path, and the earlier commits (3f7753c) may have fixed it, but the latest force-pushed commit dropped that fix.
Session header handling
The Mcp-Session-Id header handling in build_request_headers() is correct per the Streamable HTTP spec -- it only adds the header when a session ID exists, and session creation happens during initialize().
Test coverage
The unit test for with_session_manager() is fine for the builder method itself, but there's no test for the factory's non-OAuth branches. A test that exercises create_client_from_config() with an HTTP server config (no secrets, no OAuth) and asserts session_manager.is_some() on the result would directly cover the bug being fixed.
Summary
The factory fix is correct but incomplete -- cli/mcp.rs still has the same bug. Fix that call site and this is good to merge.
Address review feedback from zmanian: - Fix missed call site in cli/mcp.rs non-OAuth else branch - Add has_session_manager() accessor for test assertions - Add factory regression test: non-OAuth HTTP path must have session manager attached Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nick-stebbings
left a comment
There was a problem hiding this comment.
Fixed in becfbc4:
-
cli/mcp.rsmissed call site — added.with_session_manager(session_manager)to the non-OAuth else branch (line 509). This path bypasses the factory so it needed the same treatment. -
Factory regression test — added
test_factory_non_oauth_http_has_session_manager: creates an HTTP config with no secrets (non-OAuth path), callscreate_client_from_config(), assertshas_session_manager()is true. -
has_session_manager()accessor — added toMcpClientfor test assertions without exposing the field.
zmanian
left a comment
There was a problem hiding this comment.
Both items from previous review addressed:
- Missed cli/mcp.rs call site -- Fixed. Non-OAuth else branch now chains
.with_session_manager(session_manager). - Factory regression test -- Added.
test_factory_non_oauth_http_has_session_managercovers the exact bug scenario through the factory path.
Clean has_session_manager() accessor for testability. Approved.
Note: Fork PR -- CI only ran classify/scope. Logic verified by diff review.
|
Replacement PR opened as #986 with the approved fix rebased onto current |
|
Superseded by #986, which has merged into staging. |
…) (nearai#986) * fix(mcp): attach session manager for non-OAuth HTTP clients (nearai#793) * style(mcp): format factory regression test (nearai#986)
…) (nearai#986) * fix(mcp): attach session manager for non-OAuth HTTP clients (nearai#793) * style(mcp): format factory regression test (nearai#986)
Summary
McpClient::new_with_config()creates a client withsession_manager: None.Non-OAuth HTTP MCP servers never get Streamable HTTP session tracking — the
client omits
Mcp-Session-Idheaders, so servers that maintain per-sessionstate silently lose it between calls.
The authenticated path (
new_authenticated) already wires the session manager.This fix adds
set_session_manager()to all three non-OAuth fallback sites:app.rs: startup MCP client initialization (both with/without secrets store)cli/mcp.rs:ironclaw mcp testcommandextensions/manager.rs: hot-reload MCP activationAlso adds the
set_session_manager()public method toMcpClientand a unit test.Test plan
cargo check— cleancargo clippy --all --tests— zero warningscargo fmt -- --check— cleantest_set_session_manager🤖 Generated with Claude Code