Make $ref dereferencing optional via FastMCP(dereference_refs=...)#3151
Make $ref dereferencing optional via FastMCP(dereference_refs=...)#3151
Conversation
WalkthroughAdds an opt-out for JSON Schema $ref dereferencing: FastMCP.init gains a Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 861a76ea3e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - `server`: The server instance this lifespan is managing | ||
|
|
||
| **Returns:** | ||
| - An empty dictionary as the lifespan result. |
There was a problem hiding this comment.
Revert edits under auto-generated python-sdk docs
This commit directly edits files under docs/python-sdk/**, but the repository guideline in /workspace/fastmcp/AGENTS.md says "Never modify docs/python-sdk/** (auto-generated)"; these edits are likely to be overwritten by the doc generator and create persistent drift/churn in future regenerations, so the change should be moved to the generator/source inputs instead of the generated output.
Useful? React with 👍 / 👎.
| if dereference: | ||
| schema = dereference_refs(schema) |
There was a problem hiding this comment.
Preserve root $ref normalization when dereference=False
Guarding dereference_refs() behind if dereference: removes the resolve_root_ref() fallback for schemas with a root-level $ref, so callers that now pass through compress_schema(..., dereference=False) can emit output schemas without a root type: object; this is a regression for recursive/self-referential return models when users set FastMCP(dereference_refs=False), because list_tools can return MCP-incompatible outputSchema payloads in that mode.
Useful? React with 👍 / 👎.
861a76e to
1c223e4
Compare
Test Failure AnalysisSummary: The test Root Cause: After This contradicts the test expectation (line 273-274) that Suggested Solution: Change line 401 in # Apply combined optimizations in a single tree traversal.
# Only prune unused $defs when dereferencing (since dereference removes all $defs anyway).
# When dereference=False, preserve $defs structure for clients that support $ref.
schema = _single_pass_optimize(
schema,
prune_titles=prune_titles,
prune_additional_properties=prune_additional_properties,
prune_defs=dereference, # Changed from True
)Why this fix is correct:
Detailed AnalysisTest flow ( Initial schema: {
"type": "object",
"properties": {
"keep": {"type": "string"},
"remove": {"$ref": "#/$defs/remove_def"},
},
"required": ["keep", "remove"],
"additionalProperties": False,
"$defs": {
"remove_def": {"type": "string"},
"unused_def": {"type": "number"},
},
}After
Actual result (missing $defs): {'properties': {'keep': {'type': 'string'}}, 'required': ['keep'], 'type': 'object'}Expected result (should preserve $defs): {
'type': 'object',
'properties': {'keep': {'type': 'string'}},
'required': ['keep'],
'$defs': {
'remove_def': {'type': 'string'},
'unused_def': {'type': 'number'},
}
}Test assertion: # $defs are preserved (dereferencing is handled by middleware, not compress_schema)
assert "$defs" in result # ← FAILSRelated Files
Updated analysis: Changed suggestion from |
6cb0282 to
0755b5e
Compare
compress_schema()unconditionally inlined all$ref/$defs, which can more than double schema size for complex Pydantic models. This was added for MCP client compatibility (VS Code Copilot doesn't handle$ref), but penalizes every server regardless of client.Dereferencing is now controlled by a per-server kwarg and implemented as middleware that runs at serve-time rather than at schema creation time. Schemas are stored with
$refintact and only inlined when sent to clients vialist_tools/list_resource_templates. The default isTrue(dereference on) since the non-compliant clients are popular and the failure mode — silent breakage only visible in certain clients — is much worse than the cost of larger schemas.Closes #3141