Skip to content

Support is_error flag for tool results#2566

Open
zuhabul wants to merge 1 commit intomodelcontextprotocol:mainfrom
zuhabul:fix/mcp-348-is-error
Open

Support is_error flag for tool results#2566
zuhabul wants to merge 1 commit intomodelcontextprotocol:mainfrom
zuhabul:fix/mcp-348-is-error

Conversation

@zuhabul
Copy link
Copy Markdown

@zuhabul zuhabul commented May 10, 2026

Fixes #348 — allow tools to return (unstructured_content, structured_content, is_error) so non-text results (e.g., images) can be marked as errors. Also document the behavior in docs/migration.md.

…protocol#348)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 10, 2026 06:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to let tool implementations explicitly mark a tool call result as an error (via CallToolResult.is_error) even when returning non-text content (e.g., images/audio), by supporting a 3-tuple return shape (unstructured_content, structured_content, is_error) and documenting the behavior in the migration guide.

Changes:

  • Extend MCPServer._handle_call_tool() to interpret 3-tuples as (content, structured_content, is_error) and set CallToolResult.is_error accordingly.
  • Add migration documentation describing the new 3-tuple tool return shape and the alternative of returning CallToolResult directly.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/mcp/server/mcpserver/server.py Adds tuple parsing logic intended to propagate an is_error flag into CallToolResult.
docs/migration.md Documents the new 3-tuple return option for marking non-text tool results as errors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +319 to 335
if isinstance(result, tuple):
# Support either (unstructured_content, structured_content) or
# (unstructured_content, structured_content, is_error). The third element,
# if present, controls the CallToolResult.is_error flag.
if len(result) == 2:
unstructured_content, structured_content = result
is_error = False
elif len(result) == 3:
unstructured_content, structured_content, is_error = result
else:
# Fallback: treat as a sequence of content blocks
return CallToolResult(content=list(result))
return CallToolResult(
content=list(unstructured_content), # type: ignore[arg-type]
structured_content=structured_content, # type: ignore[arg-type]
is_error=bool(is_error),
)
Comment on lines +328 to +334
else:
# Fallback: treat as a sequence of content blocks
return CallToolResult(content=list(result))
return CallToolResult(
content=list(unstructured_content), # type: ignore[arg-type]
structured_content=structured_content, # type: ignore[arg-type]
is_error=bool(is_error),
Comment on lines 331 to 332
return CallToolResult(
content=list(unstructured_content), # type: ignore[arg-type]
Comment thread docs/migration.md
Comment on lines +1141 to +1147
Tools may now return a 3-tuple: (unstructured_content, structured_content, is_error).
If the third element is True, the resulting CallToolResult sent to clients will have
is_error=True. This allows returning non-text content (images, audio) while still
indicating the tool execution failed or produced an error state.

Alternatively, tools may return a full `CallToolResult` instance directly to control
is_error and other fields explicitly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No way to set isError=True for arbitrary tool result content

3 participants