Skip to content

Conversation

@OiPunk
Copy link
Contributor

@OiPunk OiPunk commented Feb 10, 2026

Summary

This PR hardens MCP server teardown by resetting _MCPServerWithClientSession state after cleanup().

Changes:

  • Reinitialize exit_stack to a fresh AsyncExitStack after every cleanup.
  • Clear server_initialize_result during cleanup, alongside session.
  • Add a regression test that verifies cleanup resets stack state and that reconnecting with the same MCPServerStdio instance works reliably.

Why

When cleanup reuses the same exit stack object across connection lifecycles, callbacks/references from prior connection attempts can be retained longer than needed, especially after recoverable cleanup errors. Resetting teardown state makes MCP stdio lifecycle behavior deterministic and reduces risk of lingering subprocess/stream resources.

Testing

  • uv run ruff check src/agents/mcp/server.py tests/mcp/test_connect_disconnect.py
  • env -u ALL_PROXY -u all_proxy -u HTTPS_PROXY -u https_proxy -u HTTP_PROXY -u http_proxy -u NO_PROXY -u no_proxy uv run pytest tests/mcp/test_connect_disconnect.py tests/mcp/test_server_errors.py -q
  • env -u ALL_PROXY -u all_proxy -u HTTPS_PROXY -u https_proxy -u HTTP_PROXY -u http_proxy -u NO_PROXY -u no_proxy uv run python -m trace --count --coverdir /tmp/openai_agents_618_trace --module pytest tests/mcp/test_connect_disconnect.py -q

Issue: #618

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47e48f8df3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# Always reset the exit stack so we don't retain callbacks/references from the
# previous connection. This keeps teardown deterministic and allows reconnecting
# with a fresh stack even if cleanup encountered recoverable errors.
self.exit_stack = AsyncExitStack()

Choose a reason for hiding this comment

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

P1 Badge Preserve teardown callbacks across cancelled cleanup

When cleanup() is cancelled during await self.exit_stack.aclose() (the CancelledError branch immediately above), the finally block still replaces self.exit_stack with a new stack. That discards any remaining callbacks from the partially-unwound original stack, so calling cleanup() again cannot finish closing the original MCP transport/session resources. In cancellation-heavy flows (timeouts, task-group cancellation), this can leave subprocess/stream resources orphaned.

Useful? React with 👍 / 👎.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant