Skip to content

Commit 479bb0a

Browse files
committed
add more http transport tests
1 parent d4122a0 commit 479bb0a

File tree

1 file changed

+223
-0
lines changed

1 file changed

+223
-0
lines changed

tests/test_http_real_transport.py

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,226 @@ async def test_http_initialize_request(http_client: httpx.AsyncClient, server: s
167167
assert result["id"] == 1
168168
assert "result" in result
169169
assert result["result"]["serverInfo"]["name"] == SERVER_NAME
170+
171+
172+
@pytest.mark.anyio
173+
async def test_http_list_tools(http_client: httpx.AsyncClient, server: str) -> None:
174+
"""Test tool listing via HTTP POST with JSON response."""
175+
mcp_path = "/mcp"
176+
177+
init_response = await http_client.post(
178+
mcp_path,
179+
json={
180+
"jsonrpc": "2.0",
181+
"method": "initialize",
182+
"id": 1,
183+
"params": {
184+
"protocolVersion": types.LATEST_PROTOCOL_VERSION,
185+
"capabilities": {},
186+
"clientInfo": {"name": "test-client", "version": "1.0.0"},
187+
},
188+
},
189+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
190+
)
191+
assert init_response.status_code == 200
192+
193+
initialized_response = await http_client.post(
194+
mcp_path,
195+
json={
196+
"jsonrpc": "2.0",
197+
"method": "notifications/initialized",
198+
},
199+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
200+
)
201+
assert initialized_response.status_code == 202
202+
203+
response = await http_client.post(
204+
mcp_path,
205+
json={
206+
"jsonrpc": "2.0",
207+
"method": "tools/list",
208+
"id": 2,
209+
},
210+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
211+
)
212+
213+
assert response.status_code == 200
214+
result = response.json()
215+
assert result["jsonrpc"] == "2.0"
216+
assert result["id"] == 2
217+
assert "result" in result
218+
assert "tools" in result["result"]
219+
assert len(result["result"]["tools"]) > 0
220+
221+
# Verify we have the expected tools from the simple FastAPI app
222+
tool_names = [tool["name"] for tool in result["result"]["tools"]]
223+
assert "get_item" in tool_names
224+
assert "list_items" in tool_names
225+
226+
227+
@pytest.mark.anyio
228+
async def test_http_call_tool(http_client: httpx.AsyncClient, server: str) -> None:
229+
"""Test tool calling via HTTP POST with JSON response."""
230+
mcp_path = "/mcp"
231+
232+
init_response = await http_client.post(
233+
mcp_path,
234+
json={
235+
"jsonrpc": "2.0",
236+
"method": "initialize",
237+
"id": 1,
238+
"params": {
239+
"protocolVersion": types.LATEST_PROTOCOL_VERSION,
240+
"capabilities": {},
241+
"clientInfo": {"name": "test-client", "version": "1.0.0"},
242+
},
243+
},
244+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
245+
)
246+
assert init_response.status_code == 200
247+
248+
initialized_response = await http_client.post(
249+
mcp_path,
250+
json={
251+
"jsonrpc": "2.0",
252+
"method": "notifications/initialized",
253+
},
254+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
255+
)
256+
assert initialized_response.status_code == 202
257+
258+
response = await http_client.post(
259+
mcp_path,
260+
json={
261+
"jsonrpc": "2.0",
262+
"method": "tools/call",
263+
"id": 3,
264+
"params": {
265+
"name": "get_item",
266+
"arguments": {"item_id": 1},
267+
},
268+
},
269+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
270+
)
271+
272+
assert response.status_code == 200
273+
result = response.json()
274+
assert result["jsonrpc"] == "2.0"
275+
assert result["id"] == 3
276+
assert "result" in result
277+
assert result["result"]["isError"] is False
278+
assert "content" in result["result"]
279+
assert len(result["result"]["content"]) > 0
280+
281+
# Verify the response contains expected item data
282+
content = result["result"]["content"][0]
283+
assert content["type"] == "text"
284+
assert "Item 1" in content["text"] # Should contain the item name
285+
286+
287+
@pytest.mark.anyio
288+
async def test_http_ping(http_client: httpx.AsyncClient, server: str) -> None:
289+
"""Test ping functionality via HTTP POST."""
290+
mcp_path = "/mcp"
291+
292+
init_response = await http_client.post(
293+
mcp_path,
294+
json={
295+
"jsonrpc": "2.0",
296+
"method": "initialize",
297+
"id": 1,
298+
"params": {
299+
"protocolVersion": types.LATEST_PROTOCOL_VERSION,
300+
"capabilities": {},
301+
"clientInfo": {"name": "test-client", "version": "1.0.0"},
302+
},
303+
},
304+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
305+
)
306+
assert init_response.status_code == 200
307+
308+
initialized_response = await http_client.post(
309+
mcp_path,
310+
json={
311+
"jsonrpc": "2.0",
312+
"method": "notifications/initialized",
313+
},
314+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
315+
)
316+
assert initialized_response.status_code == 202
317+
318+
response = await http_client.post(
319+
mcp_path,
320+
json={
321+
"jsonrpc": "2.0",
322+
"method": "ping",
323+
"id": 4,
324+
},
325+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
326+
)
327+
328+
assert response.status_code == 200
329+
result = response.json()
330+
assert result["jsonrpc"] == "2.0"
331+
assert result["id"] == 4
332+
assert "result" in result
333+
334+
335+
@pytest.mark.anyio
336+
async def test_http_error_handling(http_client: httpx.AsyncClient, server: str) -> None:
337+
"""Test error handling for invalid requests."""
338+
mcp_path = "/mcp"
339+
340+
response = await http_client.post(
341+
mcp_path,
342+
content="invalid json",
343+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
344+
)
345+
346+
assert response.status_code == 400
347+
result = response.json()
348+
assert "error" in result
349+
assert result["error"]["code"] == -32700 # Parse error
350+
351+
352+
@pytest.mark.anyio
353+
async def test_http_invalid_method(http_client: httpx.AsyncClient, server: str) -> None:
354+
"""Test error handling for invalid methods."""
355+
mcp_path = "/mcp"
356+
357+
response = await http_client.post(
358+
mcp_path,
359+
json={
360+
"jsonrpc": "2.0",
361+
"method": "invalid/method",
362+
"id": 5,
363+
},
364+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
365+
)
366+
367+
assert response.status_code == 200
368+
result = response.json()
369+
assert result["jsonrpc"] == "2.0"
370+
assert result["id"] == 5
371+
assert "error" in result
372+
assert result["error"]["code"] == -32602 # Invalid request parameters
373+
374+
375+
@pytest.mark.anyio
376+
async def test_http_notification_handling(http_client: httpx.AsyncClient, server: str) -> None:
377+
"""Test that notifications return 202 Accepted without response body."""
378+
mcp_path = "/mcp"
379+
380+
response = await http_client.post(
381+
mcp_path,
382+
json={
383+
"jsonrpc": "2.0",
384+
"method": "notifications/cancelled",
385+
"params": {"requestId": "test-123"},
386+
},
387+
headers={"Accept": "application/json, text/event-stream", "Content-Type": "application/json"},
388+
)
389+
390+
assert response.status_code == 202
391+
# Notifications should return empty body
392+
assert response.content == b"" or response.text == "null"

0 commit comments

Comments
 (0)