MCP elicitation UI

mandatory

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).

Spec — MCP elicitation UI

MCP normative source: https://modelcontextprotocol.io/specification/draft/client/elicitation.

Princípios

  1. *wo modes*— form (inline JSON schema fields) vs URL (external page for sensitive creds).
  2. *erver cancellable*— server may cancel; client respects + cleanup.
  3. *imeout default*— 5min; configurable per-elicitation.
  4. *o 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:

  • *ccept* validate + submit values.
  • *eject* emit elicitation/reject with optional reason.
  • *ancel* emit elicitation/cancel; close dialog.

URL mode:

  • *ancel* 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-invalid on 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

  • *1*Form mount: schema with 2 fields → both fields rendered.
  • *2*Validation: missing required → submit disabled; aria-invalid set.
  • *3*Accept: valid form → elicitation/accept sent with values.
  • *4*Reject: button → elicitation/reject sent.
  • *5*Cancel: ESC → elicitation/cancel.
  • *6*URL mode: opens browser; polls status; updates on complete.
  • *7*Timeout: advance clock 5min → elicitation/timeout sent; dialog closes.
  • *8*Server cancel: server emits cancel → client closes; no submit.
  • *9*Multi-tenant: workspace switch → previous elicitation dialog dismissed.

Source: ../home/koder/dev/koder/meta/docs/stack/specs/ai-ui/mcp-elicitation.kmd