# fix\(server\): show Claude MCP elicitations on the approval card · PR \#21903 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/21903)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: open

Source repository: Unavailable fork

Source branch: fix/claude-mcp-elicitation-approval

Target branch: main

Head commit: cac644c5d777501043545523f8bcf3f62cdcd1b0

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/21903)

[Commits](https://git.cafe/pingdotgg/t3code/pull/21903/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/21903/diffs?format=markdown)

## Description

---

## Problem

On Claude threads, any MCP tool that asks the user to confirm something gets `decline` back right away, and the user never sees a prompt. The same tool on Codex shows the app-access card. The Claude adapter never registered the Agent SDK's `onElicitation` callback, so the SDK declines on its own.

## Change

The adapter now registers `onElicitation`, opens the existing `mcp-elicitation` card with Cancel, Decline and Approve, and waits for the user to pick one.

A few calls I made:

- Claude uses Codex's `toMcpElicitationResponse` to decide what counts as a plain approval, so the two providers agree. That also handles JonasFocus's point on #14895: `allow_once`, `Allow` and `accept_once` now work.
- A form with no fields is a plain confirm. Approve answers it with `{ action: "accept", content: {} }`.
- The card can only say yes or no, so it never sends a value the user didn't see. Schema defaults are dropped, since one could be `always` or a refusal. CodeRabbit caught this.
- URL mode, a missing schema, and forms that need real input are declined without showing a card.
- Approve is always one-time. No session or always grants, and no Claude permission rules get written.
- If the session stops while the card is open, the request is cancelled. A response that arrives after that gets the usual unknown-request error.
- MCP servers that return `input_required` from a tool call go through the same callback. I checked this in the Claude Code 2.1.304 bundle.

Not covered: URL-mode auth, forms with real inputs, and session or always grants. Also, the shared helper picks an option like "disallow" if it comes before the allow option. That fails safe, since the server gets a refusal, and JonasFocus suggested fixing it for both providers in a separate PR.

## Scope and approval

Fixes #14878, following the scope set in the [triage comment](https://github.com/pingdotgg/t3code/issues/14878#issuecomment-5960949029): one-time accept only, reuse the existing card, and decline anything we can't handle. This redoes #14895, which was closed in the October cleanup, on current main.

## Verification

- Focused adapter tests cover: the card waiting and accepting only after Approve, Decline, Cancel, URL and value forms declined with no card, schema defaults never sent, abort before an answer, session stop with the card open, and a late response. The Claude, Codex and elicitation-helper test files pass, and the server typecheck is clean.
- In a local web dev build, a Claude Haiku 5.5 thread called a test MCP tool that asks for a plain confirm (`{ type: "object", properties: {} }`). On main (f740a97947) the tool got `{"action":"decline"}` back after 7.6s and no card showed up. With this branch the card showed up, and Approve sent `{"action":"accept","content":{}}` back to the server.
- Not checked by hand: Decline and Cancel (the tests cover both), desktop, and mobile. Desktop and mobile show the same card Codex already uses.

| Before (main) | After: card while waiting | After: result of Approve |
| --- | --- | --- |
| <img width="300" alt="On main the tool returns decline and no card is shown" src="https://gist.githubusercontent.com/chrischriscris/4511200577d6f3aa544e0fb4c56de72f/raw/1e200f47d175fe30522542e0122e670263a05d4a/before.png"> | <img width="300" alt="Claude thread showing the app-access card for the MCP elicitation" src="https://gist.githubusercontent.com/chrischriscris/4511200577d6f3aa544e0fb4c56de72f/raw/c1e5e562be5f0d7c7fb7eda42ac5679bfe4a2247/card.png"> | <img width="300" alt="Tool result after Approve showing action accept" src="https://gist.githubusercontent.com/chrischriscris/4511200577d6f3aa544e0fb4c56de72f/raw/c1e5e562be5f0d7c7fb7eda42ac5679bfe4a2247/result.png"> |
| The tool is declined right away and the user never sees a prompt. | The existing app-access card, with Decline, Approve and Cancel in the menu. | The server gets `accept` only after Approve is clicked. |

Written by claude-opus-5-5 via Claude Code, running in T3 Code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

