MCP Elicitation
A server asking the user for structured input mid-run. Useful, and a good phishing surface — the prompt text is written by the server and appears wearing your client’s chrome, so the requesting server is named outside its own copy.
src/components/ui/mcp-elicitation.tsxAbout
From the component's own source, where it was written.
A server asking the user for structured input, mid-run.
MCP elicitation lets a server pause and request data it does not have — a confirmation, a missing field, a choice between branches. It is a genuinely useful capability and a genuinely good phishing surface: the prompt text is written by the server, and it appears inside your client, wearing your client's chrome.
Two rules follow from that, and they are the reason this is a component rather than a SchemaForm in a dialog:
**The requesting server is named at the top, outside the server's own copy.** A message that says "your session expired, re-enter your token" is indistinguishable from the client asking, unless the client says who is asking.
**A field that looks like a credential is refused, not collected.** No legitimate elicitation needs your password, and a component that renders that field anyway is the attack working. The request still displays; the field is replaced with a warning.
Install
npx astralyx-ui add mcp-elicitation
Usage
import { McpElicitation } from '@/components/ui/mcp-elicitation'
<McpElicitation server="postgres" message={request.message} schema={request.schema} onSubmit={reply} />Composer
Change the props and the source below follows.
postgres is asking for information
Before running the migration I need to know which environment to target.
This request asks for api_key. No server should need that — the field has not been rendered.
No props to configure.
<McpElicitation
server="postgres"
message={request.message}
schema={request.schema}
onSubmit={reply}
onDecline={decline}
/>Examples
A request that also asks for an API key
<McpElicitation server="postgres" message={message} schema={schema} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
McpElicitation
Extends Omit<ComponentProps<'div'>, 'onSubmit'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| server | string | required | Named at the top, outside the server’s own message. “Your session expired, re-enter your token” is indistinguishable from the client asking unless the client says who is asking. |
| message | ReactNode | required | Untrusted text from the server. Rendered, never interpreted. |
| schema | JsonSchema | required | What it wants back. |
| onSubmit | (value: Record<string, unknown>) => void | — | — |
| onDecline | () => void | — | — |
| busy | boolean | false | — |
| submitLabel | string | 'Send' | — |
| declineLabel | string | 'Decline' | — |
| askingLabel | (server: string) => ReactNode | (name) => ( <> <code className="font-mono font-medium">{name}</code> is asking for information </> ) | — |
| credentialWarning | (fields: string[]) => ReactNode | (fields) => `This request asks for ${fields.join(', ')}. No server should need that — the field has not been rendered.` | — |
Functions
| Function | Signature | Description |
|---|---|---|
| credentialFields | (schema: JsonSchema) => string[] | Exported, so a client can refuse the request outright rather than rendering it. |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| credential refusal | automatic | A field named like a password, key, token, secret or seed phrase is stripped from the schema before the form is built, and the request is flagged. No legitimate elicitation needs one. |