Skip to content

Sanitize MCP tool output items in openai-agents-sdk template#119

Merged
bbqiu merged 2 commits into
databricks:mainfrom
dhruv0811:sanitize-mcp-output
Feb 13, 2026
Merged

Sanitize MCP tool output items in openai-agents-sdk template#119
bbqiu merged 2 commits into
databricks:mainfrom
dhruv0811:sanitize-mcp-output

Conversation

@dhruv0811
Copy link
Copy Markdown
Contributor

@dhruv0811 dhruv0811 commented Feb 12, 2026

Summary

  • MCP tools (e.g. Genie) can return output items where the output field is a list instead of a string, causing Pydantic validation errors in ResponsesAgentResponse
  • Adds sanitize_output_items / _sanitize_item to utils.py and wires it into both invoke and stream handlers

Temporary workaround until mlflow/mlflow#20777 is released.

MCP tools (e.g. Genie) can return list outputs that fail Pydantic
validation. Add sanitize_output_items to both invoke and stream paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 adds sanitization of MCP tool output items to fix Pydantic validation errors that occur when the output field is a list instead of a string. The changes introduce helper functions to convert non-string output values to JSON strings before passing them to ResponsesAgentResponse.

Changes:

  • Added _sanitize_item and sanitize_output_items helper functions to convert list-type output fields to JSON strings
  • Applied sanitization in both the invoke handler (for non-streaming responses) and the stream event handler (for streaming responses)
  • Reorganized imports in agent.py to be alphabetically sorted

Reviewed changes

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

File Description
agent-openai-agents-sdk/agent_server/utils.py Added sanitization functions _sanitize_item and sanitize_output_items to handle MCP tool outputs with list-type output fields; integrated _sanitize_item into the stream event processing
agent-openai-agents-sdk/agent_server/agent.py Updated imports to include sanitize_output_items and applied it to the invoke response output; reorganized imports alphabetically

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

Comment on lines +43 to +45
if isinstance(input_item.get("output"), list):
input_item["output"] = json.dumps(input_item["output"])
return input_item
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The function mutates the input dictionary directly, which can cause unintended side effects if the same dictionary is used elsewhere. Consider creating a copy of the dictionary before modifying it to avoid mutating the caller's data. For example, create a shallow copy at the start of the function with item = input_item.copy() and then modify and return the copy.

Suggested change
if isinstance(input_item.get("output"), list):
input_item["output"] = json.dumps(input_item["output"])
return input_item
item = input_item.copy()
if isinstance(item.get("output"), list):
item["output"] = json.dumps(item["output"])
return item

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +44
a *list* of content objects instead of a plain string. MLflow's Pydantic
models expect ``output`` to be a string, so this serialises any non-string
values to JSON.

TODO: Remove once https://github.com/mlflow/mlflow/pull/20777 is released.
"""
if isinstance(input_item.get("output"), list):
input_item["output"] = json.dumps(input_item["output"])
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The sanitization only handles the case where output is a list. However, other non-string types (e.g., dict, int, bool, None) could also cause Pydantic validation errors. Consider checking if output is not a string rather than checking if it's specifically a list. For example: if "output" in input_item and not isinstance(input_item["output"], str): to handle all non-string types consistently.

Suggested change
a *list* of content objects instead of a plain string. MLflow's Pydantic
models expect ``output`` to be a string, so this serialises any non-string
values to JSON.
TODO: Remove once https://github.com/mlflow/mlflow/pull/20777 is released.
"""
if isinstance(input_item.get("output"), list):
input_item["output"] = json.dumps(input_item["output"])
a collection or other non-string value instead of a plain string. MLflow's
Pydantic models expect ``output`` to be a string, so this serialises any
non-string values to JSON.
TODO: Remove once https://github.com/mlflow/mlflow/pull/20777 is released.
"""
output_value = input_item.get("output")
if "output" in input_item and not isinstance(output_value, str):
input_item["output"] = json.dumps(output_value)

Copilot uses AI. Check for mistakes.
Comment thread agent-openai-agents-sdk/agent_server/utils.py
Comment thread agent-openai-agents-sdk/agent_server/utils.py
Comment thread agent-openai-agents-sdk/agent_server/utils.py
.
Signed-off-by: Bryan Qiu <bryan.qiu@databricks.com>
@bbqiu bbqiu merged commit 9cc741d into databricks:main Feb 13, 2026
@bbqiu bbqiu mentioned this pull request Feb 13, 2026
3 tasks
dhruv0811 added a commit to dhruv0811/app-templates that referenced this pull request Feb 13, 2026
… with PR databricks#119

- Move Genie from standalone GENIE_SPACE_ID into SUBAGENTS as type "genie"
  with a description for the MCP server
- Comment out all SUBAGENTS entries by default; single assert catches
  unconfigured templates
- Update _sanitize_item to handle any non-string output (not just lists)
  with try/except fallback, matching the base template from PR databricks#119

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

3 participants