Sanitize MCP tool output items in openai-agents-sdk template#119
Conversation
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>
There was a problem hiding this comment.
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_itemandsanitize_output_itemshelper functions to convert list-type output fields to JSON strings - Applied sanitization in both the
invokehandler (for non-streaming responses) and thestreamevent handler (for streaming responses) - Reorganized imports in
agent.pyto 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.
| if isinstance(input_item.get("output"), list): | ||
| input_item["output"] = json.dumps(input_item["output"]) | ||
| return input_item |
There was a problem hiding this comment.
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.
| 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 |
| 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"]) |
There was a problem hiding this comment.
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.
| 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) |
… 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>
Summary
outputfield is a list instead of a string, causing Pydantic validation errors inResponsesAgentResponsesanitize_output_items/_sanitize_itemtoutils.pyand wires it into both invoke and stream handlersTemporary workaround until mlflow/mlflow#20777 is released.