Repository navigation
Resource tracker warning (leaked semaphores) with MCPServerStdio #618
Copy link
Copy link
Closed
Labels
Description
Debug information
- Agents SDK version: 0.0.12
- Python 3.13.1
Describe the bug
When using an external MCP plugin with the OpenAI Agents SDK (MCPServerStdio in this case), I consistently receive a resource_tracker: There appear to be XX leaked semaphore objects to clean up at shutdown warning message during the program's shutdown. The exact number of leaked objects (e.g., 24) varies.
Steps to reproduce
Use the following code snippet which initializes a custom OpenAI client and then attempts to run an agent configured with an MCPServerStdio plugin.
Code Snippet
import asyncio
from agents import Agent, Runner
from agents import set_default_openai_client, set_default_openai_api, set_tracing_disabled
from agents.mcp import MCPServerStdio
from openai import AsyncOpenAI
# --- Replace with your actual values ---
OPENAI_BASE_URL = "YOUR_CUSTOM_BASE_URL" # e.g., "http://localhost:11434/v1" or similar
OPENAI_API_KEY = "YOUR_API_KEY" # Can be "ollama" or similar if using local endpoint
MODEL_NAME = "YOUR_MODEL_NAME" # e.g., "llama3" or "gpt-4o"
# --- End of replacements ---
async def main():
# Create custom OpenAI client
custom_client = AsyncOpenAI(base_url=OPENAI_BASE_URL, api_key=OPENAI_API_KEY)
# Required configuration for using a custom OpenAI API endpoint
set_default_openai_api("chat_completions") # Or other API type if needed
set_default_openai_client(custom_client)
set_tracing_disabled(True) # Disable tracing if not needed
# Get Python executable path
current_dir = os.path.dirname(os.path.abspath(__file__))
python_executable = sys.executable
soc_push_script = os.path.join(current_dir, "plugins", "soc_push_script.py") # Assuming this script exists and works as an MCP plugin
# Initialize the MCP server plugin using MCPServerStdio
# Make sure soc_push_script.py implements the MCP protocol correctly
mcp_soc_push = MCPServerStdio(
name="soc_push_script",
params={
"command": python_executable,
"args": [soc_push_script],
})
# Run the agent with the MCP plugin
try:
async with mcp_soc_push as push_tool: # Use the plugin as a tool
agent = Agent(
name="test",
instructions='test',
model=MODEL_NAME,
mcp_servers=[push_tool], # Add the MCP tool to the agent's servers
)
print("Starting agent run...")
result = await Runner.run(starting_agent=agent, input='')
print("Agent run finished.")
print("Final Output:", result.final_output)
finally:
# Explicitly attempt cleanup if necessary, though the warning suggests leakage
print("Attempting cleanup (may not prevent warning)...")
# Specific MCP cleanup methods might be needed depending on implementation
pass # Add cleanup logic here if known
# Assuming this script is run directly
if __name__ == "__main__":
asyncio.run(main())Note: The soc_push_script.py file is not provided, but it is assumed to be a functional MCP plugin script that interacts via standard I/O.
Console Output
/usr/local/Cellar/python@3.13/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/multiprocessing/resource_tracker.py:276: UserWarning: resource_tracker: There appear to be 24 leaked semaphore objects to clean up at shutdown: {'/mp-t9hi4oa_', '/mp-pbo_pje7', '/mp-_1jipfl5', '/mp-04d4uokn', '/mp-jw_gfhjk', '/mp-8122t3qm', '/mp-tjg6llji', '/mp-75j5swhj', '/mp-oprtjvq9', '/mp-_9c_6tt4', '/mp-o6ld1gx6', '/mp-vfh4ncjt', '/mp-6pf__aj0', '/mp-h8x7h4uu', '/mp-_heqxtvk', '/mp-uvzgo0ft', '/mp-gqm7a9dj', '/mp-j09dabgf', '/mp-w30c1pxu', '/mp-4gzlcmxm', '/mp-b5004bcn', '/mp-d1l4chll', '/mp-we2hfv61', '/mp-t1hr16ma'}
warnings.warn(
Reactions are currently unavailable
Activity
weiguangli-io commentedon Feb 10, 2026
Opened PR #2461 to harden MCP stdio teardown by resetting session cleanup state (exit stack + server initialize result) and adding a reconnect regression test. Local lint/tests passed; details are in the PR description.
fix(mcp): suppress multiprocessing resource tracker semaphore leak wa…
fix(mcp): suppress resource_tracker semaphore warnings in MCPServerStdio
fix(mcp): close session write stream before exit stack unwind to prev…
fix(mcp): reset AsyncExitStack after cleanup for reconnect (openai#618)
fix(mcp): close session write stream before exit stack unwind to prev…
adityasingh2400 commentedon May 8, 2026
Investigation report on root cause and prior fix attempts
I spent time investigating this and want to consolidate findings for whoever picks it up next, since four PRs targeting this issue have already been closed unmerged (#2461, #2573, #2802, #2882). The pattern of rejections is informative.
The leak source is upstream, not in this SDK
The
/mp-XXXXsemaphores in the warning are POSIX named semaphores created by Python'smultiprocessing.synchronize.Semaphore(used internally bymultiprocessing.Pipe,Queue,Pool,Lock,Manager). They are not created byanyio.open_processorasyncio.create_subprocess_exec, which is whatmcp.client.stdio.stdio_clientactually uses.Two ways these end up registered with
resource_trackerin this scenario:multiprocessing(very common — many Python MCP servers do, transitively via tokenizers, transformers, torch, etc.). Whenstdio_clientkills the subprocess on cleanup without giving it a clean shutdown window, the child's resource tracker never gets the chance to unlink its semaphores.stdio_client'sfinallyblock documented at BrokenResourceError race condition in stdio_client cleanup when context exits quickly modelcontextprotocol/python-sdk#1960:read_stream.aclose()runs whilestdout_readeris still mid-send(), raisingBrokenResourceError(notClosedResourceError) — which escapes as anExceptionGroupand prevents orderly teardown. The fix PR Fix stdio_client BrokenResourceError race condition during shutdown modelcontextprotocol/python-sdk#2268 is open but unmerged.Why the four prior PRs were closed
self.exit_stack = AsyncExitStack()incleanup()or top ofconnect(). This addresses reconnection (a separate orthogonal bug), not the semaphore leak. @seratch correctly identified this as solving the wrong problem.session._write_streambeforeexit_stack.aclose()to give the child a clean stdin EOF before task cancellation. Closer to the actual root cause, but reaches intoClientSession's private attribute and was rejected as fragile / "needs substantial changes across the SDK".The path I'd recommend
A clean SDK-level fix has to either (a) wait for the upstream
mcplibrary to land modelcontextprotocol/python-sdk#2268 and then bump the lower bound, or (b) overrideMCPServerStdio.create_streams()with a wrapper that owns subprocess lifecycle explicitly — closing stdin, awaitingprocess.wait()with a timeout, and only then unwinding the inner streams. Option (b) is non-trivial because it duplicatesstdio_clientshutdown logic.A short-term mitigation that does hide the warning (without fixing the leak) is to set
PYTHONMULTIPROCESSING_FORCEFORK=1or to register anatexithandler that callsmultiprocessing.resource_tracker._resource_tracker.clear()— but this is a band-aid and shouldn't ship in the SDK.What I'm not doing
I'm declining to open a 5th speculative PR. The maintainer signal is clear: the fix needs upstream coordination (with the
mcplibrary) or a bigger refactor of_MCPServerWithClientSession's teardown contract. Anything narrower will look like the four already-closed attempts.If a maintainer wants to greenlight a specific direction (e.g., "yes, override
create_streamsand own the subprocess lifecycle in this SDK") I'm happy to implement it.seratch commentedon Aug 2, 2026
Thanks for the detailed investigation. I traced the current
MCPServerStdiopath and the prior fix attempts. The Agents SDK delegates stdio subprocess ownership and shutdown tomcp.stdio_client; the three exit-stack changes addressed reconnect state rather than reproducing this semaphore warning, while the private-stream approach would duplicate dependency internals.The MCP Python SDK has since reworked stdio shutdown in modelcontextprotocol/python-sdk#2773, and openai-agents-python #4106 is adding support for that MCP v2 path. I am closing this issue in favor of that upstream and dependency-integration work. If the same warning remains reproducible after MCP v2 support lands, please provide a complete MCP server script and exact package versions so we can determine whether a narrower Agents adapter bug remains.