Skip to content

Resource tracker warning (leaked semaphores) with MCPServerStdio #618

Closed

Description

@al0ne

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(

Activity

  1. deleted a comment from on Jul 26, 2025
  2. added and removed
    bugSomething isn't working
    on Jan 29, 2026
  3. weiguangli-io commented on Feb 10, 2026

    @weiguangli-io
    Contributor

    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.

  4. added a commit that references this issue on Mar 11, 2026
    5d9faf2
  5. added a commit that references this issue on Mar 19, 2026
    98eda1f
  6. added a commit that references this issue on Mar 28, 2026
    4468bf6
  7. added a commit that references this issue on Apr 14, 2026
    b5e5ffa
  8. adityasingh2400 commented on May 8, 2026

    @adityasingh2400
    Contributor

    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-XXXX semaphores in the warning are POSIX named semaphores created by Python's multiprocessing.synchronize.Semaphore (used internally by multiprocessing.Pipe, Queue, Pool, Lock, Manager). They are not created by anyio.open_process or asyncio.create_subprocess_exec, which is what mcp.client.stdio.stdio_client actually uses.

    Two ways these end up registered with resource_tracker in this scenario:

    1. The MCP server subprocess imports multiprocessing (very common — many Python MCP servers do, transitively via tokenizers, transformers, torch, etc.). When stdio_client kills the subprocess on cleanup without giving it a clean shutdown window, the child's resource tracker never gets the chance to unlink its semaphores.
    2. A race in stdio_client's finally block documented at BrokenResourceError race condition in stdio_client cleanup when context exits quickly modelcontextprotocol/python-sdk#1960: read_stream.aclose() runs while stdout_reader is still mid-send(), raising BrokenResourceError (not ClosedResourceError) — which escapes as an ExceptionGroup and 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

    The path I'd recommend

    A clean SDK-level fix has to either (a) wait for the upstream mcp library to land modelcontextprotocol/python-sdk#2268 and then bump the lower bound, or (b) override MCPServerStdio.create_streams() with a wrapper that owns subprocess lifecycle explicitly — closing stdin, awaiting process.wait() with a timeout, and only then unwinding the inner streams. Option (b) is non-trivial because it duplicates stdio_client shutdown logic.

    A short-term mitigation that does hide the warning (without fixing the leak) is to set PYTHONMULTIPROCESSING_FORCEFORK=1 or to register an atexit handler that calls multiprocessing.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 mcp library) 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_streams and own the subprocess lifecycle in this SDK") I'm happy to implement it.

  9. seratch commented on Aug 2, 2026

    @seratch
    Member

    Thanks for the detailed investigation. I traced the current MCPServerStdio path and the prior fix attempts. The Agents SDK delegates stdio subprocess ownership and shutdown to mcp.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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions