Closes #60162. MCP servers whose tool `inputSchema` uses `$ref`/`$defs` (e.g., Notion MCP v2.x, and any server using Zod/Pydantic-generated schemas) are silently rejected with: ``` ERROR Schema cannot be made compatible because it contains "$ref" ``` The affected tools are dropped from the agent panel — the user never sees them and there is no user-visible error. ## Root cause `adapt_to_json_schema_subset` rejects any schema containing `$ref` via `UNSUPPORTED_KEYS`: ```rust const UNSUPPORTED_KEYS: [&str; 4] = ["if", "then", "else", "$ref"]; ``` This is hit by every provider that uses `JsonSchemaSubset` format (Google Gemini, xAI Grok, OpenAI-compatible proxies, Vercel AI Gateway, Copilot Chat for Google/xAI vendors, OpenRouter for gemini/grok models). Providers using `JsonSchema` (Anthropic direct, OpenAI direct) don't hit this check — `$ref` is passed through to the API, which may or may not handle it correctly. This is not an edge case. Every modern MCP server using Zod (TypeScript), Pydantic (Python), or JSON Schema with shared definitions generates `$ref`/`$defs` in tool schemas. ## Fix Add a `resolve_refs` step in `adapt_schema_to_format` that dereferences all `$ref` pointers using the document's own `$defs` (or legacy `definitions`) map, making the schema self-contained before format-specific processing. Applied at the entry point so both `JsonSchema` and `JsonSchemaSubset` formats benefit. **Scope note:** previously `JsonSchema` providers (Anthropic direct, OpenAI direct) received the raw `$ref`/`$defs` and were expected to handle it themselves — which most do not. After this change, both paths receive a self-contained schema with refs inlined. This is intentional: it fixes the same root cause for both paths and avoids provider-specific behavior divergence. Supported `$ref` forms: - `#/$defs/<name>` (JSON Schema draft 2019-09+) - `#/definitions/<name>` (draft 4-7 legacy) Edge cases: - **Nested `$ref`** (definition references another definition): resolved recursively. - **Sibling properties alongside `$ref`** (e.g. `{ "$ref": "...", "description": "..." }`, legal under draft 2019-09+): merged onto the resolved definition, with siblings overriding the definition's keys. - **Cyclic references** (A → B → A, or self-referential schemas like a Tree node): replaced with an empty schema `{}` ("any JSON value"). The tool still works, just without type info for that recursive field. - **Unsupported `$ref` forms** (e.g., external URLs): returns an error with a clear message. - **Missing definition target**: returns an error naming the missing ref. ## Testing Added 10 unit tests in `crates/language_model_core/src/tool_schema.rs` that cover the patterns produced by Zod/Pydantic-generated MCP schemas: - `test_refs_are_resolved_via_adapt_schema_to_format` — basic `$ref` → `$defs` resolution - `test_refs_in_defs_are_resolved` — nested `$ref` (definition references another definition) - `test_refs_in_array_items_are_resolved` — `$ref` inside `array.items` - `test_legacy_definitions_prefix_is_supported` — old `#/definitions/<name>` prefix - `test_schema_without_defs_is_unchanged` — schemas with no `$defs` are unaffected - `test_refs_fail_for_unsupported_prefix` — external URL refs error clearly - `test_refs_fail_for_missing_definition` — missing target errors clearly - `test_cyclic_refs_are_replaced_with_empty_schema` — A → B → A cycle replaced with `{}` - `test_self_referential_ref_is_replaced_with_empty_schema` — Tree-like self-ref replaced with `{}` - `test_ref_sibling_properties_are_preserved` — sibling properties alongside `$ref` are merged onto the resolved definition Existing tests (which call `adapt_to_json_schema_subset` and `preprocess_json_schema` directly) are unaffected — the fix is additive at the `adapt_schema_to_format` level. ## Disclosure I used an LLM to help draft the implementation and tests. I reviewed and understand the change — it adds one new function (`resolve_refs`) with two helpers (`parse_ref`, `resolve_refs_recursive`), plus unit tests. Release Notes: - Fixed MCP tools with `$ref`/`$defs` in their `inputSchema` being silently rejected by providers using the JSON Schema Subset format (Google Gemini, xAI Grok, OpenAI-compatible proxies, etc.). Tools from servers like Notion MCP v2.x, and any server using Zod or Pydantic-generated schemas, now work correctly. --------- Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de> Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
Zed
Welcome to Zed, a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.
Installation
On macOS, Linux, and Windows you can download Zed directly or install Zed via your local package manager (macOS/Linux/Windows).
Other platforms are not yet available:
- Web (tracking discussion)
Developing Zed
Contributing
See CONTRIBUTING.md for ways you can contribute to Zed.
Also... we're hiring! Check out our jobs page for open roles.
Licensing
Zed source code is licensed primarily under GPL-3.0-or-later, with Apache-2.0 components where marked.
License information for third party dependencies must be correctly provided for CI to pass.
We use cargo-about to automatically comply with open source licenses. If CI is failing, check the following:
- Is it showing a
no license specifiederror for a crate you've created? If so, addpublish = falseunder[package]in your crate's Cargo.toml. - Is the error
failed to satisfy license requirementsfor a dependency? If so, first determine what license the project has and whether this system is sufficient to comply with this license's requirements. If you're unsure, ask a lawyer. Once you've verified that this system is acceptable add the license's SPDX identifier to theacceptedarray inscript/licenses/zed-licenses.toml. - Is
cargo-aboutunable to find the license for a dependency? If so, add a clarification field at the end ofscript/licenses/zed-licenses.toml, as specified in the cargo-about book.
Sponsorship
Zed is developed by Zed Industries, Inc., a for-profit company.
If you’d like to financially support the project, you can do so via GitHub Sponsors. Sponsorships go directly to Zed Industries and are used as general company revenue. There are no perks or entitlements associated with sponsorship.