Skip to content

Commit 2a4a289

Browse files
test(fastmcp): Use TestClient for Streamable HTTP (#5384)
1 parent 54207a2 commit 2a4a289

File tree

3 files changed

+261
-162
lines changed

3 files changed

+261
-162
lines changed

tests/conftest.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
from werkzeug.wrappers import Request, Response
1717
import jsonschema
1818

19+
try:
20+
from starlette.testclient import TestClient
21+
# Catch RuntimeError to prevent the following exception in aws_lambda tests.
22+
# RuntimeError: The starlette.testclient module requires the httpx package to be installed.
23+
except (ImportError, RuntimeError):
24+
TestClient = None
1925

2026
try:
2127
import gevent
@@ -708,6 +714,79 @@ async def simulate_client(tg, result):
708714
return inner
709715

710716

717+
@pytest.fixture()
718+
def json_rpc():
719+
def inner(app, method: str, params, request_id: str):
720+
with TestClient(app) as client: # type: ignore
721+
init_response = client.post(
722+
"/mcp/",
723+
headers={
724+
"Accept": "application/json, text/event-stream",
725+
"Content-Type": "application/json",
726+
},
727+
json={
728+
"jsonrpc": "2.0",
729+
"method": "initialize",
730+
"params": {
731+
"clientInfo": {"name": "test-client", "version": "1.0"},
732+
"protocolVersion": "2025-11-25",
733+
"capabilities": {},
734+
},
735+
"id": request_id,
736+
},
737+
)
738+
739+
session_id = init_response.headers["mcp-session-id"]
740+
741+
# Notification response is mandatory.
742+
# https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle
743+
client.post(
744+
"/mcp/",
745+
headers={
746+
"Accept": "application/json, text/event-stream",
747+
"Content-Type": "application/json",
748+
"mcp-session-id": session_id,
749+
},
750+
json={
751+
"jsonrpc": "2.0",
752+
"method": "notifications/initialized",
753+
"params": {},
754+
},
755+
)
756+
757+
response = client.post(
758+
"/mcp/",
759+
headers={
760+
"Accept": "application/json, text/event-stream",
761+
"Content-Type": "application/json",
762+
"mcp-session-id": session_id,
763+
},
764+
json={
765+
"jsonrpc": "2.0",
766+
"method": method,
767+
"params": params,
768+
"id": request_id,
769+
},
770+
)
771+
772+
return session_id, response
773+
774+
return inner
775+
776+
777+
@pytest.fixture()
778+
def select_mcp_transactions():
779+
def inner(events):
780+
return [
781+
event
782+
for event in events
783+
if event["type"] == "transaction"
784+
and event["contexts"]["trace"]["op"] == "mcp.server"
785+
]
786+
787+
return inner
788+
789+
711790
class MockServerRequestHandler(BaseHTTPRequestHandler):
712791
def do_GET(self): # noqa: N802
713792
# Process an HTTP GET request and return a response.

0 commit comments

Comments
 (0)