MCP elicitation UI
ai-ui specs/ai-ui/mcp-elicitation.kmd
UI for MCP server-initiated user input requests mid-tool-execution. Form mode (schema-driven) for inline fields; URL mode for external credentials. Completes MCP client capability surface alongside tool-invocation (#100), permission-prompt (#101), server-state (#104), and sampling-approval (#103).
When this spec applies
Primary triggers
- Display elicitation request from MCP server
All triggers
- Build MCP-aware client that supports server elicitation
- Implement Kortex/Bot/Kode MCP consumer fully
Specification body
Spec — MCP elicitation UI
MCP normative source: https://modelcontextprotocol.io/specification/draft/client/elicitation.
Princípios
- Two modes — form (inline JSON schema fields) vs URL (external page for sensitive creds).
- Server cancellable — server may cancel; client respects + cleanup.
- Timeout default — 5min; configurable per-elicitation.
- No tenant leak — input values scoped per workspace.
R1 — Form mode
Server sends elicitation request with JSON Schema:
{
"type": "elicitation/request",
"id": "e_123",
"schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "Your city"},
"temperature_unit": {"type": "string", "enum": ["C", "F"]}
},
"required": ["city"]
},
"title": "Weather lookup needs your input",
"description": "..."
}
Client renders inline dialog with form fields:
| JSON Schema type | Field |
|---|---|
string | text input (or textarea if format: textarea) |
number / integer | spinner / number input |
boolean | switch |
enum | segmented control or dropdown |
array of string | tag input |
object | nested fieldset |
Required fields: asterisk; client-side validation before submit.
R2 — URL mode
Server requests external URL elicitation (credentials, OAuth, payment):
{
"type": "elicitation/request",
"id": "e_124",
"mode": "url",
"url": "https://server.example/elicit/abc",
"title": "Sign in to GitHub"
}
Client opens external browser (desktop) / in-app WebView (mobile) OR
delegates to koder_web_kit browse component for Web Surfaces.
Polling: client polls server elicitation/status/<id> until completion
or timeout.
R3 — Actions
Form mode:
- Accept: validate + submit values.
- Reject: emit
elicitation/rejectwith optional reason. - Cancel: emit
elicitation/cancel; close dialog.
URL mode:
- Cancel: same as form cancel; abort browser session.
R4 — Timeout
Default 5min. Server may set custom timeout. Visual countdown last 30s.
On timeout: emit elicitation/timeout to server; close dialog.
R5 — Multi-tenant
Input values scoped per (koder_user_id, workspace_id, conversation_id, elicitation_id).
Cross-tenant lookup 404.
R6 — Surface bindings
| Surface | API |
|---|---|
| Flutter | KoderMCPElicitationDialog({required schema, onAccept, onReject}) em koder_kit/lib/src/ai/mcp_elicitation.dart |
| Web | <koder-mcp-elicitation> |
| Compose/SwiftUI | futuro |
| CLI / TUI | Plain prompts inline; URL mode opens system browser |
R7 — Acessibilidade
- Dialog:
role="dialog" aria-modal="true". - Form fields: standard
<label for="...">+aria-required+aria-invalidon error. - Focus trap; ESC cancela; Tab cycle.
- URL mode: announce "Opening external page" to screen reader.
R8 — i18n
| Key | en-US | pt-BR |
|---|---|---|
mcp.elicitation.action.accept | "Submit" | "Enviar" |
mcp.elicitation.action.reject | "Reject" | "Recusar" |
mcp.elicitation.action.cancel | "Cancel" | "Cancelar" |
mcp.elicitation.timeout_warning | "Closing in {seconds}s" | "Fechando em {seconds}s" |
mcp.elicitation.url_mode.opening | "Opening external page" | "Abrindo página externa" |
mcp.elicitation.field_required | "Required" | "Obrigatório" |
T-suite
- T1 Form mount: schema with 2 fields → both fields rendered.
- T2 Validation: missing required → submit disabled; aria-invalid set.
- T3 Accept: valid form →
elicitation/acceptsent with values. - T4 Reject: button →
elicitation/rejectsent. - T5 Cancel: ESC →
elicitation/cancel. - T6 URL mode: opens browser; polls status; updates on complete.
- T7 Timeout: advance clock 5min →
elicitation/timeoutsent; dialog closes. - T8 Server cancel: server emits cancel → client closes; no submit.
- T9 Multi-tenant: workspace switch → previous elicitation dialog dismissed.
Cross-link
- Companion:
mcp-tool-invocation.kmd,mcp-permission-prompt.kmd,mcp-sampling-approval.kmd - Backend:
services/ai/mcp/ - Refs: https://modelcontextprotocol.io/specification/draft/client/elicitation, GitHub blog elicitation
References
meta/docs/stack/specs/ai-ui/mcp-tool-invocation.kmdmeta/docs/stack/specs/ai-ui/mcp-permission-prompt.kmdmeta/docs/stack/policies/multi-tenant-by-default.kmd