Skip to content

fix(core): normalize MCP tool schemas to ensure type:'object' at root - #23383

Closed
netbrah wants to merge 2 commits into
google-gemini:mainfrom
netbrah:fix/mcp-tool-schema-normalization
Closed

netbrah wants to merge 2 commits into
google-gemini:mainfrom
netbrah:fix/mcp-tool-schema-normalization

Conversation

@netbrah

@netbrah netbrah commented Mar 21, 2026

Copy link
Copy Markdown

Fixes #23382

What

Add normalizeToolSchema() to ensure every MCP and extension-discovered tool parameter schema has type: 'object' at root level before it reaches the API.

Why

MCP servers from the ecosystem (Zapier, Linear, custom servers) can advertise schemas that are undefined, null, missing type, or have a non-object type at root. The Gemini API is lenient today, but:

  • Vertex AI in strict mode rejects non-conformant schemas
  • Any downstream consumer that validates JSON Schema strictly will fail
  • The JSON Schema spec requires tool parameter schemas to be objects

This is a zero-risk normalization — valid schemas pass through unchanged.

Changes

File Change
packages/core/src/tools/mcp-tool.ts Add exported normalizeToolSchema(), apply in DiscoveredMCPTool constructor
packages/core/src/tools/tool-registry.ts Apply normalizeToolSchema() at DiscoveredTool registration
packages/core/src/tools/mcp-tool.test.ts 10 test cases covering undefined, null, primitives, arrays, missing type, wrong type, valid schemas

Test Plan

  • npx vitest run packages/core/src/tools/mcp-tool.test.ts — 66 tests pass
  • Pre-commit hooks (ESLint + Prettier) pass
  • No behavior change for well-formed schemas

Made with Cursor

@netbrah
netbrah requested a review from a team as a code owner March 21, 2026 14:02
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where MCP tool parameter schemas might not conform to the JSON Schema specification, specifically regarding the type: 'object' requirement at the root. By introducing a normalization function, the system now ensures that all schemas meet this standard, preventing potential rejections from strict APIs like Vertex AI and ensuring compatibility with downstream consumers that perform strict JSON Schema validation. This change is designed to be low-risk, as valid schemas pass through without modification.

Highlights

  • Schema Normalization Function: A new normalizeToolSchema() function has been introduced to ensure all tool parameter schemas have type: 'object' at their root level.
  • Integration into MCP Tool Discovery: The normalizeToolSchema() function is now applied within the DiscoveredMCPTool constructor and during DiscoveredTool registration in the tool registry.
  • Comprehensive Test Coverage: Extensive test cases have been added for normalizeToolSchema(), covering various scenarios including undefined, null, primitive values, arrays, missing types, incorrect types, and valid schemas.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a normalizeToolSchema function to ensure tool parameter schemas are valid, which is a valuable improvement for robustness. The implementation is mostly correct, but I've identified a potential issue where an invalid schema could still be passed through under certain conditions. My review includes a suggestion to make the normalization more comprehensive.

Comment thread packages/core/src/tools/mcp-tool.ts Outdated
Comment on lines +125 to +134
const fallback: Record<string, unknown> = { type: 'object', properties: {} };
if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
return fallback;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- narrowed by typeof+Array guards above
const obj = schema as Record<string, unknown>;
if (obj['type'] !== 'object') {
return { ...obj, type: 'object', properties: obj['properties'] ?? {} };
}
return obj;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation of normalizeToolSchema can allow an invalid schema to pass through if type is already 'object' but the properties field is invalid (e.g., null or not an object). This could lead to downstream errors when the schema is consumed by stricter APIs.

The proposed change makes the normalization more robust by ensuring that type is always 'object' and properties is always a valid object. This better fulfills the function's goal of ensuring a valid tool parameter schema.

Suggested change
const fallback: Record<string, unknown> = { type: 'object', properties: {} };
if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
return fallback;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- narrowed by typeof+Array guards above
const obj = schema as Record<string, unknown>;
if (obj['type'] !== 'object') {
return { ...obj, type: 'object', properties: obj['properties'] ?? {} };
}
return obj;
const fallback: Record<string, unknown> = { type: 'object', properties: {} };
if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
return fallback;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- narrowed by typeof+Array guards above
const obj = schema as Record<string, unknown>;
const properties = obj['properties'];
const hasValidProperties =
properties && typeof properties === 'object' && !Array.isArray(properties);
return {
...obj,
type: 'object',
properties: hasValidProperties ? properties : {},
};
References
  1. Ensuring a robust and valid JSON schema structure is a foundational step towards ensuring that JSON schemas for configuration can accurately match their corresponding TypeScript interfaces.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — adopted the suggested approach. The function now always spreads to enforce both type: 'object' and valid properties, regardless of whether the original type was already correct. Added 3 test cases covering null, primitive, and array properties when type is already 'object'. Fixed in 3eae5ba.

@gemini-cli gemini-cli Bot added the area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality label Mar 21, 2026
netbrah added 2 commits March 21, 2026 22:01
MCP servers can advertise tool input schemas with missing `type`,
non-object `type`, or completely malformed structures. This causes
hard failures when the Gemini API validates strictly or when
downstream providers (Anthropic, OpenAI-compatible) reject the
request.

Add `normalizeToolSchema()` that ensures every tool parameter schema
has `type:'object'` at root level:
- Wraps undefined/null/primitive/array schemas with a valid fallback
- Injects `type:'object'` when missing from object schemas
- Preserves valid schemas unchanged

Applied at two layers for defense-in-depth:
1. DiscoveredMCPTool constructor (MCP tools)
2. DiscoveredTool registration in tool-registry (extension tools)

Made-with: Cursor
Address review feedback: ensure properties is always a valid object
even when type is already 'object'. Schemas with null, primitive, or
array properties now get corrected to an empty object.

Made-with: Cursor
@gemini-cli

gemini-cli Bot commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Hi there! Thank you for your interest in contributing to Gemini CLI.

To ensure we maintain high code quality and focus on our prioritized roadmap, we have updated our contribution policy (see Discussion #17383).

We only guarantee review and consideration of pull requests for issues that are explicitly labeled as 'help wanted'. All other community pull requests are subject to closure after 14 days if they do not align with our current focus areas. For this reason, we strongly recommend that contributors only submit pull requests against issues explicitly labeled as 'help-wanted'.

This pull request is being closed as it has been open for 14 days without a 'help wanted' designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding and for being part of our community!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality size/m A medium sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(core): MCP tool schemas with missing type:'object' cause provider rejection

2 participants