Skip to content

feat(controller): make MCP stateless mode configurable via KAGENT_MCP_STATELESS#1854

Open
onematchfox wants to merge 1 commit into
kagent-dev:mainfrom
onematchfox:feat-mcp-stateless
Open

feat(controller): make MCP stateless mode configurable via KAGENT_MCP_STATELESS#1854
onematchfox wants to merge 1 commit into
kagent-dev:mainfrom
onematchfox:feat-mcp-stateless

Conversation

@onematchfox
Copy link
Copy Markdown
Contributor

@onematchfox onematchfox commented May 12, 2026

The StreamableHTTPHandler stores sessions in memory and returns 404 for any Mcp-Session-Id it 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=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.

…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>
Copilot AI review requested due to automatic review settings May 12, 2026 14:04
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 12, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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_STATELESS to 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.

Comment on lines +106 to +109
var httpOpts *mcpsdk.StreamableHTTPOptions
if env.KagentMCPStateless.Get() {
httpOpts = &mcpsdk.StreamableHTTPOptions{Stateless: true}
}
Copy link
Copy Markdown
Contributor

@supreme-gg-gg supreme-gg-gg left a comment

Choose a reason for hiding this comment

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

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

@supreme-gg-gg supreme-gg-gg self-assigned this May 13, 2026
Copy link
Copy Markdown
Contributor

@EItanya EItanya left a comment

Choose a reason for hiding this comment

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

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

@supreme-gg-gg supreme-gg-gg removed their assignment May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants