> ## Documentation Index
> Fetch the complete documentation index at: https://docs.leanmcp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# @leanmcp/elicitation

> Structured user input collection using MCP elicitation protocol

# @leanmcp/elicitation

Structured user input collection for LeanMCP tools using the MCP elicitation protocol. The `@Elicitation` decorator automatically intercepts tool calls to request missing required parameters from users.

## Features

<CardGroup cols={2}>
  <Card title="@Elicitation Decorator" icon="square-pen">
    Automatically collect missing user inputs before tool execution
  </Card>

  <Card title="Fluent Builder API" icon="hammer">
    Programmatic form creation with `ElicitationFormBuilder`
  </Card>

  <Card title="Multiple Strategies" icon="layer-group">
    Form and multi-step elicitation strategies
  </Card>

  <Card title="Built-in Validation" icon="check">
    min/max, pattern matching, custom validators
  </Card>
</CardGroup>

## Installation

```bash theme={null}
npm install @leanmcp/elicitation @leanmcp/core
```

## Quick Start

### Simple Form Elicitation

```typescript theme={null}
import { Tool } from "@leanmcp/core";
import { Elicitation } from "@leanmcp/elicitation";

class SlackService {
  @Tool({ description: "Create a new Slack channel" })
  @Elicitation({
    title: "Create Channel",
    description: "Please provide channel details",
    fields: [
      {
        name: "channelName",
        label: "Channel Name",
        type: "text",
        required: true,
        validation: {
          pattern: "^[a-z0-9-]+$",
          errorMessage: "Must be lowercase alphanumeric with hyphens"
        }
      },
      {
        name: "isPrivate",
        label: "Private Channel",
        type: "boolean",
        defaultValue: false
      }
    ]
  })
  async createChannel(args: { channelName: string; isPrivate: boolean }) {
    return { success: true, channelName: args.channelName };
  }
}
```

### How It Works

1. **Client calls tool** with missing required fields
2. **Decorator intercepts** and checks for missing fields
3. **Elicitation request returned** with form definition
4. **Client displays form** to collect user input
5. **Client calls tool again** with complete arguments
6. **Method executes** normally

***

## Fluent Builder API

For more complex forms, use `ElicitationFormBuilder`:

```typescript theme={null}
import { Tool } from "@leanmcp/core";
import { Elicitation, ElicitationFormBuilder, validation } from "@leanmcp/elicitation";

class UserService {
  @Tool({ description: "Create user account" })
  @Elicitation({
    builder: () => new ElicitationFormBuilder()
      .title("User Registration")
      .description("Create a new user account")
      .addEmailField("email", "Email Address", { required: true })
      .addTextField("username", "Username", {
        required: true,
        validation: validation()
          .minLength(3)
          .maxLength(20)
          .pattern("^[a-zA-Z0-9_]+$")
          .build()
      })
      .addSelectField("role", "Role", [
        { label: "Admin", value: "admin" },
        { label: "User", value: "user" }
      ])
      .build()
  })
  async createUser(args: any) {
    return { success: true, email: args.email };
  }
}
```

### Builder Methods

| Method                                             | Description                   |
| -------------------------------------------------- | ----------------------------- |
| `title(string)`                                    | Set form title                |
| `description(string)`                              | Set form description          |
| `condition(fn)`                                    | Set condition for elicitation |
| `addTextField(name, label, opts?)`                 | Add text input                |
| `addTextAreaField(name, label, opts?)`             | Add textarea                  |
| `addNumberField(name, label, opts?)`               | Add number input              |
| `addBooleanField(name, label, opts?)`              | Add checkbox                  |
| `addSelectField(name, label, options, opts?)`      | Add dropdown                  |
| `addMultiSelectField(name, label, options, opts?)` | Add multi-select              |
| `addEmailField(name, label, opts?)`                | Add email input               |
| `addUrlField(name, label, opts?)`                  | Add URL input                 |
| `addDateField(name, label, opts?)`                 | Add date picker               |
| `addCustomField(field)`                            | Add custom field              |
| `build()`                                          | Build final config            |

***

## Conditional Elicitation

Only ask for inputs when needed:

```typescript theme={null}
@Tool({ description: "Send message to Slack" })
@Elicitation({
  condition: (args) => !args.channelId,
  title: "Select Channel",
  fields: [
    {
      name: "channelId",
      label: "Channel",
      type: "select",
      required: true,
      options: [
        { label: "#general", value: "C12345" },
        { label: "#random", value: "C67890" }
      ]
    }
  ]
})
async sendMessage(args: { channelId?: string; message: string }) {
  // Only elicits if channelId is missing
}
```

***

## Multi-Step Elicitation

Break input collection into sequential steps:

```typescript theme={null}
@Tool({ description: "Deploy application" })
@Elicitation({
  strategy: "multi-step",
  builder: () => [
    {
      title: "Step 1: Environment",
      fields: [
        {
          name: "environment",
          label: "Environment",
          type: "select",
          required: true,
          options: [
            { label: "Production", value: "prod" },
            { label: "Staging", value: "staging" }
          ]
        }
      ]
    },
    {
      title: "Step 2: Configuration",
      fields: [
        {
          name: "replicas",
          label: "Replicas",
          type: "number",
          defaultValue: 3
        }
      ],
      condition: (prev) => prev.environment === "prod"
    }
  ]
})
async deployApp(args: any) {
  // Implementation
}
```

***

## Field Types

| Type          | Description              |
| ------------- | ------------------------ |
| `text`        | Single-line text input   |
| `textarea`    | Multi-line text area     |
| `number`      | Numeric input            |
| `boolean`     | Checkbox                 |
| `select`      | Dropdown (single choice) |
| `multiselect` | Multi-select             |
| `email`       | Email input              |
| `url`         | URL input                |
| `date`        | Date picker              |

***

## Validation

### Built-in Validation

```typescript theme={null}
{
  name: "username",
  label: "Username",
  type: "text",
  validation: {
    minLength: 3,
    maxLength: 20,
    pattern: "^[a-zA-Z0-9_]+$",
    errorMessage: "Username must be 3-20 alphanumeric characters"
  }
}
```

### Using ValidationBuilder

```typescript theme={null}
import { validation } from "@leanmcp/elicitation";

validation()
  .minLength(8)
  .maxLength(100)
  .pattern("^[a-zA-Z0-9]+$")
  .customValidator((value) => value !== "admin")
  .errorMessage("Invalid input")
  .build()
```

***

## Elicitation Flow

### Request/Response Cycle

**First Call (Missing Fields):**

```json theme={null}
// Request
{
  "method": "tools/call",
  "params": {
    "name": "createChannel",
    "arguments": {}
  }
}

// Response (Elicitation Request)
{
  "type": "elicitation",
  "title": "Create Channel",
  "fields": [
    {
      "name": "channelName",
      "label": "Channel Name",
      "type": "text",
      "required": true
    }
  ]
}
```

**Second Call (Complete Fields):**

```json theme={null}
// Request
{
  "method": "tools/call",
  "params": {
    "name": "createChannel",
    "arguments": {
      "channelName": "my-channel",
      "isPrivate": false
    }
  }
}

// Response (Tool Result)
{
  "content": [{"type": "text", "text": "{\"success\": true}"}]
}
```

***

## API Reference

### ElicitationConfig

```typescript theme={null}
interface ElicitationConfig {
  strategy?: 'form' | 'multi-step';
  title?: string;
  description?: string;
  fields?: ElicitationField[];
  condition?: (args: any) => boolean;
  builder?: (context: ElicitationContext) => ElicitationRequest | ElicitationStep[];
}
```

### ElicitationField

```typescript theme={null}
interface ElicitationField {
  name: string;
  label: string;
  type: 'text' | 'number' | 'boolean' | 'select' | 'multiselect' | 'date' | 'email' | 'url' | 'textarea';
  description?: string;
  required?: boolean;
  defaultValue?: any;
  options?: Array<{ label: string; value: any }>;
  validation?: FieldValidation;
  placeholder?: string;
  helpText?: string;
}
```

### FieldValidation

```typescript theme={null}
interface FieldValidation {
  min?: number;
  max?: number;
  minLength?: number;
  maxLength?: number;
  pattern?: string;
  customValidator?: (value: any) => boolean | string;
  errorMessage?: string;
}
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Use Conditional Elicitation">
    Only ask when truly needed using the `condition` option:

    ```typescript theme={null}
    @Elicitation({
      condition: (args) => !args.channelId,
      // ...
    })
    ```
  </Accordion>

  <Accordion title="Provide Sensible Defaults">
    Reduce user input burden with `defaultValue`:

    ```typescript theme={null}
    {
      name: "priority",
      type: "select",
      defaultValue: "normal",
      options: [...]
    }
    ```
  </Accordion>

  <Accordion title="Use Builder for Complex Forms">
    The fluent API is more maintainable:

    ```typescript theme={null}
    builder: () => new ElicitationFormBuilder()
      .addTextField("name", "Name", { required: true })
      .addSelectField("role", "Role", [...])
      .build()
    ```
  </Accordion>

  <Accordion title="Add Helpful Descriptions">
    Use `helpText` and `placeholder` to guide users:

    ```typescript theme={null}
    {
      name: "email",
      type: "email",
      placeholder: "user@example.com",
      helpText: "We'll send confirmation here"
    }
    ```
  </Accordion>
</AccordionGroup>

## Related Packages

* [@leanmcp/core](/sdk/core) - Core decorators and server functionality
* [@leanmcp/auth](/sdk/auth) - Authentication decorators and providers
* [@leanmcp/cli](/sdk/cli) - CLI tool for creating new projects

## Links

* [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
* [MCP Specification](https://modelcontextprotocol.io/specification/2025-11-25)
* [NPM Package](https://www.npmjs.com/package/@leanmcp/elicitation)
