A very simple server fails to shut down on a signal if it processed at least one request:
❯ python test-server.py --port=8085
INFO: Started server process [216035]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8085 (Press CTRL+C to quit)
INFO: 127.0.0.1:55188 - "GET /sse HTTP/1.1" 200 OK
INFO: 127.0.0.1:55192 - "POST /messages/?session_id=e690de9733914d09aebf2b0e8c78191c HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:55192 - "POST /messages/?session_id=e690de9733914d09aebf2b0e8c78191c HTTP/1.1" 202 Accepted
INFO: 127.0.0.1:55192 - "POST /messages/?session_id=e690de9733914d09aebf2b0e8c78191c HTTP/1.1" 202 Accepted
Processing request of type CallToolRequest
^CINFO: Shutting down
INFO: Waiting for background tasks to complete. (CTRL+C to force quit)
The expected behaviour would be:
❯ python test-server.py --port=8085
INFO: Started server process [216006]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8085 (Press CTRL+C to quit)
^CINFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [216006]
Here is the code for both the server and the client.
What do I miss?
the server
import click
import sys
from pydantic import Field
from mcp.server.fastmcp import FastMCP
@click.command()
@click.option("--port", default=8085, help="Port to listen", type=int)
def main(port: int):
mcp = FastMCP(
"mcp-echo-tool",
debug=True,
log_level="INFO",
port=port,
)
@mcp.tool(name="echo")
async def echo_tool(string: str = Field(description="A string to echo back")) -> str:
"""Echoes back the input string"""
return string
mcp.run(transport='sse')
return 0
if __name__ == "__main__":
sys.exit(main())
and the client
import asyncio
import click
import sys
from mcp.client.session import ClientSession
from mcp.client.sse import sse_client
async def client(url, string):
async with sse_client(url) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("echo", {"string": string})
print(result.content)
@click.command()
@click.option('--url', default='http://localhost:8085', help='MCP Server URL', type=str)
@click.argument('string', type=str)
def main(url: str, string: str):
asyncio.run(client(url, string))
if __name__ == "__main__":
sys.exit(main())
Reactions are currently unavailable
A very simple server fails to shut down on a signal if it processed at least one request:
The expected behaviour would be:
Here is the code for both the server and the client.
What do I miss?
the server
import click import sys from pydantic import Field from mcp.server.fastmcp import FastMCP @click.command() @click.option("--port", default=8085, help="Port to listen", type=int) def main(port: int): mcp = FastMCP( "mcp-echo-tool", debug=True, log_level="INFO", port=port, ) @mcp.tool(name="echo") async def echo_tool(string: str = Field(description="A string to echo back")) -> str: """Echoes back the input string""" return string mcp.run(transport='sse') return 0 if __name__ == "__main__": sys.exit(main())and the client
import asyncio import click import sys from mcp.client.session import ClientSession from mcp.client.sse import sse_client async def client(url, string): async with sse_client(url) as (read, write): async with ClientSession(read, write) as session: await session.initialize() result = await session.call_tool("echo", {"string": string}) print(result.content) @click.command() @click.option('--url', default='http://localhost:8085', help='MCP Server URL', type=str) @click.argument('string', type=str) def main(url: str, string: str): asyncio.run(client(url, string)) if __name__ == "__main__": sys.exit(main())