fix(mcp): sync required array with properties in tool schemas (#754)
* fix(mcp): sync required array with properties in tool schemas MCP servers can emit schemas where the required array contains keys not present in properties. This causes API 400 errors: "Extra required key 'X' supplied." - Add sanitizeSchemaRequired() to filter required arrays - Apply it to MCP tool inputJSONSchema before sending to API - Also fix filterSwarmFieldsFromSchema to update required after removing properties Fixes #525 * test: add MCP schema required sanitization test
This commit is contained in:
@@ -111,11 +111,60 @@ function filterSwarmFieldsFromSchema(
|
||||
delete filteredProps[field]
|
||||
}
|
||||
filtered.properties = filteredProps
|
||||
|
||||
// Keep `required` in sync after removing properties
|
||||
if (Array.isArray(filtered.required)) {
|
||||
filtered.required = filtered.required.filter(
|
||||
(key: string) => key in filteredProps,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure `required` only lists keys present in `properties`.
|
||||
* MCP servers may emit schemas where these are out of sync, causing
|
||||
* API 400 errors ("Extra required key supplied").
|
||||
* Recurses into nested object schemas.
|
||||
*/
|
||||
function sanitizeSchemaRequired(
|
||||
schema: Anthropic.Tool.InputSchema,
|
||||
): Anthropic.Tool.InputSchema {
|
||||
if (!schema || typeof schema !== 'object') {
|
||||
return schema
|
||||
}
|
||||
|
||||
const result = { ...schema }
|
||||
const props = result.properties as Record<string, unknown> | undefined
|
||||
|
||||
if (props && Array.isArray(result.required)) {
|
||||
result.required = result.required.filter(
|
||||
(key: string) => key in props,
|
||||
)
|
||||
}
|
||||
|
||||
// Recurse into nested object properties
|
||||
if (props) {
|
||||
const sanitizedProps = { ...props }
|
||||
for (const [key, value] of Object.entries(sanitizedProps)) {
|
||||
if (
|
||||
value &&
|
||||
typeof value === 'object' &&
|
||||
(value as Record<string, unknown>).type === 'object'
|
||||
) {
|
||||
sanitizedProps[key] = sanitizeSchemaRequired(
|
||||
value as Anthropic.Tool.InputSchema,
|
||||
)
|
||||
}
|
||||
}
|
||||
result.properties = sanitizedProps
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export async function toolToAPISchema(
|
||||
tool: Tool,
|
||||
options: {
|
||||
@@ -156,7 +205,7 @@ export async function toolToAPISchema(
|
||||
// Use tool's JSON schema directly if provided, otherwise convert Zod schema
|
||||
let input_schema = (
|
||||
'inputJSONSchema' in tool && tool.inputJSONSchema
|
||||
? tool.inputJSONSchema
|
||||
? sanitizeSchemaRequired(tool.inputJSONSchema as Anthropic.Tool.InputSchema)
|
||||
: zodToJsonSchema(tool.inputSchema)
|
||||
) as Anthropic.Tool.InputSchema
|
||||
|
||||
|
||||
Reference in New Issue
Block a user