diff --git a/apps/sim/lib/knowledge/mcp/tool-arguments.test.ts b/apps/sim/lib/knowledge/mcp/tool-arguments.test.ts new file mode 100644 index 00000000000..bca0b850c9f --- /dev/null +++ b/apps/sim/lib/knowledge/mcp/tool-arguments.test.ts @@ -0,0 +1,28 @@ +/** + * @vitest-environment node + */ +import { describe, expect, it } from 'vitest' +import { toolCallInputIssues } from '@/lib/knowledge/mcp/tool-arguments' + +const searchCall = (args: Record) => ({ + jsonrpc: '2.0', + id: 1, + method: 'tools/call', + params: { name: 'search', arguments: args }, +}) + +describe('toolCallInputIssues', () => { + it('names the fields a native query carries that the schema does not know', () => { + const issues = toolCallInputIssues( + searchCall({ + query: 'roadmap', + nativeQueries: [{ provider: 'jira', query: 'roadmap', limit: 5 }], + }) + ) + expect(issues?.issues).toContainEqual({ + code: 'unrecognized_keys', + path: 'nativeQueries.0', + keys: ['limit'], + }) + }) +}) diff --git a/apps/sim/lib/knowledge/mcp/tool-arguments.ts b/apps/sim/lib/knowledge/mcp/tool-arguments.ts index 0e0603ed0ae..80ee4ee4d2e 100644 --- a/apps/sim/lib/knowledge/mcp/tool-arguments.ts +++ b/apps/sim/lib/knowledge/mcp/tool-arguments.ts @@ -87,9 +87,18 @@ export function repairToolCallMessage(message: Record) { return { message: { ...message, params: { ...call, arguments: args } }, repairs: [...repairs] } } +/** + * Unrecognized field names logged per schema issue, each cut short. The schema caps native queries + * at nine, so a rejection's log line stays bounded. + */ +const MAX_LOGGED_KEYS = 5 +const MAX_LOGGED_KEY_CHARACTERS = 64 + /** * Where a tool call's arguments fail its input schema, as field paths and issue codes without - * values. The SDK rejects such a call before the tool runs, so nothing else records it. + * values, plus the names of fields the schema does not know, so a repeated client mistake can be + * told apart from a new one. The SDK rejects such a call before the tool runs, so nothing else + * records it. */ export function toolCallInputIssues(message: Record) { const call = readToolCall(message) @@ -99,6 +108,14 @@ export function toolCallInputIssues(message: Record) { if (parsed.success) return undefined return { toolName: call.name, - issues: parsed.error.issues.map(({ code, path }) => ({ code, path: path.join('.') })), + issues: parsed.error.issues.map((issue) => ({ + code: issue.code, + path: issue.path.join('.'), + ...(issue.code === 'unrecognized_keys' && { + keys: issue.keys + .slice(0, MAX_LOGGED_KEYS) + .map((key) => key.slice(0, MAX_LOGGED_KEY_CHARACTERS)), + }), + })), } }