Gemini: sanitizeGemini doesn't handle anyOf/const patterns in MCP tool schemas #8944

Open
opened 2026-02-16 18:11:14 -05:00 by yindo · 0 comments
Owner

Originally created by @nxxxsooo on GitHub (Feb 9, 2026).

Originally assigned to: @thdxr on GitHub.

Bug Description

When using Google Gemini models (both via @ai-sdk/google API key and antigravity OAuth), MCP tools with anyOf/const patterns in their JSON Schema cause Gemini API to reject the request with errors like:

GenerateContentRequest.tools[0].function_declarations[32].parameters.properties[format].any_of[0].enum: only allowed for STRING type

Root Cause

ProviderTransform.schema() in packages/opencode/src/provider/transform.ts has a sanitizeGemini function (line 772) that converts integer enums to string enums, but does not flatten anyOf/const patterns that Gemini API rejects.

MCP servers (notably Obsidian Local REST API) generate tool schemas like:

{
  "format": {
    "anyOf": [
      { "const": "json" },
      { "const": "markdown" }
    ]
  }
}

Gemini expects this to be:

{
  "format": {
    "type": "string",
    "enum": ["json", "markdown"]
  }
}

The same issue affects fields with anyOf + enum patterns:

{
  "operation": {
    "anyOf": [
      { "const": "append", "description": "..." },
      { "const": "prepend", "description": "..." },
      { "const": "replace", "description": "..." }
    ]
  }
}

Affected Tools

All Obsidian REST API MCP tools with enum-like fields:

  • GetActiveFile / GetVaultFileformat field
  • PatchActiveFile / PatchVaultFilecontentType, operation, targetType fields
  • SearchVaultqueryType field
  • ExecuteTemplatecreateFile field

Suggested Fix

In sanitizeGemini, add handling for anyOf/oneOf arrays of const values:

// Flatten anyOf/oneOf with const values into enum
for (const keyword of ['anyOf', 'any_of', 'oneOf', 'one_of']) {
  if (Array.isArray(result[keyword])) {
    const constants = result[keyword]
      .filter((item: any) => item && typeof item === 'object' && 'const' in item)
    if (constants.length === result[keyword].length && constants.length > 0) {
      result.type = 'string'
      result.enum = constants.map((item: any) => String(item.const))
      delete result[keyword]
    }
  }
}

Environment

  • OpenCode version: 1.1.53
  • Provider: @ai-sdk/google (both API key and antigravity plugin)
  • MCP server: Obsidian Local REST API
  • OS: macOS (Apple Silicon)

Workaround

Currently the only workaround is to disable the problematic MCP server's tools using permissions, but this affects all providers — not just Gemini.

Originally created by @nxxxsooo on GitHub (Feb 9, 2026). Originally assigned to: @thdxr on GitHub. ## Bug Description When using Google Gemini models (both via `@ai-sdk/google` API key and antigravity OAuth), MCP tools with `anyOf`/`const` patterns in their JSON Schema cause Gemini API to reject the request with errors like: ``` GenerateContentRequest.tools[0].function_declarations[32].parameters.properties[format].any_of[0].enum: only allowed for STRING type ``` ## Root Cause `ProviderTransform.schema()` in `packages/opencode/src/provider/transform.ts` has a `sanitizeGemini` function (line 772) that converts integer enums to string enums, but **does not flatten `anyOf`/`const` patterns** that Gemini API rejects. MCP servers (notably [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api)) generate tool schemas like: ```json { "format": { "anyOf": [ { "const": "json" }, { "const": "markdown" } ] } } ``` Gemini expects this to be: ```json { "format": { "type": "string", "enum": ["json", "markdown"] } } ``` The same issue affects fields with `anyOf` + `enum` patterns: ```json { "operation": { "anyOf": [ { "const": "append", "description": "..." }, { "const": "prepend", "description": "..." }, { "const": "replace", "description": "..." } ] } } ``` ## Affected Tools All Obsidian REST API MCP tools with enum-like fields: - `GetActiveFile` / `GetVaultFile` → `format` field - `PatchActiveFile` / `PatchVaultFile` → `contentType`, `operation`, `targetType` fields - `SearchVault` → `queryType` field - `ExecuteTemplate` → `createFile` field ## Suggested Fix In `sanitizeGemini`, add handling for `anyOf`/`oneOf` arrays of `const` values: ```typescript // Flatten anyOf/oneOf with const values into enum for (const keyword of ['anyOf', 'any_of', 'oneOf', 'one_of']) { if (Array.isArray(result[keyword])) { const constants = result[keyword] .filter((item: any) => item && typeof item === 'object' && 'const' in item) if (constants.length === result[keyword].length && constants.length > 0) { result.type = 'string' result.enum = constants.map((item: any) => String(item.const)) delete result[keyword] } } } ``` ## Environment - OpenCode version: 1.1.53 - Provider: `@ai-sdk/google` (both API key and antigravity plugin) - MCP server: Obsidian Local REST API - OS: macOS (Apple Silicon) ## Workaround Currently the only workaround is to disable the problematic MCP server's tools using permissions, but this affects all providers — not just Gemini.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#8944