Repository navigation
RuntimeError: Attempted to exit cancel scope in a different task than it was entered in with AsyncExitStack #79
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Describe the bug
I am pushing the stdio_client and ClientSession onto an AsyncExitStack to avoid needing to wrap everyting in with statements. My client will have multiple simultaneous instances of different ClientSessions, so I wanted a manager class to handle cleaning up the session when it is GC'd. My plan was to run a task in the manager classes __del__ method to clean up, e.g. asyncio.create_task(self.exit_stack.aclose()).
However this raises RuntimeError: Attempted to exit cancel scope in a different task than it was entered in
To Reproduce
uv run this script:
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "mcp",
# ]
# ///
import asyncio
from contextlib import AsyncExitStack
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main() -> None:
exit_stack = AsyncExitStack()
server_params = StdioServerParameters(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
)
read, write = await exit_stack.enter_async_context(stdio_client(server_params))
session = await exit_stack.enter_async_context(ClientSession(read, write))
await session.initialize()
asyncio.create_task(exit_stack.aclose())
if __name__ == "__main__":
asyncio.run(main())Expected behavior
Clean shutdown.
Logs
(node:63152) ExperimentalWarning: CommonJS module /opt/homebrew/lib/node_modules/npm/node_modules/debug/src/node.js is loading ES Module /opt/homebrew/lib/node_modules/npm/node_modules/supports-color/index.js using require().
Support for loading ES Module in require() is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Secure MCP Filesystem Server running on stdio
Allowed directories: [ '/tmp' ]
unhandled exception during asyncio.run() shutdown
task: <Task finished name='Task-6' coro=<AsyncExitStack.aclose() done, defined at /Users/aw/.local/share/uv/python/cpython-3.10.15-macos-aarch64-none/lib/python3.10/contextlib.py:654> exception=RuntimeError('Attempted to exit cancel scope in a different task than it was entered in')>
Traceback (most recent call last):
File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/mcp/client/stdio.py", line 128, in stdio_client
yield read_stream, write_stream
File "/Users/aw/.local/share/uv/python/cpython-3.10.15-macos-aarch64-none/lib/python3.10/contextlib.py", line 697, in __aexit__
cb_suppress = await cb(*exc_details)
File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/mcp/shared/session.py", line 122, in __aexit__
return await self._task_group.__aexit__(exc_type, exc_val, exc_tb)
File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 769, in __aexit__
if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__):
File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 433, in __exit__
raise RuntimeError(
RuntimeError: Attempted to exit cancel scope in a different task than it was entered in
During handling of the above exception, another exception occurred:
+ Exception Group Traceback (most recent call last):
| File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 763, in __aexit__
| raise BaseExceptionGroup(
| exceptiongroup.ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 767, in __aexit__
| raise exc_val
| File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 741, in __aexit__
| await _wait(self._tasks)
| File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 706, in _wait
| await waiter
| asyncio.exceptions.CancelledError
|
| During handling of the above exception, another exception occurred:
|
| Traceback (most recent call last):
| File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/mcp/client/stdio.py", line 128, in stdio_client
| yield read_stream, write_stream
| File "/Users/aw/.local/share/uv/python/cpython-3.10.15-macos-aarch64-none/lib/python3.10/contextlib.py", line 697, in __aexit__
| cb_suppress = await cb(*exc_details)
| File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/mcp/shared/session.py", line 122, in __aexit__
| return await self._task_group.__aexit__(exc_type, exc_val, exc_tb)
| File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 769, in __aexit__
| if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__):
| File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 433, in __exit__
| raise RuntimeError(
| RuntimeError: Attempted to exit cancel scope in a different task than it was entered in
+------------------------------------
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/aw/.local/share/uv/python/cpython-3.10.15-macos-aarch64-none/lib/python3.10/contextlib.py", line 656, in aclose
await self.__aexit__(None, None, None)
File "/Users/aw/.local/share/uv/python/cpython-3.10.15-macos-aarch64-none/lib/python3.10/contextlib.py", line 714, in __aexit__
raise exc_details[1]
File "/Users/aw/.local/share/uv/python/cpython-3.10.15-macos-aarch64-none/lib/python3.10/contextlib.py", line 697, in __aexit__
cb_suppress = await cb(*exc_details)
File "/Users/aw/.local/share/uv/python/cpython-3.10.15-macos-aarch64-none/lib/python3.10/contextlib.py", line 217, in __aexit__
await self.gen.athrow(typ, value, traceback)
File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/mcp/client/stdio.py", line 122, in stdio_client
async with (
File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 769, in __aexit__
if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__):
File "/Users/aw/Library/Caches/uv/archive-v0/bkm4-HGL-Ma8SIqOuzaOM/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 433, in __exit__
raise RuntimeError(
RuntimeError: Attempted to exit cancel scope in a different task than it was entered in
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity
rectalogic commentedon Nov 28, 2024
Looks like an
anyioissue and this is probably not the correct approach, closing.docshun commentedon Mar 21, 2025
I met the same problem, how did you solve it
WikiHkz commentedon Apr 1, 2025
I met the same problem, how did you solve it?
fuhuiking commentedon Apr 4, 2025
I met the same problem, how did you solve it?
rectalogic commentedon Apr 4, 2025
Solve it by not doing this
asyncio.create_task(exit_stack.aclose())liudonghua123 commentedon Apr 7, 2025
I have the similar problems when trying to extract the session creation into a separate module.
Run it with
python openai_function_calling_with_mcp.py.And If I changed
initializeof mcp_client to useasync with AsyncExitStack() as stack, then no problems.npkanaka commentedon May 15, 2025
Just checking if there are any plans to address the
RuntimeErrorwhen exitingAsyncExitStackacross tasks.