fastmcp/tests/server/providers/openapi/test_legacy_client_compat.py

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)