fix(tests): convert create_mcp_client_session to asynccontextmanager

The multi-user-basic integration job was consistently failing with
`CancelledError: Cancelled via cancel scope ... by <async_generator_athrow>`
followed by a cascade of `anyio.ClosedResourceError` in every subsequent
test. Root cause: `create_mcp_client_session` was declared as an async
generator driven by `async for session in ...:`, so Python's generator
finalizer (`aclose`) ran under pytest-asyncio's cleanup task instead of
the task that owned the nested `streamablehttp_client` cancel scope.
anyio then raised when the inner task group saw its scope being exited
from a foreign task, leaving the memory object streams half-closed and
poisoning the rest of the session.

Switching to `@asynccontextmanager` + `async with ... as session:` makes
`__aenter__`/`__aexit__` run in the frame that owns the context manager,
satisfying anyio's structured concurrency requirements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-04-15 12:58:47 +02:00
co-authored by Claude Opus 4.6
parent 9b6b554155
commit 3935f45be8
5 changed files with 50 additions and 48 deletions
@@ -145,11 +145,11 @@ async def test_astrolabe_plotly_visualization_with_basic_auth(
logger.info(f"Authorization result: {auth_result}")
# Create MCP client session as alice - all MCP operations inside this block
async for alice_mcp_client in create_mcp_client_session(
async with create_mcp_client_session(
url="http://localhost:8003/mcp",
headers={"Authorization": auth_header},
client_name="Alice BasicAuth MCP",
):
) as alice_mcp_client:
# Phase 3: Get initial indexed count
initial_sync = await alice_mcp_client.call_tool(
"nc_get_vector_sync_status", {}
@@ -355,11 +355,11 @@ The visualization should show this document as a point in PCA-reduced space.
# Cleanup note if not already cleaned (create new client for cleanup)
if note_id:
try:
async for cleanup_client in create_mcp_client_session(
async with create_mcp_client_session(
url="http://localhost:8003/mcp",
headers={"Authorization": auth_header},
client_name="Cleanup MCP",
):
) as cleanup_client:
delete_response = await cleanup_client.call_tool(
"nc_notes_delete_note", {"note_id": note_id}
)