You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
MCP Server with Python on Claude Desktop Never Exits #526
Describe the bug
When using an MCP Server (stdio) installed in Claude Desktop with the command uv run mcp istall server_test.py and then closing Claude Desktop, the process mcp.exe remains active in Task Manager on Windows 10.
If you open and close Claude Desktop again, the number of lingering mcp.exe processes increases.
To Reproduce
Steps to reproduce the behavior:
Install server_test.py using the command above.
Open Claude Desktop and ensure the MCP server is correctly set up.
Close Claude Desktop and check Task Manager for mcp.exe or python.exe still running.
Repeat steps 2 and 3 to see the processes being duplicated.
Expected behavior
The process should exit cleanly when Claude Desktop is closed.
I tested the MCP server provided by the C# SDK, and it exits correctly — so the issue might be specific to the Python implementation or FastMCP.
This also happens on macOS (probably any other unix-like as well). It also means that the cleanup section of any lifetime context manager never gets run so any resources the server is using never get cleaned up either.
I "fixed" this for the moment by noticing that the parent process id for the server becomes 1 when Claude Desktop exits. So I set up a thread that woke every few seconds to check to see if it has been orphaned and then kills itself. This is on a Mac:
# Set up a background threadimportthreadingimporttimedefbackground_task():
"""Task to be run periodically in the background."""whileTrue:
try:
logger.info("Background task running...")
importosifos.getppid() <100:
logger.info("We have been orphaned.")
os._exit(0)
exceptExceptionase:
logger.error(f"Error in background task: {str(e)}")
# Sleep for 5 secondstime.sleep(5)
# Create and start the background threadbg_thread=threading.Thread(target=background_task, daemon=True)
bg_thread.start()
This works reliably enough. os._exit() is a bit vicious, but sys.exit() didn't actually cause the program to quit so I had to go for something deadlier.
I "fixed" this for the moment by noticing that the parent process id for the server becomes 1 when Claude Desktop exits. So I set up a thread that woke every few seconds to check to see if it has been orphaned and then kills itself. This is on a Mac:
# Set up a background thread
import threading
import time
def background_task():
"""Task to be run periodically in the background."""
while True:
try:
logger.info("Background task running...")
import os
if os.getppid() < 100:
logger.info("We have been orphaned.")
os._exit(0)
except Exception as e:
logger.error(f"Error in background task: {str(e)}")
# Sleep for 5 seconds
time.sleep(5)
# Create and start the background thread
bg_thread = threading.Thread(target=background_task, daemon=True)
bg_thread.start()
This works reliably enough. os._exit() is a bit vicious, but sys.exit() didn't actually cause the program to quit so I had to go for something deadlier.
Thank you for your sharing. Do you mean to run this process monitoring program to control the mcp-server to exit?
Thank you for your sharing. Do you mean to run this process monitoring program to control the mcp-server to exit?
This is not a standalone program; rather it sits inside the startup code for my MCP server. The thread just runs along happily in the background of the MCP server, looking to see if the Claude Desktop that started it is still there (that is, the parent process id is still Claude's) and, when it notices that Claude has quit (and its parent process id becomes 1), it forces the server to exit.
I noticed that this problem only happens to me on the Mac because it seems like Claude Desktop keeps background processes running on Windows so when you start it again you don't end up with yet another MCP server running.
The stdio server exits once its stdin reaches EOF (src/mcp/server/stdio.py), and the stdio lifecycle puts closing that stream on the client, so a server outliving Claude Desktop or Cline means its stdin never saw EOF — a client-side lifecycle issue rather than an SDK one (same shape as #2231). Closing as part of a general backlog cleanup following the v2 release. If it's still relevant, feel free to reopen.
Activity
[-]MCP Server with Python on Claude Desktop Never Exit[/-][+]MCP Server with Python on Claude Desktop Never Exits[/+]byi8220 commentedon Apr 23, 2025
+1, I'm also seeing this using Claude Desktop. Could be an issue on Claude Desktop's side, but I don't have any ideas.
Could be quite annoying if one's MCP tools are long running and not properly cancelled when the user exits.
Hollow-cat commentedon Apr 27, 2025
I also have the problem in Vscode Cline Extension.
hutchisr commentedon May 7, 2025
This also happens on macOS (probably any other unix-like as well). It also means that the cleanup section of any lifetime context manager never gets run so any resources the server is using never get cleaned up either.
cmcguinness commentedon May 9, 2025
I "fixed" this for the moment by noticing that the parent process id for the server becomes 1 when Claude Desktop exits. So I set up a thread that woke every few seconds to check to see if it has been orphaned and then kills itself. This is on a Mac:
This works reliably enough. os._exit() is a bit vicious, but sys.exit() didn't actually cause the program to quit so I had to go for something deadlier.
Hollow-cat commentedon May 9, 2025
Thank you for your sharing. Do you mean to run this process monitoring program to control the mcp-server to exit?
cmcguinness commentedon May 9, 2025
This is not a standalone program; rather it sits inside the startup code for my MCP server. The thread just runs along happily in the background of the MCP server, looking to see if the Claude Desktop that started it is still there (that is, the parent process id is still Claude's) and, when it notices that Claude has quit (and its parent process id becomes 1), it forces the server to exit.
I noticed that this problem only happens to me on the Mac because it seems like Claude Desktop keeps background processes running on Windows so when you start it again you don't end up with yet another MCP server running.
fix: cancel in-flight handlers when transport closes in server.run()
fix(server): exit when MCP parent process disappears (#217)
maxisbey commentedon Aug 10, 2026
The stdio server exits once its stdin reaches EOF (
src/mcp/server/stdio.py), and the stdio lifecycle puts closing that stream on the client, so a server outliving Claude Desktop or Cline means its stdin never saw EOF — a client-side lifecycle issue rather than an SDK one (same shape as #2231). Closing as part of a general backlog cleanup following the v2 release. If it's still relevant, feel free to reopen.AI Disclaimer