fix: provider-agnostic tool schema for Bedrock/Gemini MCP tools (#4472) - #4912
fix: provider-agnostic tool schema for Bedrock/Gemini MCP tools (#4472)#4912joaquinhuigomez wants to merge 6 commits into
Conversation
…flake-connector-python) (crewAIInc#4913) - authlib 1.6.7 → 1.6.9 (CVE-2026-27962 critical, CVE-2026-28498, CVE-2026-28490) - PyJWT 2.11.0 → 2.12.1 (CVE-2026-32597) - snowflake-connector-python 4.2.0 → 4.3.0
|
Addressed the Cursor Bugbot issue: Bug: Fix: Added a Latest commit: a99502cac |
a99502c to
d2f6073
Compare
* fix: enhance LLM response handling and serialization * Updated the Flow class to improve error handling when both structured and simple prompting fail, ensuring the first outcome is returned as a fallback. * Introduced a new function, _serialize_llm_for_context, to properly serialize LLM objects with provider prefixes for better context management. * Added tests to validate the new serialization logic and ensure correct behavior when LLM calls fail. This update enhances the robustness of LLM interactions and improves the overall flow of handling outcomes. * fix: patch VCR response handling to prevent httpx.ResponseNotRead errors (crewAIInc#4917) * fix: enhance LLM response handling and serialization * Updated the Flow class to improve error handling when both structured and simple prompting fail, ensuring the first outcome is returned as a fallback. * Introduced a new function, _serialize_llm_for_context, to properly serialize LLM objects with provider prefixes for better context management. * Added tests to validate the new serialization logic and ensure correct behavior when LLM calls fail. This update enhances the robustness of LLM interactions and improves the overall flow of handling outcomes. * fix: patch VCR response handling to prevent httpx.ResponseNotRead errors VCR's _from_serialized_response mocks httpx.Response.read(), which prevents the response's internal _content attribute from being properly initialized. When OpenAI's client (using with_raw_response) accesses response.content, httpx raises ResponseNotRead. This patch explicitly sets response._content after the response is created, ensuring that tests using VCR cassettes work correctly with the OpenAI client's raw response handling. Fixes tests: - test_hierarchical_crew_creation_tasks_with_sync_last - test_conditional_task_last_task_when_conditional_is_false - test_crew_log_file_output --------- Co-authored-by: Joao Moura <joaomdmoura@gmail.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: alex-clawd <alex@crewai.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
…AIInc#4472) Add generate_tool_parameters_schema() that produces clean JSON schemas without OpenAI-specific artifacts (additionalProperties, forced required for all fields, title on nested objects) that Bedrock and Gemini reject. Update extract_tool_info() to use the new function instead of generate_model_description() for the args_schema code path, which is shared across all providers via safe_tool_conversion().
…ema_metadata A tool model with a field named 'title' or 'default' would have its entire property definition silently removed, producing a broken schema. Fix by skipping metadata stripping when iterating a 'properties' mapping (where keys are field names, not schema keywords).
…t mode - _strip_schema_metadata: distinguish between properties-mapping dicts (where keys are user field names) and schema nodes. Previously, fields named "title", "default", or "additionalProperties" were silently removed from the schema. Now the function only strips metadata keys from schema nodes, not from the properties mapping itself. - _strip_schema_metadata: a field literally named "properties" no longer causes its schema node to be misidentified as a properties mapping, which would skip metadata stripping. - OpenAI strict mode: re-apply ensure_all_properties_required in _convert_tools_for_interference so that MCP tools with optional parameters are not rejected by the OpenAI API.
885b728 to
51ccbf1
Compare
…erference
Switching extract_tool_info to generate_tool_parameters_schema removed
three strict-mode transforms that generate_model_description previously
applied. Re-add them explicitly in the OpenAI provider:
strip_unsupported_formats — removes 'uri', 'email', 'uuid' formats
ensure_type_in_schemas — converts empty {} to {"type": "object"}
convert_oneof_to_anyof — normalises oneOf → anyOf for strict mode
ensure_all_properties_required and force_additional_properties_false
were already present. Pipeline now matches the original behaviour exactly.
Also adds:
- test for field named 'properties' not suppressing sibling stripping
- unit tests for all three newly-wired transforms
|
Addressed all three Cursor Bugbot findings: High — OpenAI strict mode missing Medium — Missing
Low — Field named All 88 schema utils tests pass. |
e0a819a to
3804278
Compare
|
Addressed the review comments — let me know if you need anything else. |
|
Closing this from my side — it's gone stale and the underlying schema work has likely shifted. Happy to revisit later if there's still interest. |

Summary
Fixes #4472 — MCP tools break with Bedrock and Gemini because
extract_tool_info()usesgenerate_model_description(), which applies OpenAI-specific JSON schema transformations that these providers reject:additionalProperties: false— rejected by Bedrockrequired— breaks optional field semantics on Gemini/Bedrocktitleon nested objects — rejected by GeminiWhat this PR does
generate_tool_parameters_schema()inpydantic_schema_utils.py— a clean, provider-agnostic alternative togenerate_model_description()that:$ref/$defsinlinetitle,default, andadditionalPropertiesrequiredarray (does NOT force all fields required)extract_tool_info()incommon.pyto use the new function for theargs_schemapath, which flows throughsafe_tool_conversion()to all providers (Bedrock, Gemini, Anthropic, OpenAI, Azure)additionalProperties, optional fields not forced required, notitleon nested objects, refs resolved, null stripped, defaults stripped, descriptions preserved, types preservedContext
generate_model_description()is designed for OpenAI structured outputs (strict mode) and should not be used for the shared tool-parameter extraction pathWhy this approach
The
generate_model_description()function is correct for OpenAI structured outputs — it needsadditionalProperties: false, all-required, and strict mode. The problem is thatextract_tool_info()(shared across providers) was reusing it for tool parameter schemas. This PR separates the two concerns with a dedicated function.Test plan
TestGenerateToolParametersSchematests passtest_pydantic_schema_utils.pytests pass (no regressions)test_agent_utils.pytests pass (no regressions)Note
Medium Risk
Changes how tool
args_schemais converted into JSON Schema for all providers, which can affect tool-calling payload validation and optional/required semantics. Mitigated by focused unit tests, but still touches a cross-provider integration surface.Overview
Fixes MCP tool failures on Bedrock/Gemini by separating provider-agnostic tool parameter schema generation from OpenAI strict-mode schemas.
extract_tool_info()now uses a newgenerate_tool_parameters_schema()for Pydanticargs_schema, producing a cleaned schema (refs inlined,nullstripped, and removingtitle/default/additionalProperties) without forcing all fieldsrequired. OpenAI tool conversion keeps (and strengthens) its strict-mode pipeline by explicitly applyingstrip_unsupported_formats,ensure_type_in_schemas,convert_oneof_to_anyof,ensure_all_properties_required, andforce_additional_properties_false.Adds comprehensive tests for the new provider-agnostic schema output and a few strict-mode transform assertions.
Written by Cursor Bugbot for commit e0a819a. This will update automatically on new commits. Configure here.