Skip to content

fix(transport): single Server instance causes response routing to wrong clients#141

Merged
polaz merged 10 commits intomainfrom
feat/#138-fixtransport-single-server-instance-causes-respons
Jan 23, 2026
Merged

fix(transport): single Server instance causes response routing to wrong clients#141
polaz merged 10 commits intomainfrom
feat/#138-fixtransport-single-server-instance-causes-respons

Conversation

@polaz
Copy link
Copy Markdown
Member

@polaz polaz commented Jan 23, 2026

Summary

  • Replaces single global Server instance with per-session Server instances via new SessionManager class
  • Each SSE/StreamableHTTP connection gets its own isolated Server, preventing _transport overwrite that caused responses to be routed to wrong clients
  • Adds automatic session cleanup: idle timeout (30min default) + disconnect-based cleanup for SSE
  • Fixes ERR_HTTP_HEADERS_SENT by checking res.headersSent before sending error responses
  • sendToolsListChangedNotification() now broadcasts to all active sessions

Test plan

  • All 3495 existing unit tests pass
  • New SessionManager unit tests (19 tests): per-session isolation, cleanup, broadcast, shutdown
  • Updated server.test.ts (30 tests): verifies session manager integration
  • Lint clean, build succeeds
  • Manual testing with concurrent Claude Code agents connecting simultaneously
  • Verify SSE clients receive responses after another client connects
  • Verify session cleanup after disconnect (no orphaned sessions)

Closes #138

…routing to wrong clients

A single global Server instance caused `_transport` to be overwritten on each
new connection, routing responses to the most recently connected client instead
of the requesting one. This resulted in clients hanging indefinitely in
multi-session deployments.

Introduces SessionManager that creates isolated Server instances per session
with automatic idle timeout cleanup (30min default), disconnect-based cleanup
for SSE, and broadcast notifications across all active sessions.

Also fixes ERR_HTTP_HEADERS_SENT by checking res.headersSent before error responses.

Closes #138
Copilot AI review requested due to automatic review settings January 23, 2026 13:53
@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 23, 2026

📊 Test Coverage Report

Overall Coverage: 91.57%

Coverage Details

Metric Percentage
Statements 91.57%
Branches 83.54%
Functions 81.26%
Lines 91.98%

Coverage Report: View detailed coverage report

This report was generated automatically from your PR changes.

@codecov
Copy link
Copy Markdown

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 97.24771% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/session-manager.ts 97.14% 1 Missing and 1 partial ⚠️
src/server.ts 97.43% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

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

This pull request fixes a critical bug where a single global MCP Server instance caused response routing failures when multiple clients connected concurrently. The fix replaces the global server with per-session Server instances managed by a new SessionManager class.

Changes:

  • Introduces SessionManager class to manage per-session Server instances, preventing transport routing conflicts
  • Adds automatic session cleanup with configurable idle timeout (30 minutes default) and disconnect-based cleanup for SSE
  • Improves error handling by checking res.headersSent before sending error responses to prevent ERR_HTTP_HEADERS_SENT errors
  • Updates sendToolsListChangedNotification to broadcast to all active sessions via SessionManager

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/session-manager.ts New SessionManager class that creates isolated Server instances per session, manages session lifecycle, cleanup, and broadcasts notifications
src/server.ts Removes global Server instance, integrates SessionManager, adds session cleanup on disconnect, improves error handling with headersSent checks, updates graceful shutdown
tests/unit/session-manager.test.ts Comprehensive unit tests (19 tests) for SessionManager covering isolation, cleanup, broadcast, and edge cases
tests/unit/server.test.ts Updated tests (30 tests) to verify SessionManager integration, mocks sessionManager instead of global server

polaz added 4 commits January 23, 2026 16:12
- Pre-generate session ID and await createSession before
  handleWithContext to prevent race condition in StreamableHTTP
- Remove redundant handlersInitialized if-else in SessionManager
- Wrap sendToolsListChangedNotification in try/catch to prevent
  error propagation to callers
- Add tests for onsessioninitialized/closed callbacks, OAuth
  session association, graceful shutdown, SSE disconnect cleanup,
  and headersSent guards
Copy link
Copy Markdown

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

…heck

- Wrap SSE createSession calls in try/catch with proper error response
- Add schemaModeDetected flag to prevent setDetectedSchemaMode race condition
- Add duplicate sessionId guard in createSession (warns and closes existing)
- Add tests for all new behaviors
@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 23, 2026

Test Coverage Report

Overall Coverage: 93.18%

Metric Percentage
Statements 92.69%
Branches 84.21%
Functions 82.48%
Lines 93.18%

View detailed coverage report

polaz added 3 commits January 23, 2026 17:24
… transport cases

determineTransportMode() only returns "stdio" or "dual", making the
standalone "sse" and "streamable-http" switch cases dead code that
cannot be tested. The "dual" mode already provides both transports.
Copy link
Copy Markdown

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Move the duplicate session guard to the beginning of createSession(),
before creating a new Server instance and registering handlers.
This avoids wasteful resource allocation when a duplicate is detected.
Copy link
Copy Markdown

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@polaz polaz merged commit 86f5317 into main Jan 23, 2026
21 checks passed
@polaz polaz deleted the feat/#138-fixtransport-single-server-instance-causes-respons branch January 23, 2026 15:56
sw-release-bot bot pushed a commit that referenced this pull request Jan 23, 2026
## [6.31.1](v6.31.0...v6.31.1) (2026-01-23)

### Bug Fixes

* **transport:** single Server instance causes response routing to wrong clients ([#141](#141)) ([86f5317](86f5317)), closes [#138](#138)
@sw-release-bot
Copy link
Copy Markdown

🎉 This PR is included in version 6.31.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(transport): single Server instance causes response routing to wrong clients

3 participants