Skip to content

Commit 5239245

Browse files
committed
test(lowlevel): update outputSchema-no-structured-content test for new behavior
CI flagged that the existing test_content_only_with_output_schema_error asserted the old contract (replace tool output with a generic 'outputSchema validation' message). This PR's whole point is to NOT do that, so the assertion was guaranteed to flip. Renames the test to test_content_only_with_output_schema_surfaces_error and updates assertions to verify the new contract: - isError = True (so callers can branch on it) - the tool's original unstructured TextContent payload is preserved verbatim (so callers see the tool's own error message, e.g. 'Resource not found', instead of a generic SDK validation string) - structuredContent stays None Verified locally with `python -m pytest tests/server/test_lowlevel_output_validation.py` → 9 passed. Signed-off-by: SAY-5 <say.apm35@gmail.com>
1 parent 58889e6 commit 5239245

1 file changed

Lines changed: 18 additions & 5 deletions

File tree

tests/server/test_lowlevel_output_validation.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,15 @@ async def test_callback(client_session: ClientSession) -> CallToolResult:
213213

214214

215215
@pytest.mark.anyio
216-
async def test_content_only_with_output_schema_error():
217-
"""Test error when outputSchema is defined but only content is returned."""
216+
async def test_content_only_with_output_schema_surfaces_error():
217+
"""When an outputSchema-bound tool returns only unstructured content,
218+
the result is treated as a tool-error (isError=True) and the original
219+
unstructured payload is preserved so the caller sees the tool's own
220+
error message instead of a generic validation message.
221+
222+
Mirrors the TypeScript SDK fix in modelcontextprotocol/typescript-sdk#655.
223+
See #2429 for the original report.
224+
"""
218225
tools = [
219226
Tool(
220227
name="structured_tool",
@@ -234,21 +241,27 @@ async def test_content_only_with_output_schema_error():
234241
]
235242

236243
async def call_tool_handler(name: str, arguments: dict[str, Any]) -> list[TextContent]:
237-
# This returns only content, but outputSchema expects structured data
244+
# This returns only content, but outputSchema expects structured data.
245+
# Real-world callers use this path to surface tool-execution errors
246+
# like "Resource not found" or "API rate limit hit"; that text must
247+
# not be replaced by a generic validation message.
238248
return [TextContent(type="text", text="This is not structured")]
239249

240250
async def test_callback(client_session: ClientSession) -> CallToolResult:
241251
return await client_session.call_tool("structured_tool", {})
242252

243253
result = await run_tool_test(tools, call_tool_handler, test_callback)
244254

245-
# Verify error
255+
# Result is flagged as an error (isError=True) so callers can detect it,
256+
# but the tool's original unstructured payload is preserved verbatim.
246257
assert result is not None
247258
assert result.isError
248259
assert len(result.content) == 1
249260
assert result.content[0].type == "text"
250261
assert isinstance(result.content[0], TextContent)
251-
assert "Output validation error: outputSchema defined but no structured output returned" in result.content[0].text
262+
assert result.content[0].text == "This is not structured"
263+
# No structured content was produced; that field stays None.
264+
assert result.structuredContent is None
252265

253266

254267
@pytest.mark.anyio

0 commit comments

Comments
 (0)