Skip to content

Return JSON-RPC errors for expired sessions#4426

Merged
amirejaz merged 2 commits intostacklok:mainfrom
gkatz2:fix/json-rpc-session-not-found-4425
Mar 30, 2026
Merged

Return JSON-RPC errors for expired sessions#4426
amirejaz merged 2 commits intostacklok:mainfrom
gkatz2:fix/json-rpc-session-not-found-4425

Conversation

@gkatz2
Copy link
Copy Markdown
Contributor

@gkatz2 gkatz2 commented Mar 30, 2026

Summary

  • ToolHive's proxies returned plain-text HTTP errors for expired or unknown sessions, preventing MCP clients from detecting session expiry and recovering automatically
  • Replace all session-not-found error responses across all three proxy types with JSON-RPC errors (HTTP 404, code -32001), matching the MCP TypeScript SDK reference server convention
  • Fix the transparent proxy's incorrect HTTP 400 status code (should be 404 per MCP spec)

Fixes #4425

Type of change

  • Bug fix

Test plan

  • Unit tests (task test)
  • Linting (task lint-fix)
  • Manual testing (describe below)

Built from the fix branch and started MCP servers exercising all three proxy types. Verified with curl that requests with a bogus Mcp-Session-Id return HTTP 404 with Content-Type: application/json and "code":-32001 in the JSON-RPC error body:

  • Streamable HTTP proxy (stdio server, default proxy mode)
  • Transparent proxy (container server with HTTP backend)
  • SSE proxy (stdio server, --proxy-mode sse)

Changes

File Change
pkg/transport/session/jsonrpc_errors.go New shared JSON-RPC error utilities (WriteNotFound, NotFoundResponse, NotFoundBody)
pkg/transport/session/jsonrpc_errors_test.go Unit tests for the new utilities
pkg/transport/proxy/streamable/streamable_proxy.go Replace 3 plain-text session-not-found errors with session.WriteNotFound
pkg/transport/proxy/transparent/transparent_proxy.go Replace plain-text error with session.NotFoundResponse, fix status 400→404
pkg/transport/proxy/httpsse/http_proxy.go Replace plain-text error with session.WriteNotFound
pkg/transport/proxy/streamable/streamable_proxy_spec_test.go Add body assertions to existing test + 3 new tests for uncovered paths
pkg/transport/proxy/transparent/backend_routing_test.go Update status assertion 400→404, add JSON-RPC body assertions
pkg/transport/proxy/httpsse/http_proxy_test.go Update assertion to check for JSON-RPC error format

Does this introduce a user-facing change?

MCP clients that implement session recovery (checking for HTTP 404 with JSON-RPC error code -32001) will now be able to automatically recover from session expiry without requiring a client restart.

Generated with Claude Code

ToolHive's proxies returned plain-text HTTP errors for expired or
unknown sessions. MCP clients like Claude Code rely on receiving
HTTP 404 with a JSON-RPC error body containing code -32001 to
trigger automatic session recovery. The plain-text responses
bypassed this detection, leaving connections broken until the
user manually restarted their client.

Fixes stacklok#4425

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Greg Katz <gkatz@indeed.com>
@github-actions github-actions bot added size/M Medium PR: 300-599 lines changed and removed size/M Medium PR: 300-599 lines changed labels Mar 30, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 30, 2026

Codecov Report

❌ Patch coverage is 70.21277% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.49%. Comparing base (feef6ed) to head (7d90dd6).
⚠️ Report is 14 commits behind head on main.

Files with missing lines Patch % Lines
...g/transport/proxy/transparent/transparent_proxy.go 7.69% 12 Missing ⚠️
pkg/transport/session/jsonrpc_errors.go 93.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4426      +/-   ##
==========================================
- Coverage   69.50%   69.49%   -0.02%     
==========================================
  Files         486      487       +1     
  Lines       50017    50044      +27     
==========================================
+ Hits        34766    34776      +10     
- Misses      12570    12584      +14     
- Partials     2681     2684       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The revive linter requires exported constants to have doc
comments. The blank line between the two constants in the
const block means they need individual comments.

Signed-off-by: Greg Katz <gkatz@indeed.com>
@github-actions github-actions bot added size/M Medium PR: 300-599 lines changed and removed size/M Medium PR: 300-599 lines changed labels Mar 30, 2026
@amirejaz amirejaz merged commit c465888 into stacklok:main Mar 30, 2026
39 of 40 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Medium PR: 300-599 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session expiry breaks MCP connections instead of allowing client recovery

2 participants