diff --git a/src/validation/wire-schema.test.ts b/src/validation/wire-schema.test.ts index 98fc4d7b..0c8a321b 100644 --- a/src/validation/wire-schema.test.ts +++ b/src/validation/wire-schema.test.ts @@ -117,6 +117,24 @@ describe('wireSchemaErrors', () => { ).toEqual([]); }); + it('accepts extension result types through the generic result envelope', () => { + expect( + wireSchemaErrors( + DRAFT_PROTOCOL_VERSION, + { + jsonrpc: '2.0', + id: 3, + result: { + resultType: 'task', + taskId: 'task-1', + status: 'working' + } + }, + 'tools/call' + ) + ).toEqual([]); + }); + it('accepts a JSON-RPC batch under 2025-03-26 and reports per-element errors', () => { expect( wireSchemaErrors('2025-03-26', [ diff --git a/src/validation/wire-schema.ts b/src/validation/wire-schema.ts index 8b45849d..bf3dc5f9 100644 --- a/src/validation/wire-schema.ts +++ b/src/validation/wire-schema.ts @@ -261,15 +261,23 @@ export function wireSchemaErrors( if (msg.result !== undefined) { // SEP-2322 (MRTR): any request may be answered with an InputRequiredResult - // instead of its method's result type; discriminate on resultType. + // instead of its method's result type; discriminate on resultType. Results + // introduced by extensions use the same open discriminator and are checked + // against the generic result envelope until their schema is available here. + const resultType = (msg.result as Record | null) + ?.resultType; const inputRequired = - (msg.result as Record | null)?.resultType === - 'input_required' && 'InputRequiredResult' in spec.defs; - const resultDefName = inputRequired - ? 'InputRequiredResult' - : requestMethod !== undefined - ? spec.resultDefs.get(requestMethod) - : undefined; + resultType === 'input_required' && 'InputRequiredResult' in spec.defs; + const extensionResult = + typeof resultType === 'string' && + resultType !== 'complete' && + resultType !== 'input_required'; + let resultDefName: string | undefined; + if (inputRequired) { + resultDefName = 'InputRequiredResult'; + } else if (!extensionResult && requestMethod !== undefined) { + resultDefName = spec.resultDefs.get(requestMethod); + } if (resultDefName) { const typed = validateAgainst(resultDefName, msg.result).map( (e) => `${e} (result of '${requestMethod}')`