Skip to content

ClientSessionGroup leaves old tools after disconnecting a re-registered session #3713

Open

Description

@inanna-malick

Initial Checks

Release line

2.x (current stable)

Description

Registering the same caller-owned session twice can leave tools behind after disconnect. The first catalog contains old; the second contains only new. Both connect_with_session() calls return successfully. After disconnect_from_server(), group.sessions == [] but group.tools still contains old.

I expected disconnect to remove every tool registered through that session. A deliberate rejection of repeated registration or a coherent refresh would both be reasonable; this report concerns the accepted repeat leaving stale entries.

The aggregation path replaces the session's reverse index with the latest catalog while updating the aggregate dictionary, which retains the earlier entries. Disconnect then removes only the names in the replacement index. This differs from #3490's transport leak after a rejected connection and #3384's empty-catalog failure.

Example Code

Self-contained failing test using public Client, connect_with_session(), and disconnect_from_server() APIs. Test-only branch; no production changes.

After checking out that branch:

uv run --frozen pytest tests/client/test_session_group.py::test_disconnect_removes_all_tools_after_same_session_reregistration -q

Python & MCP Python SDK

Python 3.14.7, Linux x86_64. Reproduces on latest stable 2.3.0 (2118f14f8a19bc158d8a1cf90af58d85d187f849) and main 754254c08fe1c3eda18b69da3d336106fe8d72d6. The other 12 session-group tests pass against each source revision.

AI-assisted investigation and test reproduction, with a human in the loop.

Activity

  1. added
    bugSomething isn't working
    v2Affects the v2 line (2.x on main)
    v1Affects the v1.x maintenance line
    on Oct 14, 2026
  2. abhay-2108 commented on Oct 15, 2026

    @abhay-2108

    Hi! @inanna-malick
    I'd like to work on this issue. Could you please assign it to me? I'll reproduce it with the provided test case and put up a PR shortly.

  3. abhay-2108 commented on Oct 15, 2026

    @abhay-2108

    I investigated the root cause and verified the reproduction:

    In ClientSessionGroup._aggregate_components(), when an existing session is re-registered via connect_with_session(), self._sessions[session] is overwritten with the new catalog's names while self._tools and self._tool_to_session retain the previous entries. On disconnect_from_server(), only the names in the current _sessions[session] index are removed, leaving earlier tools orphaned in group.tools.

    I've tested and prepared a coherent refresh approach in #3716:

    1. Evicts the session's previously registered components from _tools, _resources, _prompts, and _tool_to_session before aggregating the new catalog.
    2. Excludes the session's own existing registrations during duplicate collision checks so re-registering does not trigger false collisions against itself, while still guarding against collisions with other sessions.
    3. Guards del self._session_exit_stacks[session] with if session in self._session_exit_stacks: to handle caller-owned empty-catalog registrations safely without KeyError.
    4. Documents this refresh behavior in docs/client/session-groups.md.
    5. Includes comprehensive invariant unit tests in tests/client/test_session_group.py achieving 100% statement and branch coverage on session_group.py.

    Would appreciate being assigned to this issue so CI can run and #3716 can be reviewed when capacity allows. Thanks!

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingv1Affects the v1.x maintenance linev2Affects the v2 line (2.x on main)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions