mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-09 15:19:10 +02:00
110 lines
3.7 KiB
Python
110 lines
3.7 KiB
Python
"""Deprecation bridge for legacy-httpx OpenAPI clients."""
|
|
|
|
import pytest
|
|
|
|
from fastmcp import Client, FastMCP, FastMCPDeprecationWarning
|
|
from fastmcp.exceptions import ToolError
|
|
|
|
httpx = pytest.importorskip("httpx", reason="legacy httpx not installed")
|
|
|
|
SPEC = {
|
|
"openapi": "3.0.0",
|
|
"info": {"title": "Legacy Client API", "version": "1.0.0"},
|
|
"servers": [{"url": "https://api.example.com"}],
|
|
"paths": {
|
|
"/items": {
|
|
"get": {
|
|
"operationId": "list_items",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Items",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"items": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
}
|
|
},
|
|
}
|
|
}
|
|
},
|
|
}
|
|
},
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
|
|
async def test_legacy_client_warns_and_remains_usable() -> None:
|
|
def handler(request: "httpx.Request") -> "httpx.Response":
|
|
return httpx.Response(200, json={"items": ["a", "b"]})
|
|
|
|
transport = httpx.MockTransport(handler)
|
|
async with httpx.AsyncClient(
|
|
transport=transport,
|
|
base_url="https://api.example.com",
|
|
) as client:
|
|
with pytest.warns(
|
|
FastMCPDeprecationWarning,
|
|
match="httpx.AsyncClient.*deprecated",
|
|
):
|
|
server = FastMCP.from_openapi(SPEC, client=client)
|
|
|
|
async with Client(server) as mcp_client:
|
|
result = await mcp_client.call_tool("list_items", {})
|
|
|
|
assert result.structured_content == {"items": ["a", "b"]}
|
|
|
|
|
|
async def test_legacy_client_preserves_http_error_details() -> None:
|
|
def handler(request: "httpx.Request") -> "httpx.Response":
|
|
return httpx.Response(404, json={"detail": "items not found"})
|
|
|
|
transport = httpx.MockTransport(handler)
|
|
async with httpx.AsyncClient(
|
|
transport=transport,
|
|
base_url="https://api.example.com",
|
|
) as client:
|
|
with pytest.warns(FastMCPDeprecationWarning):
|
|
server = FastMCP.from_openapi(SPEC, client=client)
|
|
|
|
async with Client(server) as mcp_client:
|
|
with pytest.raises(ToolError, match="HTTP error 404") as exc_info:
|
|
await mcp_client.call_tool("list_items", {})
|
|
|
|
assert "items not found" in str(exc_info.value)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("error_kind", "message"),
|
|
[
|
|
("timeout", "HTTP request timed out (ReadTimeout)"),
|
|
("connect", "Request error (ConnectError)"),
|
|
],
|
|
)
|
|
async def test_legacy_client_preserves_transport_error_details(
|
|
error_kind: str,
|
|
message: str,
|
|
) -> None:
|
|
def handler(request: "httpx.Request") -> "httpx.Response":
|
|
if error_kind == "timeout":
|
|
raise httpx.ReadTimeout("transport failed", request=request)
|
|
raise httpx.ConnectError("transport failed", request=request)
|
|
|
|
transport = httpx.MockTransport(handler)
|
|
async with httpx.AsyncClient(
|
|
transport=transport,
|
|
base_url="https://api.example.com",
|
|
) as client:
|
|
with pytest.warns(FastMCPDeprecationWarning):
|
|
server = FastMCP.from_openapi(SPEC, client=client)
|
|
|
|
async with Client(server) as mcp_client:
|
|
with pytest.raises(ToolError) as exc_info:
|
|
await mcp_client.call_tool("list_items", {})
|
|
|
|
assert message in str(exc_info.value)
|