ClientDisconnect returns HTTP 500

オープン 初心者向け
#1,648 コメント 6 件 リアクション 1 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
76/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
python
領域
api, backend

調査の方向性

src/mcp/server/streamable_http.py の StreamableHTTPServerTransport._handle_post_request から始め、490–500 行付近にある広範な例外ハンドラーを確認し、ClientDisconnect がどのようにそこへ到達するかを調べてください。提供されている部分的な body の socket 再現を実行し、現在のレスポンスとログを確認してください。通常のクライアント切断によって HTTP 500、ERROR レベルの traceback、または本番環境での 5XX アラートが発生しなくなれば完了です。

索引モデルが issue の本文から書いたものです。

説明

bug P2 ready for work
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
主要言語
Python
スター
24.3k
フォーク
4k
平均マージ
1日 1時間
マージ済み PR(30日)
31

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

modelcontextprotocol/python-sdk のほかの issue

modelcontextprotocol/python-sdk の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。