Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/gemini-mcp-schema-required.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@kilocode/cli": patch
---

Prevent Gemini requests from failing when MCP tool schemas contain `required` fields without matching object properties.
10 changes: 8 additions & 2 deletions packages/opencode/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1487,9 +1487,15 @@ export function schema(model: Provider.Model, schema: JSONSchema7): JSONSchema7
}

// Filter required array to only include fields that exist in properties
if (result.type === "object" && result.properties && Array.isArray(result.required)) {
result.required = result.required.filter((field: any) => field in result.properties)
// kilocode_change start - Gemini rejects required entries without matching properties
if (result.type === "object" && Array.isArray(result.required)) {
const properties = isPlainObject(result.properties) ? result.properties : undefined
result.required = properties ? result.required.filter((field: any) => field in properties) : []
if (result.required.length === 0) {
delete result.required
}
}
// kilocode_change end

if (result.type === "array" && !hasCombiner(result)) {
if (result.items == null) {
Expand Down
45 changes: 45 additions & 0 deletions packages/opencode/test/provider/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,51 @@ describe("ProviderTransform.schema - gemini non-object properties removal", () =
expect(result.properties.data.required).toEqual(["name"])
})

test("removes required from object array items with no properties", () => {
const schema = {
type: "object",
properties: {
issue_fields: {
type: "array",
items: {
type: "object",
required: ["type"],
},
},
},
} as any

const result = ProviderTransform.schema(geminiModel, schema) as any

expect(result.properties.issue_fields.items.type).toBe("object")
expect(result.properties.issue_fields.items.required).toBeUndefined()
})

test("sanitizes gemini schemas routed through the Kilo Gateway", () => {
const gatewayGeminiModel = {
providerID: "kilocode",
api: {
id: "google/gemini-2.5-pro",
},
} as any
const schema = {
type: "object",
properties: {
issue_fields: {
type: "array",
items: {
type: "object",
required: ["type"],
},
},
},
} as any

const result = ProviderTransform.schema(gatewayGeminiModel, schema) as any

expect(result.properties.issue_fields.items.required).toBeUndefined()
})

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

please move the new tests to a new file in a kilocode folder

test("does not affect non-gemini providers", () => {
const openaiModel = {
providerID: "openai",
Expand Down
Loading