feat(controller): make MCP stateless mode configurable via KAGENT_MCP_STATELESS#1854
feat(controller): make MCP stateless mode configurable via KAGENT_MCP_STATELESS#1854onematchfox wants to merge 1 commit into
KAGENT_MCP_STATELESS#1854Conversation
…P_STATELESS` The `StreamableHTTPHandler` stores sessions in memory and returns 404 for any `Mcp-Session-Id` it doesn't recognise. With multiple replicas, a request may land on a different replica than the one that created the session. `KAGENT_MCP_STATELESS=true` enables stateless mode, which skips session-ID validation and creates a temporary session per request, making any replica capable of handling any request. This enables use of the MCP when the network path does/can not provide sticky session routing based on the `Mcp-Session-Id` header. Server->client initiated streaming is disabled in stateless mode, but that is not needed here — both tools are request/response and A2A conversation continuity is carried in the `context_id` field of the `invoke_agent` input. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds an opt-in configuration to run the controller’s MCP StreamableHTTPHandler in stateless mode to better support multi-replica deployments where requests may not have sticky routing by session header.
Changes:
- Register a new controller env var
KAGENT_MCP_STATELESSto toggle MCP stateless behavior. - When enabled, construct the MCP HTTP handler with
StreamableHTTPOptions{Stateless: true}.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| go/core/pkg/env/kagent.go | Adds KAGENT_MCP_STATELESS env var registration and description under controller-scoped env vars. |
| go/core/internal/mcp/mcp_handler.go | Wires the env var into MCP handler creation by passing StreamableHTTPOptions to the MCP SDK handler. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var httpOpts *mcpsdk.StreamableHTTPOptions | ||
| if env.KagentMCPStateless.Get() { | ||
| httpOpts = &mcpsdk.StreamableHTTPOptions{Stateless: true} | ||
| } |
supreme-gg-gg
left a comment
There was a problem hiding this comment.
this lgtm overall. I agree with copilot we should add test coverage though. Perhaps not e2e test since it could be flaky and also make CI run even longer, I think integration test that spins up two handlers (simulating two replicas) and verifying stateful fails while stateless succeeds would be good
EItanya
left a comment
There was a problem hiding this comment.
I wonder if we should actually just make it stateless by default always. Realistically this will not be stateful without a bunch more work on our side
The
StreamableHTTPHandlerstores sessions in memory and returns404for anyMcp-Session-Idit doesn't recognise. With multiple controller replicas, a request may land on a different replica than the one that created the session.KAGENT_MCP_STATELESS=trueenables stateless mode, which skips session-ID validation and creates a temporary session per request, making any replica capable of handling any request. This enables use of the MCP when the network path does/can not provide sticky session routing based on theMcp-Session-Idheader.Server->client initiated streaming is disabled in stateless mode, but that is not needed here — both tools are request/response and A2A conversation continuity is carried in the
context_idfield of theinvoke_agentinput.