chore: Lazy import jsonschema library (#1596)

Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
This commit is contained in:
Liang Wu
2025-11-19 07:30:52 -08:00
committed by GitHub
parent 5489e8b6fb
commit 9c8f763aa8
2 changed files with 23 additions and 4 deletions
+2 -1
View File
@@ -4,7 +4,6 @@ from typing import Any, Protocol, overload
import anyio.lowlevel
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
from jsonschema import SchemaError, ValidationError, validate
from pydantic import AnyUrl, TypeAdapter
from typing_extensions import deprecated
@@ -376,6 +375,8 @@ class ClientSession(
logger.warning(f"Tool {name} not listed by server, cannot validate any structured content")
if output_schema is not None:
from jsonschema import SchemaError, ValidationError, validate
if result.structuredContent is None:
raise RuntimeError(
f"Tool {name} has an output schema but did not return structured content"
+21 -3
View File
@@ -19,9 +19,27 @@ def bypass_server_output_validation():
This simulates a malicious or non-compliant server that doesn't validate
its outputs, allowing us to test client-side validation.
"""
# Patch jsonschema.validate in the server module to disable all validation
with patch("mcp.server.lowlevel.server.jsonschema.validate"):
# The mock will simply return None (do nothing) for all validation calls
import jsonschema
# Save the original validate function
original_validate = jsonschema.validate
# Create a mock that tracks which module is calling it
def selective_mock(instance: Any = None, schema: Any = None, *args: Any, **kwargs: Any) -> None:
import inspect
# Check the call stack to see where this is being called from
for frame_info in inspect.stack():
# If called from the server module, skip validation
# TODO: fix this as it's a rather gross workaround and will eventually break
# Normalize path separators for cross-platform compatibility
normalized_path = frame_info.filename.replace("\\", "/")
if "mcp/server/lowlevel/server.py" in normalized_path:
return None
# Otherwise, use the real validation (for client-side)
return original_validate(instance=instance, schema=schema, *args, **kwargs)
with patch("jsonschema.validate", selective_mock):
yield