Fix: resolve root-level $ref in outputSchema for MCP spec compliance#2727
Fix: resolve root-level $ref in outputSchema for MCP spec compliance#2727jlowin merged 1 commit intorelease/2.xfrom
Conversation
WalkthroughThis pull request adds a utility function to resolve root-level JSON Schema Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/fastmcp/utilities/json_schema.py (1)
7-43: Consider shallow copy implications and potential $defs conflict.The implementation correctly resolves root-level
$refreferences for MCP compliance. However, there are two edge cases to be aware of:
Shallow copy on line 39:
dict(defs[def_name])creates a shallow copy. If the referenced definition contains nested dicts or lists, they'll be shared between the original and resolved schema. This is likely acceptable for read-only schema generation, but could cause issues if schemas are modified after resolution.$defs overwrite on line 41: If the referenced definition already contains its own
$defskey (though uncommon in typical JSON Schema patterns), it will be overwritten by the root-level$defs. Consider checking for this case or documenting the behavior.🔎 Optional enhancement to preserve nested $defs
If you want to handle the edge case where a referenced definition might have its own
$defs:# Create a new schema by copying the referenced definition resolved = dict(defs[def_name]) - # Preserve $defs for nested references (other fields may still use them) - resolved["$defs"] = defs + # Preserve $defs for nested references, merging if necessary + if "$defs" in resolved: + # Merge with root $defs, preferring root definitions + resolved["$defs"] = {**resolved["$defs"], **defs} + else: + resolved["$defs"] = defs return resolved
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
tests/tools/test_tool.pyis excluded by none and included by nonetests/utilities/test_json_schema.pyis excluded by none and included by none
📒 Files selected for processing (2)
src/fastmcp/tools/tool.pysrc/fastmcp/utilities/json_schema.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Use Python ≥ 3.10 with full type annotations
Never use bareexcept- be specific with exception types
Files:
src/fastmcp/tools/tool.pysrc/fastmcp/utilities/json_schema.py
🧬 Code graph analysis (1)
src/fastmcp/tools/tool.py (1)
src/fastmcp/utilities/json_schema.py (2)
compress_schema(240-270)resolve_root_ref(7-43)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Run tests: Python 3.10 on ubuntu-latest
- GitHub Check: Run tests with lowest-direct dependencies
- GitHub Check: Run tests: Python 3.10 on windows-latest
- GitHub Check: Run tests: Python 3.13 on ubuntu-latest
🔇 Additional comments (3)
src/fastmcp/utilities/json_schema.py (1)
4-4: LGTM: Import addition is appropriate.The
Anyimport is necessary for the type annotations in the newresolve_root_reffunction.src/fastmcp/tools/tool.py (2)
35-35: LGTM: Import addition is clean.The
resolve_root_refimport is added cleanly alongside the existingcompress_schemaimport.
562-564: Excellent placement for root $ref resolution.The call to
resolve_root_refis correctly positioned after schema compression and before returning theParsedFunctioninstance. This ensures that self-referential Pydantic models produce MCP-compliant schemas with"type": "object"at the root level while preserving$defsfor nested references. The explanatory comment is helpful for future maintainers.
Cherry-pick of #2720 to release/2.x.
Resolves root-level
$refin outputSchema for self-referential Pydantic models to meet MCP spec requirement fortype: objectat root.Closes #2455