[PR #8253] fix(mcp): close existing client before reassignment to prevent leaks #12676

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

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

State: closed
Merged: Yes


Summary

Fix memory leak in MCP client management where existing clients are orphaned when replaced.

Fixes #8257
Relates to #7261
Relates to #3013

Problem

In MCP.add() and the OAuth finishAuth() flow, when a new MCP client is created and assigned to s.clients[name], any existing client at that key is silently overwritten:

// Before (leaks existing client)
s.clients[name] = result.mcpClient

The old client is never closed, leaving:

  • Open connections/sockets
  • Active event listeners
  • Unreleased resources

This happens when:

  • Reconnecting to an MCP server
  • Completing OAuth flow for an already-connected server
  • Re-initializing MCP configuration

Solution

Check for and close existing clients before reassignment in both locations:

// Close existing client if present to prevent memory leaks
const existingClient = s.clients[name]
if (existingClient) {
  await existingClient.close().catch((error) => {
    log.error("Failed to close existing MCP client", { name, error })
  })
}
s.clients[name] = result.mcpClient

Changes

  • packages/opencode/src/mcp/index.ts: Added client cleanup in add() function
  • packages/opencode/src/mcp/index.ts: Added client cleanup in finishAuth() flow

Testing

  • Build passes for all platforms
  • Full test suite passes (652 tests, 0 failures)
  • Code-review verified to follow correct resource cleanup pattern
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/8253 **State:** closed **Merged:** Yes --- ## Summary Fix memory leak in MCP client management where existing clients are orphaned when replaced. Fixes #8257 Relates to #7261 Relates to #3013 ## Problem In `MCP.add()` and the OAuth `finishAuth()` flow, when a new MCP client is created and assigned to `s.clients[name]`, any existing client at that key is silently overwritten: ```typescript // Before (leaks existing client) s.clients[name] = result.mcpClient ``` The old client is never closed, leaving: - Open connections/sockets - Active event listeners - Unreleased resources This happens when: - Reconnecting to an MCP server - Completing OAuth flow for an already-connected server - Re-initializing MCP configuration ## Solution Check for and close existing clients before reassignment in both locations: ```typescript // Close existing client if present to prevent memory leaks const existingClient = s.clients[name] if (existingClient) { await existingClient.close().catch((error) => { log.error("Failed to close existing MCP client", { name, error }) }) } s.clients[name] = result.mcpClient ``` ## Changes - `packages/opencode/src/mcp/index.ts`: Added client cleanup in `add()` function - `packages/opencode/src/mcp/index.ts`: Added client cleanup in `finishAuth()` flow ## Testing - ✅ Build passes for all platforms - ✅ Full test suite passes (652 tests, 0 failures) - Code-review verified to follow correct resource cleanup pattern
yindo added the pull-request label 2026-02-16 18:17:34 -05:00
yindo closed this issue 2026-02-16 18:17:34 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#12676