{"record":{"id":"ff57e8b9bc9200f8","repo":"microsoft/semantic-kernel","slug":"failed-to-enter-context-manager","errorCode":null,"errorMessage":"Failed to enter context manager.","messagePattern":"Failed to enter context manager\\.","errorType":"exception","errorClass":"FunctionExecutionException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/mcp.py","lineNumber":308,"sourceCode":"    async def __aexit__(\n        self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: Any\n    ) -> None:\n        \"\"\"Exit the context manager.\"\"\"\n        await self.close()\n\n    async def connect(self) -> None:\n        \"\"\"Connect to the MCP server.\"\"\"\n        ready_event = asyncio.Event()\n        try:\n            self._current_task = asyncio.create_task(self._inner_connect(ready_event))\n            await ready_event.wait()\n        except KernelPluginInvalidConfigurationError:\n            ready_event.clear()\n            raise\n        except Exception as ex:\n            ready_event.clear()\n            await self.close()\n            raise FunctionExecutionException(\"Failed to enter context manager.\") from ex\n\n    async def close(self) -> None:\n        \"\"\"Disconnect from the MCP server.\"\"\"\n        if self._stop_event:\n            # Signal the stop event, which asks the _inner_connect\n            # method to close the session with the exit stack\n            self._stop_event.set()\n        if self._current_task:\n            # After, the signal, we wait for it to close the exit stack.\n            await self._current_task\n            self._current_task = None\n        self.session = None\n\n    async def _inner_connect(self, ready_event: asyncio.Event) -> None:\n        if not self.session:\n            try:\n                transport = await self._exit_stack.enter_async_context(self.get_mcp_client())\n            except Exception as ex:","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/mcp.py#L290-L326","documentation":"Thrown by MCPPluginBase.connect (mcp.py:308) as a FunctionExecutionException, wrapping any exception during connect() that is NOT a KernelPluginInvalidConfigurationError. The connect() flow spawns _inner_connect as a task and waits on a ready_event; only config errors are re-raised verbatim, everything else (and event-wait failures) is wrapped here and forces a close().","triggerScenarios":"An asyncio.CancelledError or unexpected runtime error during ready_event.wait(); a failure inside _inner_connect that surfaces as a generic Exception rather than the dedicated config errors at mcp.py:329/345/352; double-connect races; the task being cancelled externally.","commonSituations":"Calling connect() concurrently from two coroutines; cancelling the connect task mid-handshake; an unhandled error in load_tools()/load_prompts() (which run after session init inside _inner_connect); event-loop closure during connect.","solutions":["Inspect the chained __cause__ (from ex) for the real underlying error before acting.","Ensure connect() is called exactly once and awaited fully; use the async context manager (async with plugin:) to avoid races.","If load_tools/load_prompts is the culprit, set load_tools=False/load_prompts=False and load manually after connect.","Avoid cancelling the connect task; if you must, expect this wrapper."],"exampleFix":"# before\nawait plugin.connect()  # may race if called twice\n\n# after (use the context manager)\nasync with plugin:\n    result = await plugin.call_tool(\"foo\", arg=1)","handlingStrategy":"try-catch","validationCode":"# ensure single, awaited connect before use\nasync def safe_connect(plugin) -> bool:\n    if plugin.session is not None:\n        return True\n    await plugin.connect()\n    return plugin.session is not None","typeGuard":"def plugin_is_connected(plugin) -> bool:\n    return getattr(plugin, \"session\", None) is not None","tryCatchPattern":"from semantic_kernel.exceptions.function_exceptions import FunctionExecutionException\n\ntry:\n    async with plugin:\n        await plugin.call_tool(\"foo\")\nexcept FunctionExecutionException as ex:\n    if \"Failed to enter context manager\" in str(ex):\n        # inspect ex.__cause__; likely asyncio cancellation or a runtime error\n        log.error(\"connect failed: %r\", ex.__cause__)","preventionTips":["Use the async context manager (async with plugin:) so connect/close are deterministic.","Never call connect() concurrently from two coroutines on the same plugin.","Do not cancel the connect task mid-handshake.","If load_tools/load_prompts errors during connect, disable them and load manually."],"tags":["mcp","connection","asyncio","context-manager","error-wrapping"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}