Title: Bug: RuntimeError during cleanup on Windows – no running event loop · Issue #575 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: Bug: RuntimeError during cleanup on Windows – no running event loop · Issue #575 · modelcontextprotocol/python-sdk
X Title: Bug: RuntimeError during cleanup on Windows – no running event loop · Issue #575 · modelcontextprotocol/python-sdk
Description: Describe the bug When running the mcp client using uv run client.py on Windows, the client connects and runs correctly, but after the response is returned, a RuntimeError: no running event loop is thrown during shutdown. The error occurs...
Open Graph Description: Describe the bug When running the mcp client using uv run client.py on Windows, the client connects and runs correctly, but after the response is returned, a RuntimeError: no running event loop is ...
X Description: Describe the bug When running the mcp client using uv run client.py on Windows, the client connects and runs correctly, but after the response is returned, a RuntimeError: no running event loop is ...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/issues/575
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Bug: RuntimeError during cleanup on Windows – no running event loop","articleBody":"---\n\n### **Describe the bug** \nWhen running the `mcp` client using `uv run client.py` on **Windows**, the client connects and runs correctly, but after the response is returned, a `RuntimeError: no running event loop` is thrown during shutdown. The error occurs inside the `terminate_windows_process` function in `win32.py`, which uses `anyio.fail_after()` after the event loop has already closed.\n\n---\n\n### **To Reproduce**\nSteps to reproduce the behavior:\n1. Use the following Python code to create a minimal MCP client that connects to a server and runs a tool-enabled Groq chat query:\n\n```python\n# save this as `client.py`\nimport asyncio\nimport json\nfrom contextlib import AsyncExitStack\nimport os\nfrom typing import Any, Dict, List, Optional\n\nimport nest_asyncio\nfrom dotenv import load_dotenv\nfrom mcp import ClientSession, StdioServerParameters\nfrom mcp.client.stdio import stdio_client\nfrom groq import AsyncGroq\n\nnest_asyncio.apply()\nload_dotenv()\n\nclass MCPGroqClient:\n def __init__(self, model: str = \"llama-3.3-70b-versatile\"):\n self.session: Optional[ClientSession] = None\n self.exit_stack = AsyncExitStack()\n self.groq_client = AsyncGroq(api_key=os.getenv(\"GROQ_API_KEY\"))\n self.model = model\n self.stdio: Optional[Any] = None\n self.write: Optional[Any] = None\n\n async def connect_to_server(self, server_script_path: str = \"server.py\"):\n server_params = StdioServerParameters(command=\"python\", args=[server_script_path])\n stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))\n self.stdio, self.write = stdio_transport\n self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))\n await self.session.initialize()\n tools_result = await self.session.list_tools()\n print(\"\\nConnected to server with tools:\")\n for tool in tools_result.tools:\n print(f\" - {tool.name}: {tool.description}\")\n\n async def get_mcp_tools(self) -\u003e List[Dict[str, Any]]:\n tools_result = await self.session.list_tools()\n return [\n {\n \"type\": \"function\",\n \"function\": {\n \"name\": tool.name,\n \"description\": tool.description,\n \"parameters\": tool.inputSchema,\n },\n }\n for tool in tools_result.tools\n ]\n\n async def process_query(self, query: str) -\u003e str:\n tools = await self.get_mcp_tools()\n response = await self.groq_client.chat.completions.create(\n model=self.model,\n messages=[{\"role\": \"user\", \"content\": query}],\n tools=tools,\n tool_choice=\"auto\",\n )\n assistant_message = response.choices[0].message\n messages = [{\"role\": \"user\", \"content\": query}, assistant_message]\n\n if assistant_message.tool_calls:\n for tool_call in assistant_message.tool_calls:\n result = await self.session.call_tool(\n tool_call.function.name,\n arguments=json.loads(tool_call.function.arguments),\n )\n messages.append({\n \"role\": \"tool\",\n \"tool_call_id\": tool_call.id,\n \"content\": result.content[0].text,\n })\n\n final_response = await self.groq_client.chat.completions.create(\n model=self.model,\n messages=messages,\n tools=tools,\n tool_choice=\"none\",\n )\n return final_response.choices[0].message.content\n\n return assistant_message.content\n\n async def cleanup(self):\n await self.exit_stack.aclose()\n\nasync def main():\n client = MCPGroqClient()\n await client.connect_to_server()\n query = \"What is our company's vacation policy?\"\n print(f\"\\nQuery: {query}\")\n response = await client.process_query(query)\n print(f\"\\nResponse: {response}\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n2. Set your environment variable `GROQ_API_KEY`.\n3. Start the server with a valid tool (like `knowledge_base`).\n4. Run the client using:\n ```bash\n uv run client.py\n ```\n5. Observe the traceback at shutdown related to `RuntimeError: no running event loop`.\n\n---\n\n### **Expected behavior** \nThe client should shut down gracefully **without throwing exceptions** after processing a response.\n\n---\n\n### **Screenshots / Traceback**\n```bash\nException ignored in: \u003casync_generator object stdio_client at 0x000002025AE0EFC0\u003e\nTraceback (most recent call last):\n File \"C:\\Program Files\\Python312\\Lib\\asyncio\\tasks.py\", line 314, in __step_run_and_handle_result\n result = coro.send(None)\n ^^^^^^^^^^^^^^^\nRuntimeError: async generator ignored GeneratorExit\n\nException ignored in: \u003ccoroutine object terminate_windows_process at 0x000002025AF5F3E0\u003e\nTraceback (most recent call last):\n File \"...\\Lib\\site-packages\\mcp\\client\\stdio\\win32.py\", line 105, in terminate_windows_process\n with anyio.fail_after(2.0):\n File \"C:\\Program Files\\Python312\\Lib\\contextlib.py\", line 158, in __exit__\n self.gen.throw(value)\n File \"...\\Lib\\site-packages\\anyio\\_core\\_tasks.py\", line 112, in fail_after\n with get_async_backend().create_cancel_scope(\n File \"...\\Lib\\site-packages\\anyio\\_backends\\_asyncio.py\", line 456, in __exit__\n if current_task() is not self._host_task:\n ^^^^^^^^^^^^^^\nRuntimeError: no running event loop\n```\n\n---\n\n### **Desktop (please complete the following information):**\n- **OS:** Windows 11 \n- **Python Version:** 3.12 \n- **MCP Version:** [insert version] \n- **AnyIO Version:** [insert version] \n- **Terminal:** Windows PowerShell \n- **Command Used:** `uv run client.py`\n\n---\n\n### **Additional context** \n- This issue seems to be a **Windows-specific async shutdown bug**.\n- Happens when `anyio.fail_after()` is used after the event loop is already closed.\n- Suggest adding a check before using async context tools during shutdown, such as:\n ```python\n if asyncio.get_event_loop().is_running():\n with anyio.fail_after(2.0):\n ...\n ```\n- Or use `try/except RuntimeError` to suppress it gracefully.\n\n---\n","author":{"url":"https://github.com/Dadiya-Harsh","@type":"Person","name":"Dadiya-Harsh"},"datePublished":"2025-04-23T18:26:36.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/575/python-sdk/issues/575"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:a4c83bec-483e-56b3-c06b-1ea073cff2cd |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E212:B6152:A347CC:EC3186:6A579807 |
| html-safe-nonce | 50c2268c718f2a61631991ad89ac62b2e367b50c208a3241cba4bed256fc9092 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFMjEyOkI2MTUyOkEzNDdDQzpFQzMxODY6NkE1Nzk4MDciLCJ2aXNpdG9yX2lkIjoiNjQwNjA2ODE5NjIxNTMzMDgyMyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 4d2932221a5a02df6f29c562128db8389514a8f6695b0ac4fecae26fbd21c9b1 |
| hovercard-subject-tag | issue:3014919425 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/modelcontextprotocol/python-sdk/575/issue_layout |
| twitter:image | https://opengraph.githubassets.com/b11fef2af559d9dfd5d7ba21c044200cab8d74fa047b58edc9db2a9e37c5d1c8/modelcontextprotocol/python-sdk/issues/575 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/b11fef2af559d9dfd5d7ba21c044200cab8d74fa047b58edc9db2a9e37c5d1c8/modelcontextprotocol/python-sdk/issues/575 |
| og:image:alt | Describe the bug When running the mcp client using uv run client.py on Windows, the client connects and runs correctly, but after the response is returned, a RuntimeError: no running event loop is ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | Dadiya-Harsh |
| hostname | github.com |
| expected-hostname | github.com |
| None | a87fc68e9bdf22e1c7e48ac6a60b98882f4bb103314b3f26b3460c61fc5441ae |
| turbo-cache-control | no-preview |
| go-import | github.com/modelcontextprotocol/python-sdk git https://github.com/modelcontextprotocol/python-sdk.git |
| octolytics-dimension-user_id | 182288589 |
| octolytics-dimension-user_login | modelcontextprotocol |
| octolytics-dimension-repository_id | 862584018 |
| octolytics-dimension-repository_nwo | modelcontextprotocol/python-sdk |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 862584018 |
| octolytics-dimension-repository_network_root_nwo | modelcontextprotocol/python-sdk |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | a2198d0212ed703af207673eb4d0868d4f867a5b |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width