feat(mcp): switch anonymous sign-in nudge to elicitation#2716
Open
fahreddinozcan wants to merge 3 commits into
Open
feat(mcp): switch anonymous sign-in nudge to elicitation#2716fahreddinozcan wants to merge 3 commits into
fahreddinozcan wants to merge 3 commits into
Conversation
Replace the in-result markdown nudge with an MCP `elicitation/create` form request. The previous text-injection approach instructed the assistant to relay the message to the user, which some agents flagged as prompt injection. Elicitations are delivered out-of-band to the client UI, bypassing that surface entirely. - `maybeElicitAuthSignIn` fires after each tool response when the backend has set `ctx.shouldPrompt` (via `X-Context7-Auth-Prompt: 1`) and the caller is anonymous. - Gated on the client advertising the `elicitation` capability; no-op otherwise. - Includes a "Don't show this again" checkbox; opting out suppresses further nudges for the lifetime of the MCP process, keyed per session id / client IP. - Fire-and-forget: the elicitation never blocks or fails the surrounding tool response.
Replace the "Don't show this again" checkbox with a single-select radio between "I'll run the command to sign in" and "Continue anonymously with smaller limits". The radio makes the user's intent explicit and softens the protocol-fixed Accept/Decline labels — Accept now just submits the choice. Picking "Continue anonymously" (or declining/cancelling outright) suppresses further nudges for the lifetime of the MCP process. The command itself stays in the dialog message for the user to copy; the server does not attempt to drive the client to execute it.
Switch the elicitation's choice field from `oneOf` with separate `const`/`title` entries to the simpler `enum: [...]` shape. Cursor's elicitation UI does not render the `oneOf`-with-titles pattern correctly — it falls back to a plain text input with the const string as the default value. The flat enum form is rendered as a proper dropdown / radio across the clients we tested. The user-facing strings are now also the enum const values, so the elicitation response surfaces the chosen label directly. Suppression logic compares against the same string constants.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the in-tool-result sign-in nudge introduced in #2604 with an MCP
elicitation/createform request. The previous markdown block instructed the assistant to relay the message to the user and offer to run the setup command, which some agents (notably Claude Code) flagged as prompt injection on the tool result. Elicitations are delivered out-of-band to the client UI, so they bypass that path entirely.What changes
maybeElicitAuthSignIn(server, ctx)is called fromresolve-library-idandquery-docsafter the response is built. The tool result text is now clean (no markdown nudge).ctx.shouldPromptviaX-Context7-Auth-Prompt: 1and the caller is anonymous — same trigger condition as before, just a different surface.getClientCapabilities().elicitation. Clients that don't advertise elicitation see no nudge — safe no-op.npx ctx7 setup ...command from the dialog and runs it in their terminal.sessionId/clientIp. Decline / Cancel produce the same suppression.void ... .catch(...). Never blocks or alters the surrounding tool response.Deployment dependency
This PR is dormant until the backend re-enables the prompt header. The corresponding one-line flip lives in context7app at
lib/api/v2/anonymousSignInPrompt.ts(setENABLED = true). Without that,ctx.shouldPromptis never set andmaybeElicitAuthSignInis a no-op.Known limitations
accept/decline/canceland gives the client full control over button labels. There is no way for the server to rename Accept/Decline to "Close" or "OK", or to render a single-button dialog (spec ref). The two-option radio mitigates the confusion because the user has already chosen intent before clicking Accept.Test plan
pnpm exec tsc --noEmitinpackages/mcp— passespnpm exec vitest runinpackages/mcp— 12/12 passesENABLED = truein the backend, make 5 anonymous calls, confirm elicitation dialog appears with thenpx ctx7 setupcommand and the two-option radio