Initial Checks
Description
Dear developpers,
I am developing with MCP SDK Python on Windows. I noticed that the resource cleanup process of my local process defined inside the lifespan is not executed at all. To investigate the issue, I tested with the minimal code below and found that the code after the yield statement is never executed, regardless of whether an error occurs or not.
I haven’t been able to test this on platforms other than Windows or with the SSE transport.
"""agent_runner.pyA minimum code to use MCP server.Please run this file."""importosimportsysimportasyncioimportloggingfromdotenvimportload_dotenvfromopenaiimportAsyncOpenAIfromagentsimportAgent, Runner, OpenAIChatCompletionsModelfromagents.mcpimportMCPServerStdio, MCPServerStdioParamsload_dotenv() # loading OPENAI_API_KEYlogging.basicConfig(level=logging.INFO)
logger=logging.getLogger("agent_runner")
# disable library loggerslogging.getLogger('mcp').setLevel(logging.ERROR)
logging.getLogger('httpx').setLevel(logging.ERROR)
asyncdefmain():
# Launch MCP serverparams=MCPServerStdioParams(
command=sys.executable,
args=[os.path.join(os.path.dirname(__file__), "srv_stdio.py")],
env={},
encoding="utf-8"
)
asyncwithMCPServerStdio(params=params, name="MCP tool") asmcp_server:
logger.info("4. MCP stdio server running")
# Create agentagent=Agent(
name="AgentWithMCP",
instructions="Answer with using tools.",
model=OpenAIChatCompletionsModel(model="gpt-4", openai_client=AsyncOpenAI()),
mcp_servers=[mcp_server]
)
prompt="Please reverse the word 'hello'."logger.info(f" PROMPT: {prompt}")
result=awaitRunner.run(agent, input=prompt)
logger.info(f" FINAL OUTPUT: {result.final_output}")
if__name__=="__main__":
logger.info("1. Starting program...")
asyncio.run(main())
logger.info("8. Program terminated.")"""srv_stdio.pyA minimum code to show ignoring after "yield" in lifetime.Please put this file on the same folder as "agent_runner.py"."""from __future__ importannotationsas_annotationsimportosimportsysimportloggingfromcollections.abcimportAsyncIteratorfromcontextlibimportasynccontextmanagerfrommcp.server.fastmcpimportFastMCPfrommcp.server.lowlevel.serverimportServer, LifespanResultT, RequestTlogging.basicConfig(level=logging.INFO)
logger=logging.getLogger("stdio server")
# disable library loggerslogging.getLogger('mcp').setLevel(logging.ERROR)
logging.getLogger('httpx').setLevel(logging.ERROR)
ifsys.platform=="win32"andos.environ.get('PYTHONIOENCODING') isNone:
sys.stdin.reconfigure(encoding="utf-8")
sys.stdout.reconfigure(encoding="utf-8")
sys.stderr.reconfigure(encoding="utf-8")
@asynccontextmanagerasyncdeflifespan(server: Server[LifespanResultT, RequestT]) ->AsyncIterator[object]:
logger.info('3. Launching Server...')
try:
yield {}
finally:
logger.info('6. Terminating Server ''(Want to release my resources here).') # not shownmcp=FastMCP(
"EchoMCPServer",
lifespan=lifespan,
)
@mcp.tool()defecho(msg: str) ->str:
"""Make the passed string reversed."""logger.info(f"5. [echo] called with msg='{msg}'")
returnmsg[::-1]
if__name__=="__main__":
logger.info("2. Starting MCP server...")
mcp.run()
logger.info("7. MCP server terminated.") # not shownThe outputs missing "6. Terminating Server ~" and "7. MCP server terminated.".
INFO:agent_runner:1. Starting program...
INFO:stdio server:2. Starting MCP server...
INFO:stdio server:3. Launching Server...
INFO:agent_runner:4. MCP stdio server running
INFO:agent_runner: PROMPT: Please reverse the word 'hello'.
INFO:stdio server:5. [echo] called with msg='olleh'
INFO:agent_runner: FINAL OUTPUT: The reverse of 'hello' is 'olleh'.
INFO:agent_runner:8. Program terminated.
I suspected that this issue might be due to the process being forcibly terminated when exiting the with block in MCPServerStdio. Upon investigation, I found that modifying the following section allows the sample code to correctly display "6. Terminating Server ~" and "7. MCP server terminated.", and the cleanup process is executed as intended.
# mcp/client/stdio/win32.py102-process.terminate()
102+os.kill(process.pid, signal.CTRL_C_EVENT)
This change seems to resolve the issue on my end, but do you think it could be helpful for improving the MCP SDK overall?
Example Code
Python & MCP Python SDK
Python 3.10
mcp 1.9.4
openai-agents 0.0.17
Initial Checks
Description
Dear developpers,
I am developing with MCP SDK Python on Windows. I noticed that the resource cleanup process of my local process defined inside the
lifespanis not executed at all. To investigate the issue, I tested with the minimal code below and found that the code after theyieldstatement is never executed, regardless of whether an error occurs or not.I haven’t been able to test this on platforms other than Windows or with the SSE transport.
The outputs missing "6. Terminating Server ~" and "7. MCP server terminated.".
I suspected that this issue might be due to the process being forcibly terminated when exiting the
withblock inMCPServerStdio. Upon investigation, I found that modifying the following section allows the sample code to correctly display "6. Terminating Server ~" and "7. MCP server terminated.", and the cleanup process is executed as intended.This change seems to resolve the issue on my end, but do you think it could be helpful for improving the MCP SDK overall?
Example Code
Python & MCP Python SDK