Files
wehub-resource-sync 60e0ffc959
Upgrade checks / Notify on failure (push) Has been cancelled
Upgrade checks / Close issue on success (push) Has been cancelled
Schema Crash Test / Real-world schema crash test (232K schemas) (push) Has been cancelled
Run static analysis / static_analysis (push) Has been cancelled
Tests / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Tests / Tests with lowest-direct dependencies (push) Has been cancelled
Tests / MCP conformance tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
Tests / Package install smoke (push) Has been cancelled
Upgrade checks / Static analysis (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Upgrade checks / Integration tests (push) Has been cancelled
Update MCPServerConfig Schema / update-config-schema (push) Has been cancelled
Update SDK Documentation / update-sdk-docs (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:59 +08:00

137 lines
4.3 KiB
Python

"""Tests for DereferenceRefsMiddleware."""
from enum import Enum
import pydantic
from fastmcp import Client, FastMCP
class Color(Enum):
RED = "red"
GREEN = "green"
BLUE = "blue"
class PaintRequest(pydantic.BaseModel):
color: Color
opacity: float = 1.0
class TestDereferenceRefsMiddleware:
"""End-to-end tests for the dereference_schemas server kwarg."""
async def test_dereference_schemas_true_inlines_refs(self):
"""With dereference_schemas=True (default), tool schemas have $ref inlined."""
mcp = FastMCP("test", dereference_schemas=True)
@mcp.tool
def paint(request: PaintRequest) -> str:
return "ok"
async with Client(mcp) as client:
tools = await client.list_tools()
schema = tools[0].input_schema
# $defs should be removed — everything inlined
assert "$defs" not in schema
# The Color enum should be inlined into the request property
assert "$ref" not in str(schema)
async def test_dereference_schemas_false_preserves_refs(self):
"""With dereference_schemas=False, $ref and $defs are preserved."""
mcp = FastMCP("test", dereference_schemas=False)
@mcp.tool
def paint(request: PaintRequest) -> str:
return "ok"
async with Client(mcp) as client:
tools = await client.list_tools()
schema = tools[0].input_schema
# $defs should still be present
assert "$defs" in schema
async def test_default_is_true(self):
"""Default behavior dereferences $ref."""
mcp = FastMCP("test")
@mcp.tool
def paint(request: PaintRequest) -> str:
return "ok"
async with Client(mcp) as client:
tools = await client.list_tools()
schema = tools[0].input_schema
assert "$defs" not in schema
async def test_does_not_mutate_original_tool(self):
"""Middleware should not mutate the shared Tool object."""
mcp = FastMCP("test", dereference_schemas=True)
@mcp.tool
def paint(request: PaintRequest) -> str:
return "ok"
# Get the original tool's parameters before middleware runs
original_tools = await mcp._local_provider._list_tools()
assert "$defs" in original_tools[0].parameters
# List tools through the client (triggers middleware)
async with Client(mcp) as client:
await client.list_tools()
# The original tool stored in the server should still have $defs
tools_after = await mcp._local_provider._list_tools()
assert "$defs" in tools_after[0].parameters
async def test_output_schema_dereferenced(self):
"""Middleware also dereferences output_schema when present."""
mcp = FastMCP("test", dereference_schemas=True)
@mcp.tool
def paint(request: PaintRequest) -> PaintRequest:
return request
async with Client(mcp) as client:
tools = await client.list_tools()
tool = tools[0]
# Both input and output schemas should be dereferenced
assert "$defs" not in tool.input_schema
if tool.output_schema is not None:
assert "$defs" not in tool.output_schema
async def test_resource_templates_dereferenced(self):
"""Middleware dereferences resource template schemas."""
mcp = FastMCP("test", dereference_schemas=True)
@mcp.resource("paint://{color}")
def get_paint(color: Color) -> str:
return f"paint: {color}"
async with Client(mcp) as client:
templates = await client.list_resource_templates()
# Resource templates also get their schemas dereferenced
# (only if the template parameters have $ref)
assert len(templates) == 1
async def test_no_ref_schemas_unchanged(self):
"""Tools without $ref should pass through unmodified."""
mcp = FastMCP("test", dereference_schemas=True)
@mcp.tool
def add(a: int, b: int) -> int:
return a + b
async with Client(mcp) as client:
tools = await client.list_tools()
schema = tools[0].input_schema
# Simple schema should not have $defs regardless
assert "$defs" not in schema
assert schema["properties"]["a"]["type"] == "integer"