|
1 | 1 | import logging |
2 | 2 | from contextlib import contextmanager |
| 3 | +from pathlib import Path |
3 | 4 | from typing import Any |
4 | 5 | from unittest.mock import patch |
5 | 6 |
|
6 | 7 | import pytest |
| 8 | +from referencing.exceptions import Unresolvable |
7 | 9 |
|
8 | 10 | from mcp.server.lowlevel import Server |
9 | 11 | from mcp.shared.memory import ( |
@@ -215,3 +217,34 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]: |
215 | 217 |
|
216 | 218 | # Check that warning was logged |
217 | 219 | assert "Tool mystery_tool not listed" in caplog.text |
| 220 | + |
| 221 | + |
| 222 | +# jsonschema's fallback retriever emits this DeprecationWarning; keep it a plain warning so the |
| 223 | +# assertions below decide the outcome rather than the suite's warnings-as-errors filter. |
| 224 | +@pytest.mark.filterwarnings("default:Automatically retrieving remote references:DeprecationWarning") |
| 225 | +@pytest.mark.anyio |
| 226 | +async def test_output_schema_ref_outside_the_document_is_rejected(tmp_path: Path): |
| 227 | + """A `$ref` to a URI outside the output schema is not resolved, and a result whose validation |
| 228 | + reaches one fails as an invalid schema (spec `$ref` resolution; applying it to `file:` URIs too |
| 229 | + is SDK-defined).""" |
| 230 | + target = tmp_path / "schema.json" |
| 231 | + target.write_text("{}", encoding="utf-8") |
| 232 | + server = Server("test-server") |
| 233 | + |
| 234 | + @server.list_tools() |
| 235 | + async def list_tools(): |
| 236 | + return [ |
| 237 | + Tool(name="probe", description="", inputSchema={"type": "object"}, outputSchema={"$ref": target.as_uri()}) |
| 238 | + ] |
| 239 | + |
| 240 | + @server.call_tool() |
| 241 | + async def call_tool(name: str, arguments: dict[str, Any]): |
| 242 | + return {"v": 1} |
| 243 | + |
| 244 | + with bypass_server_output_validation(): |
| 245 | + async with client_session(server) as client: |
| 246 | + with pytest.raises(RuntimeError) as exc_info: |
| 247 | + await client.call_tool("probe", {}) |
| 248 | + # SDK-authored prefix only; the tail is `referencing`'s text. |
| 249 | + assert str(exc_info.value).startswith("Invalid schema for tool probe: ") |
| 250 | + assert isinstance(exc_info.value.__cause__, Unresolvable) |
0 commit comments