[PR #8413] fix(mcp): abort hanging connections to non-standard servers #12731

Open
opened 2026-02-16 18:17:37 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/8413

State: open
Merged: No


Issue

Fixes #8406

Problem

When connecting to non-standard MCP servers, OpenCode can hang indefinitely if the server returns HTTP 200 but:

  • Sends malformed SSE stream
  • Never completes MCP initialize handshake
  • Stalls during message exchange

The existing withTimeout wrapper rejects the promise but doesn't cancel the underlying network request, leaving connections hanging.

Solution

Add AbortController support to remote MCP transports using native Web APIs:

  1. Created AbortController instances for each transport (StreamableHTTP, SSE)
  2. Passed signal to requestInit - uses native fetch abort mechanism
  3. Abort on timeout - setTimeout calls abort() at configured timeout
  4. Cleanup in all paths - ensures abort() called on error/timeout

Changes

  • Modified packages/opencode/src/mcp/index.ts:
    • Added AbortController instances for each transport
    • Passed signal to transport requestInit
    • Added timeout handler that calls abort()
    • Added cleanup in .catch() and error paths

Before: OpenCode hung indefinitely
After: Connection aborted after 30s timeout, clean error message

Implementation Notes

  • Follows team style: uses .catch() over try/catch
  • Minimal changes: ~27 lines added
  • Uses native Web APIs (AbortController/AbortSignal)
  • No new abstractions or files
  • Matches existing cleanup patterns (see #8253)
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/8413 **State:** open **Merged:** No --- ## Issue Fixes #8406 ## Problem When connecting to non-standard MCP servers, OpenCode can hang indefinitely if the server returns HTTP 200 but: - Sends malformed SSE stream - Never completes MCP initialize handshake - Stalls during message exchange The existing `withTimeout` wrapper rejects the promise but doesn't cancel the underlying network request, leaving connections hanging. ## Solution Add `AbortController` support to remote MCP transports using native Web APIs: 1. **Created AbortController instances** for each transport (StreamableHTTP, SSE) 2. **Passed `signal` to `requestInit`** - uses native fetch abort mechanism 3. **Abort on timeout** - `setTimeout` calls `abort()` at configured timeout 4. **Cleanup in all paths** - ensures `abort()` called on error/timeout ## Changes - Modified `packages/opencode/src/mcp/index.ts`: - Added `AbortController` instances for each transport - Passed `signal` to transport `requestInit` - Added timeout handler that calls `abort()` - Added cleanup in `.catch()` and error paths **Before:** OpenCode hung indefinitely **After:** Connection aborted after 30s timeout, clean error message ## Implementation Notes - Follows team style: uses `.catch()` over try/catch - Minimal changes: ~27 lines added - Uses native Web APIs (AbortController/AbortSignal) - No new abstractions or files - Matches existing cleanup patterns (see #8253)
yindo added the pull-request label 2026-02-16 18:17:37 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#12731