modelcontextprotocol / modelcontextprotocol/python-sdk

ClientDisconnect returns HTTP 500

Aberta Para iniciantes
#1,648 6 comentários 1 reação 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

bug P2 ready for work
Linguagem predominante
Python
Estrelas
24.3k
Forks
4k
Merge médio
1d 1h
PRs com merge (30d)
31

Descrição

Initial Checks
Description

StreamableHTTPServerTransport._handle_post_request in mcp/server/streamable_http.py incorrectly handles starlette.requests.ClientDisconnect exceptions.

Current behavior:

  • Returns HTTP 500 (Internal Server Error)
  • Logs as ERROR with full traceback
  • Triggers production 5XX alerts

When This Occurs

ClientDisconnect happens during normal operations:

  • Network timeouts
  • User cancels request
  • Load balancer timeouts
  • Mobile client network interruptions

These are client-side events, not server failures.

Root Cause

File: src/mcp/server/streamable_http.py
Line: ~490-500

The broad except Exception handler catches ClientDisconnect and returns 500:

except Exception as err:  # pragma: no cover
    logger.exception("Error handling POST request")  # ❌ Logs as ERROR
    response = self._create_error_response(
        f"Error handling POST request: {err}",
        HTTPStatus.INTERNAL_SERVER_ERROR,  # ❌ Returns 500
        INTERNAL_ERROR,
    )
    await response(scope, receive, send)
Example Code

Reproduction

Steps

1. Install MCP SDK:

python3 -m venv venv
source venv/bin/activate
pip install mcp

2. Create minimal_mcp_server.py based on the documentation:

#!/usr/bin/env python3
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Bug Demo", json_response=True)

@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

3. Create test_client_disconnect.py:

#!/usr/bin/env python3
import socket
import time

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", 8000))

# Send headers claiming 100KB body
headers = (
    b"POST /mcp HTTP/1.1\r\n"
    b"Host: localhost\r\n"
    b"Content-Type: application/json\r\n"
    b"Content-Length: 100000\r\n"
    b"Accept: application/json, text/event-stream\r\n"
    b"\r\n"
)
sock.send(headers)

# Send partial body then disconnect
sock.send(b'{"jsonrpc": "2.0", "method": "initialize", "params": {')
time.sleep(0.05)
sock.close()

print("✓ Client disconnect simulated")

4. Run:

Terminal 1

python minimal_mcp_server.py

Terminal 2

python test_client_disconnect.py

5. Observe the bug in Terminal 1:

Error handling POST request
Traceback (most recent call last):
  File ".../mcp/server/streamable_http.py", line 351, in _handle_post_request
    body = await request.body()
           ^^^^^^^^^^^^^^^^^^^^
  File ".../starlette/requests.py", line 243, in body
    async for chunk in self.stream():
  File ".../starlette/requests.py", line 237, in stream
    raise ClientDisconnect()
starlette.requests.ClientDisconnect
Python & MCP Python SDK
Python 3.12.9, MCP Python SDK v1.21.2

Guia de contribuição

Abrir o guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Direção de pesquisa

Comece em src/mcp/server/streamable_http.py, em StreamableHTTPServerTransport._handle_post_request, próximo ao handler amplo de exceções nas linhas 490–500, e analise como ClientDisconnect chega até ele. Execute a reprodução fornecida do socket com body parcial para observar a resposta e o logging atuais. Está concluído quando desconexões normais do cliente não produzirem mais um HTTP 500, traceback de nível ERROR ou alerta 5XX em produção.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
python
Domínio
api, backend
Tipo de issue
Bug
Dificuldade
2/5
Tempo estimado
1-3 horas
Status de atividade
Ativa
Clareza
Claramente especificada
Facilidade para iniciantes
76/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.