Skip to main content
Elicitation allows tools and agents to request interactive user input during execution. This enables approval workflows, multi-step confirmations, OAuth flows, and any scenario where a tool needs user input before continuing.
This feature implements the MCP Elicitation specification. FrontMCP handles all protocol details automatically.

Why Elicitation?

In the Model Context Protocol, elicitation fills a critical gap: Elicitation is ideal for:
  • Approval workflows — confirm destructive operations before execution
  • Multi-step forms — collect additional information during tool execution
  • OAuth flows — redirect users to external authentication (URL mode)
  • Human-in-the-loop — require explicit user consent for sensitive actions
  • Disambiguation — ask users to clarify ambiguous requests

Basic Usage

Class Style (ToolContext)

Use this.elicit() within any tool that extends ToolContext:

Class Style (AgentContext)

Agents are LLM-powered autonomous units that can also use elicitation. Override execute() to add custom logic like approval workflows:
Most agents don’t need to override execute(). The default implementation runs the LLM loop automatically. Override only when you need custom pre/post processing like approval workflows.

Elicitation Modes

FrontMCP supports two elicitation modes per the MCP specification:

Form Mode (Default)

Displays a form to collect structured input directly in the client:

URL Mode

Redirects the user to an external URL for out-of-band interaction (OAuth, payments, etc.). URL mode requires an elicitationId — an opaque identifier you generate to correlate the out-of-band callback with the pending elicitation:
Security: Never put a raw session ID into the elicitation URL. Generate an opaque elicitationId (e.g. via randomUUID()) and store the mapping to the session server-side, or use a signed/encrypted payload that you can validate on callback.

Elicitation Result

The elicit() method returns an ElicitResult with the following structure:

Status Values

Handling Responses


Schema Validation

When the client returns an elicitation result with action: 'accept', FrontMCP automatically validates the content against the original schema you provided. This ensures type safety and data integrity.

How It Works

  1. When you call this.elicit(message, schema), FrontMCP stores the schema alongside the pending elicitation record
  2. When the user responds, FrontMCP validates the content against the stored schema
  3. Invalid content is rejected with an InvalidInputError (same as tool input validation)

Validation Behavior

Error Handling

Invalid elicitation content throws the same InvalidInputError used for tool input validation. This allows LLMs (especially in fallback mode) to recognize the error format and retry with corrected data:
The error includes:
  • path: The JSON path to the invalid field (e.g., ["user", "age"])
  • message: Human-readable validation error message

Example: Schema Mismatch

Schema validation uses the same InvalidInputError as tool input validation (HTTP 400, code INVALID_INPUT). This consistency helps LLMs understand and recover from validation errors.

Timeout Handling

Elicitation requests have a configurable timeout. When the timeout expires, an ElicitationTimeoutError is thrown to kill the tool execution and release resources.

Default Timeout

The default timeout is 5 minutes (300,000ms):

Custom Timeout

Specify a custom timeout with the ttl option:

Handling Timeouts

Timeouts throw an exception to ensure the tool execution is terminated:
Timeouts are designed to throw exceptions to kill tool execution. Do not catch and suppress timeout errors—this defeats the purpose of resource cleanup.

Single Elicit Per Session

Only one elicitation can be pending per session at a time. If a new elicitation is requested while one is pending, the previous one is automatically cancelled with status: 'cancel'.
This design ensures predictable behavior and prevents conflicting elicitation UI states.

Elicitation Hooks

FrontMCP provides flow hooks to intercept elicitation requests and results. Hooks are methods inside plugin classes that run before, after, or around specific flow stages.

Hook Types

ElicitationRequestHook

Intercepts the elicitation request flow before sending to the client. Stages:

ElicitationResultHook

Intercepts the elicitation result flow when the user responds. Stages:

Example: Plugin with Elicitation Hooks

Registering the Plugin

Use Cases

Input Sanitization (BEFORE buildResult):
Analytics (AFTER finalize):
Conditional Hooks (with filter):

Client Capability Detection

Not all MCP clients support elicitation. FrontMCP automatically checks client capabilities before sending elicitation requests.

Automatic Validation

When you call this.elicit(), FrontMCP:
  1. Checks if the client declared elicitation capability during initialization
  2. Verifies the client supports the requested mode (form or url)
  3. Throws ElicitationNotSupportedError if elicitation is not supported

Manual Capability Check

You can check elicitation support before calling elicit():

Capability Helper

The supportsElicitation helper function:

Universal LLM Support

FrontMCP elicitation works with all LLMs, not just those that support the MCP elicitation protocol. For clients that don’t support elicitation (like OpenAI, Google Gemini, Cursor, etc.), FrontMCP automatically falls back to an LLM-mediated approach.
Zero code changes required! Your tools use the same this.elicit() API regardless of client capabilities. FrontMCP handles detection and routing automatically.

How It Works

Standard Elicitation (Claude, supporting clients): Fallback Elicitation (OpenAI, Gemini, etc.):

Client Compatibility

Fallback Response Format

When a tool calls elicit() and the client doesn’t support elicitation, FrontMCP returns a structured response:
The LLM reads these instructions, asks the user, then calls the sendElicitationResult tool:

The sendElicitationResult Tool

This system tool is automatically registered for clients that don’t support elicitation. It:
  • Is hidden from clients that support standard elicitation
  • Accepts the elicitId, user action, and content
  • Re-invokes the original tool with the result pre-injected
  • Returns the original tool’s final result
Input Schema:

Key Benefits

  1. Transparent to developers — Same this.elicit() API for all clients
  2. Automatic detection — Framework checks client capabilities at runtime
  3. Works with Redis — Fallback state is stored in Redis for distributed deployments
  4. Type-safe — Schema is converted to JSON Schema for LLM understanding

Error Handling

ElicitationNotSupportedError

Thrown when:
  • Client doesn’t support elicitation
  • Client doesn’t support the requested mode (form/url)
  • No session is available
  • Transport is not available

ElicitationTimeoutError

Thrown when the user doesn’t respond within the TTL:

Configuration Options

The elicit() method accepts an options object:

Distributed Deployments

By default, elicitation state is stored in-memory on the server that initiated the elicit request. This works for single-node deployments but fails in distributed environments where different nodes may handle the initial request and the user’s response.

The Problem

In a distributed deployment: When Redis is configured, FrontMCP automatically uses Redis for elicitation state storage and pub/sub for cross-node result routing:
With Redis configured, elicitation works seamlessly across nodes:

Single-Node Mode (Development)

Without Redis, FrontMCP uses in-memory storage with a warning:
This is appropriate for:
  • Local development
  • Single-node deployments
  • Testing environments

Sticky Sessions (Alternative)

If you cannot use Redis, configure your load balancer for session affinity to ensure requests from the same client always reach the same server: Nginx:
AWS ALB:
  • Enable “Stickiness” in target group settings
  • Use application-based cookie (recommended) or duration-based stickiness
  • Set appropriate stickiness duration (longer than your elicitation TTL)
Kubernetes (Ingress):
Sticky sessions are less reliable than Redis because they depend on load balancer behavior and can fail during node restarts or scaling events. Use Redis for production deployments.

Vercel Edge Functions

Edge functions are stateless and require Redis for elicitation. An error is thrown if elicitation is attempted without Redis on Edge:
Configure Redis when deploying to Vercel Edge:
Upstash provides serverless Redis that works well with Vercel Edge functions.

Deployment Mode Summary


Encrypted Elicitation

When collecting sensitive user data (passwords, PII, payment information), FrontMCP can encrypt all elicitation data at rest using session-derived keys.

Why Encrypt?

Elicitation often collects sensitive data:
  • Account credentials and API keys
  • Personal information (SSN, address, phone)
  • Financial data (card numbers, bank accounts)
  • Health information (HIPAA-protected data)
Without encryption, this data is stored in plaintext in Redis or memory, accessible to anyone with database access.

Security Model

Encrypted elicitation provides zero-knowledge storage:
  1. Session-Derived Keys: Each session gets a unique encryption key derived from HKDF-SHA256(serverSecret + sessionId)
  2. AES-256-GCM: Authenticated encryption prevents tampering
  3. Cross-Session Isolation: Session B cannot decrypt Session A’s data, even with database access
  4. Fail-Safe Decryption: Decryption fails silently for tampered or corrupted data

Configuration

Set one of these environment variables to enable encryption:
Encryption is automatic when a secret is available. No code changes required.

How It Works

Cross-Session Isolation

Even if an attacker gains database access, they cannot decrypt elicitation data without:
  1. The server secret (MCP_ELICITATION_SECRET)
  2. The specific sessionId used to encrypt the data

Best Practices

Do:
  • Use a strong random secret (32+ characters)
  • Rotate secrets periodically (with care for in-flight elicitations)
  • Set secrets via environment variables, not code
  • Use MCP_ELICITATION_SECRET for dedicated elicitation security
Don’t:
  • Store secrets in version control
  • Use weak or predictable secrets
  • Share secrets across environments (dev/staging/prod)
  • Log or expose encrypted data for debugging

Real-World Examples

Approval Workflow

Multi-Step Confirmation

OAuth Authorization (URL Mode)

The elicitationId is an opaque correlation handle. Map it to the session in your own server-side store so the OAuth callback can resolve the session without exposing raw session IDs in URLs.

Graceful Fallback


MCP Protocol Integration

Elicitation integrates with the MCP protocol via:

Client Capabilities

Clients advertise elicitation support during MCP initialization:
FrontMCP automatically reads these capabilities and validates them before sending elicitation requests.

Protocol Flow

  1. Tool calls this.elicit(message, schema, options)
  2. FrontMCP validates client capabilities
  3. FrontMCP sends elicitation/create request to client
  4. Client displays form/redirects user based on mode
  5. User interacts with the elicitation UI
  6. Client sends result back with action (‘accept’, ‘cancel’, ‘decline’) and optional content
  7. FrontMCP resolves the promise with typed ElicitResult
For the full protocol specification, see MCP Elicitation.

Best Practices

Do:
  • Use descriptive messages that clearly explain what information is needed
  • Define clear Zod schemas with .describe() on each field
  • Set appropriate timeouts based on the complexity of the request
  • Handle all three status values (accept, cancel, decline)
  • Provide graceful fallbacks for clients without elicitation support
  • Use form mode for simple confirmations and structured data collection
  • Use URL mode only for external authentication flows
Don’t:
  • Suppress timeout errors—let them propagate to terminate execution
  • Request elicitation for every tool—only when user input is truly needed
  • Set extremely long timeouts that could leave resources hanging
  • Assume all clients support elicitation—always check or handle errors
  • Chain multiple dependent elicitations without clear user guidance
  • Use elicitation for data that should be provided upfront in tool input

API Reference

Types

Errors

Helpers