Skip to content

feat: stateless HTTP mode to eliminate session drops (#180)#232

Merged
cmeans merged 2 commits into
mainfrom
feat/stateless-http-mode
Apr 9, 2026
Merged

feat: stateless HTTP mode to eliminate session drops (#180)#232
cmeans merged 2 commits into
mainfrom
feat/stateless-http-mode

Conversation

@cmeans-claude-dev
Copy link
Copy Markdown
Contributor

@cmeans-claude-dev cmeans-claude-dev Bot commented Apr 9, 2026

Summary

  • New AWARENESS_STATELESS_HTTP=true env var enables stateless HTTP transport — fresh MCP transport per request, no session tracking
  • Eliminates the entire class of session drop / 409 Conflict bugs (fix: stale MCP sessions return 409 Conflict after server restart #180) — no sessions means nothing to go stale
  • Auth unchanged — JWT Bearer token flows per-request, independent of MCP sessions
  • Session registry automatically skipped in stateless mode; stateful mode (default) still available
  • SDK-recommended pattern for production servers that don't need server-initiated push

Closes #180

QA

Prerequisites

  • pip install -e ".[dev]"
  • Deploy to test instance on alternate port (AWARENESS_PORT=8421)

Manual tests (via MCP tools)

Stateless mode:

    • Start with AWARENESS_STATELESS_HTTP=true
      Expected: logs show "Transport mode: stateless HTTP" and "Session registry: disabled"
    • Basic tool calls work without session
      get_briefing, remember, get_knowledge — all return valid results, no session ID in response headers
    • No 409 after restart
      Restarted instance, sent request with fake stale session ID — returned 200, not 409

Stateful mode (backward compat):
4. - [x] Start without AWARENESS_STATELESS_HTTP (or =false)
Stateful behavior unchanged, session ID returned in response headers, no stateless log messages

🤖 Generated with Claude Code

New AWARENESS_STATELESS_HTTP=true option creates a fresh MCP transport
per request with no session tracking. Eliminates the entire class of
session drop / 409 Conflict bugs since there are no sessions to go
stale. Auth still flows per-request via JWT Bearer token.

Session registry is automatically skipped in stateless mode. Stateful
mode (default) remains available for clients that need persistent
sessions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cmeans-claude-dev cmeans-claude-dev Bot added enhancement New feature or request Dev Active Developer is actively working on this PR; QA should not start labels Apr 9, 2026
@github-actions github-actions Bot added the Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA label Apr 9, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

7 tests total:
- 3 unit: config wiring, session registry skip, FastMCP setting
- 4 integration: tool call without session, no session ID in headers,
  stale session ID doesn't cause 409, concurrent requests succeed

Fix env var leak between integration test classes by cleaning up
AWARENESS_STATELESS_HTTP after stateless tests. README count: 754.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cmeans-claude-dev cmeans-claude-dev Bot added Ready for QA Dev work complete — QA can begin review and removed Dev Active Developer is actively working on this PR; QA should not start labels Apr 9, 2026
@github-actions github-actions Bot removed the Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA label Apr 9, 2026
@cmeans cmeans added QA Active QA is actively reviewing; Dev should not push changes and removed Ready for QA Dev work complete — QA can begin review labels Apr 9, 2026
@cmeans
Copy link
Copy Markdown
Owner

cmeans commented Apr 9, 2026

Adding QA Active — reviewing stateless HTTP mode.

Copy link
Copy Markdown
Owner

@cmeans cmeans left a comment

Choose a reason for hiding this comment

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

QA Review — Round 1

Clean feature. The implementation is minimal — one env var, one stateless_http= kwarg to FastMCP, and a guard in _wrap_with_session_registry. The tests are thorough: 4 unit tests + 4 integration tests covering the no-session, no-409, concurrent, and backward-compat paths.

Code review

Check Result
AWARENESS_STATELESS_HTTP parsed correctly (accepts "1", "true")
stateless_http=STATELESS_HTTP passed to FastMCP constructor
Session registry skipped in stateless mode
Log messages for mode identification
README: env var documented with description
README: SESSION_DATABASE_URL doc updated ("Ignored when stateless")
CHANGELOG: entry under [Unreleased] ### Added
README: 754 tests (verified locally)
CI all green

Manual test results (Docker QA instance)

# Test Result
1 Logs show stateless mode + session registry disabled
2 get_briefing, remember, get_knowledge — all pass, no session ID in headers
3 Restart + stale session ID → 200, not 409
4 Stateful mode — session ID returned, no stateless log messages
5 Stateful + session registry ⏭️ Already verified in PR #169 reviews

QA infrastructure cleaned up.

Test sufficiency

The integration tests cover the key scenarios well. test_no_409_after_restart is the most important — it proves the core value proposition. test_concurrent_stateless_requests with 5 parallel threads validates that per-request transports don't interfere. The unit tests cover the configuration wiring. No gaps identified.

Zero findings. Verdict: Pass — ready for signoff.

@cmeans cmeans added Ready for QA Signoff QA passed — ready for maintainer final review and merge and removed QA Active QA is actively reviewing; Dev should not push changes labels Apr 9, 2026
@cmeans
Copy link
Copy Markdown
Owner

cmeans commented Apr 9, 2026

Applying Ready for QA Signoff — stateless + stateful modes both verified on Docker QA instance, 754/754 tests pass, CI green, zero findings.

Copy link
Copy Markdown
Owner

@cmeans cmeans left a comment

Choose a reason for hiding this comment

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

LGTM

@cmeans cmeans added QA Approved Manual QA testing completed and passed and removed Ready for QA Signoff QA passed — ready for maintainer final review and merge labels Apr 9, 2026
@cmeans cmeans merged commit 10af406 into main Apr 9, 2026
43 checks passed
@cmeans cmeans deleted the feat/stateless-http-mode branch April 9, 2026 21:48
cmeans pushed a commit that referenced this pull request Apr 10, 2026
6 bug-fix PRs since v0.16.1:
- #226 LazyStore thread safety (#164)
- #227 SQL template injection hardening (#165)
- #232 Stateless HTTP mode (#180)
- #233 GET /mcp intercept + request logger (#178)
- #234 delete_entry IDOR fix (#193)
- #236 RLS-safe opt-in cleanup (#179, #183)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cmeans-claude-dev cmeans-claude-dev Bot mentioned this pull request Apr 10, 2026
3 tasks
cmeans-claude-dev Bot added a commit that referenced this pull request Apr 10, 2026
6 bug-fix PRs since v0.16.1:
- #226 LazyStore thread safety (#164)
- #227 SQL template injection hardening (#165)
- #232 Stateless HTTP mode (#180)
- #233 GET /mcp intercept + request logger (#178)
- #234 delete_entry IDOR fix (#193)
- #236 RLS-safe opt-in cleanup (#179, #183)

Co-authored-by: cmeans-claude-dev[bot] <3223881+cmeans-claude-dev[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request QA Approved Manual QA testing completed and passed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: stale MCP sessions return 409 Conflict after server restart

1 participant