From eecf73dc77eb8166fd26e4afa9a1cd6608c0a401 Mon Sep 17 00:00:00 2001 From: murashit Date: Sat, 18 Jul 2026 18:52:44 +0900 Subject: [PATCH] fix(chat): preserve accepted MCP elicitation URLs --- .../domain/pending-requests/result-items.ts | 5 +-- .../chat/app-server/inbound/handler.test.ts | 33 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/features/chat/domain/pending-requests/result-items.ts b/src/features/chat/domain/pending-requests/result-items.ts index 2c3125ed..cd3e8d46 100644 --- a/src/features/chat/domain/pending-requests/result-items.ts +++ b/src/features/chat/domain/pending-requests/result-items.ts @@ -67,7 +67,7 @@ export function createMcpElicitationResultItem( ...definedProp("turnId", elicitation.params.turnId ?? undefined), provenance: { source: "localUser", channel: "response", interaction: "userInputResponse", sourceId: String(elicitation.requestId) }, executionState: accepted ? "completed" : "failed", - questions: mcpElicitationResultQuestions(elicitation, accepted ? content : null), + questions: mcpElicitationResultQuestions(elicitation, accepted, accepted ? content : null), }; } @@ -98,6 +98,7 @@ function mcpElicitationResultText(elicitation: PendingMcpElicitation, action: Mc function mcpElicitationResultQuestions( elicitation: PendingMcpElicitation, + accepted: boolean, content: Record | null, ): readonly ThreadStreamUserInputQuestionResult[] { if (elicitation.params.mode === "url") { @@ -106,7 +107,7 @@ function mcpElicitationResultQuestions( id: "url", header: "URL", question: elicitation.params.message, - ...(content ? { answer: elicitation.params.url } : {}), + ...(accepted ? { answer: elicitation.params.url } : {}), }, ]; } diff --git a/tests/features/chat/app-server/inbound/handler.test.ts b/tests/features/chat/app-server/inbound/handler.test.ts index 7ed2155e..8833371c 100644 --- a/tests/features/chat/app-server/inbound/handler.test.ts +++ b/tests/features/chat/app-server/inbound/handler.test.ts @@ -807,6 +807,37 @@ describe("ChatInboundHandler", () => { }); }); + it("records the accepted URL in the MCP elicitation result item", () => { + const state = chatStateFixture(); + const respondToServerRequest = vi.fn(() => true); + const handler = handlerForState(state, { respondToServerRequest }); + + handler.handleServerRequest({ + id: 46, + method: "mcpServer/elicitation/request", + params: { + threadId: "thread-active", + turnId: "turn-active", + serverName: "github", + mode: "url", + _meta: null, + message: "Confirm in browser", + url: "https://example.com/confirm", + elicitationId: "elicit-1", + }, + }); + + handler.resolveMcpElicitation(46, "accept"); + + expect(respondToServerRequest).toHaveBeenCalledWith(46, { action: "accept", content: null, _meta: null }); + expect(chatStateThreadStreamItems(handler.currentState()).at(-1)).toMatchObject({ + kind: "userInputResult", + text: "MCP request from github accepted.", + executionState: "completed", + questions: [{ id: "url", answer: "https://example.com/confirm" }], + }); + }); + it("declines MCP elicitation URL server requests", () => { const state = chatStateFixture(); const respondToServerRequest = vi.fn(() => true); @@ -835,7 +866,9 @@ describe("ChatInboundHandler", () => { kind: "userInputResult", text: "MCP request from github declined.", executionState: "failed", + questions: [{ id: "url" }], }); + expect(chatStateThreadStreamItems(handler.currentState()).at(-1)).not.toHaveProperty("questions.0.answer"); }); it("ignores missing requestUserInput ids", () => {