modelcontextprotocol / modelcontextprotocol/python-sdk
FastMCP server with SSE transport fails to shut down on a signal
Nessuno ha ancora preso questa issue.
- Lingua principale
- Python
- Stelle
- 24.3k
- Fork
- 4k
- Merge medio
- 1g 1h
- PR unite (30g)
- 31
Descrizione
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())
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Riproduci il comportamento di arresto con il server e il client FastMCP SSE forniti, verificando prima che una richiesta sia stata elaborata prima di inviare il segnale. Traccia quindi il ciclo di vita del server FastMCP SSE e il relativo percorso di arresto di Uvicorn; il lavoro è completato quando il processo raggiunge l’arresto dell’applicazione e termina senza richiedere un secondo segnale.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- python
- Ambito
- api, backend
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Attiva
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 48/100