Skip to content

Fix: Raise RuntimeError when ClientSession is used without context manager to prevent hangs#1849

Open
newbiehwang wants to merge 2 commits intomodelcontextprotocol:mainfrom
newbiehwang:fix/prevent-session-hang
Open

Fix: Raise RuntimeError when ClientSession is used without context manager to prevent hangs#1849
newbiehwang wants to merge 2 commits intomodelcontextprotocol:mainfrom
newbiehwang:fix/prevent-session-hang

Conversation

@newbiehwang
Copy link

Fixes #1564

Summary

This PR adds a runtime check to ClientSession to ensure it is being used within an asynchronous context manager (async with). If initialize() is called without entering the context, it now raises a clear RuntimeError instead of hanging indefinitely.

Motivation and Context

Currently, if a user attempts to call await session.initialize() without wrapping the session in an async with block, the program hangs indefinitely. This happens because the background receive loop (_receive_loop) is only started inside __aenter__.

This behavior leads to a frustrating debugging experience (deadlock) for developers. This change provides immediate feedback by enforcing correct usage of the session, preventing the deadlock.

How Has This Been Tested?

I reproduced the issue using the script provided in #1564.

  1. Before fix: The script hung indefinitely at await session.initialize().
  2. After fix: The script immediately raises RuntimeError: ClientSession must be used within an 'async with' block., as expected.
  3. Verified that normal usage (with async with) continues to work correctly.

Breaking Changes

No. This change is backward compatible for all correct usages. It only affects code that was previously incorrect and hanging.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

I implemented this using a simple state flag (_entered) to maintain backward compatibility without requiring significant architectural refactoring of the session class.

@newbiehwang newbiehwang force-pushed the fix/prevent-session-hang branch 5 times, most recently from 9068f71 to 17ba89f Compare January 17, 2026 01:37
@maxisbey maxisbey added bug Something isn't working P3 Nice to haves, rare edge cases labels Feb 10, 2026
…nager

This change ensures ClientSession is always used within an 'async with' block
by checking the context manager state before allowing operations that depend
on the background receive loop.

Without this check, calling initialize() outside of a context manager causes
the program to hang indefinitely because the _receive_loop task is only started
in __aenter__.

Changes:
- Add _entered flag to track context manager state
- Override __aenter__ and __aexit__ to manage the flag
- Add _check_is_active() method to enforce proper usage
- Call _check_is_active() in initialize() to prevent hangs
- Add test case for invalid usage

Fixes modelcontextprotocol#1564

Co-authored-by: Cursor <cursoragent@cursor.com>
@newbiehwang newbiehwang force-pushed the fix/prevent-session-hang branch from 48b3cc9 to 5f89866 Compare February 14, 2026 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working P3 Nice to haves, rare edge cases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stdio_client fails with BrokenResourceError during initialization

2 participants