60e0ffc959
Upgrade checks / Notify on failure (push) Has been cancelled
Upgrade checks / Close issue on success (push) Has been cancelled
Schema Crash Test / Real-world schema crash test (232K schemas) (push) Has been cancelled
Run static analysis / static_analysis (push) Has been cancelled
Tests / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Tests / Tests with lowest-direct dependencies (push) Has been cancelled
Tests / MCP conformance tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
Tests / Package install smoke (push) Has been cancelled
Upgrade checks / Static analysis (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Upgrade checks / Integration tests (push) Has been cancelled
Update MCPServerConfig Schema / update-config-schema (push) Has been cancelled
Update SDK Documentation / update-sdk-docs (push) Has been cancelled
106 lines
3.5 KiB
Plaintext
106 lines
3.5 KiB
Plaintext
---
|
|
title: Form Input
|
|
sidebarTitle: Form Input
|
|
description: Collect structured data from users via Pydantic models
|
|
icon: rectangle-list
|
|
tag: NEW
|
|
---
|
|
|
|
import { VersionBadge } from '/snippets/version-badge.mdx'
|
|
|
|
<VersionBadge version="3.2.0" />
|
|
|
|
`FormInput` generates a validated form from a Pydantic model. The user fills it out, and the submission is validated against the model before being returned. Structured elicitation that can't be hallucinated.
|
|
|
|
<Frame>
|
|
<img src="/apps/images/app-form.png" alt="The FormInput provider shown in Goose, with a bug report form" />
|
|
</Frame>
|
|
|
|
```python
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
from fastmcp import FastMCP
|
|
from fastmcp.apps.form import FormInput
|
|
|
|
class BugReport(BaseModel):
|
|
title: str = Field(description="Brief summary")
|
|
severity: Literal["low", "medium", "high", "critical"]
|
|
description: str = Field(
|
|
description="Detailed description",
|
|
json_schema_extra={"ui": {"type": "textarea"}},
|
|
)
|
|
|
|
mcp = FastMCP("My Server")
|
|
mcp.add_provider(FormInput(model=BugReport))
|
|
```
|
|
|
|
This registers two tools:
|
|
|
|
| Tool | Visibility | Purpose |
|
|
|------|-----------|---------|
|
|
| `collect_bugreport` | Model | Opens the form UI |
|
|
| `submit_form` | App only | Validates and processes the submission |
|
|
|
|
The tool name is derived from the model class name, lowercased: `collect_{modelname}`. So `BugReport` becomes `collect_bugreport`, `ShippingAddress` becomes `collect_shippingaddress`. Use `tool_name` to override if needed. The LLM calls it with a prompt explaining what it needs, and the user gets a form with fields matching the model.
|
|
|
|
## Field mapping
|
|
|
|
`FormInput` uses Prefab's `Form.from_model()`, which maps Pydantic types to form components:
|
|
|
|
| Python type | Form component |
|
|
|------------|---------------|
|
|
| `str` | Text input |
|
|
| `int`, `float` | Number input |
|
|
| `bool` | Checkbox |
|
|
| `datetime.date` | Date picker |
|
|
| `Literal[...]` | Select dropdown |
|
|
| `SecretStr` | Password input |
|
|
|
|
Use `Field()` metadata to control labels (`title`), placeholders (`description`), and validation (`min_length`, `max_length`, `ge`, `le`). Use `json_schema_extra={"ui": {"type": "textarea"}}` for multiline text.
|
|
|
|
## Callback
|
|
|
|
By default, the validated model is returned as JSON. Provide an `on_submit` callback to process the data server-side:
|
|
|
|
```python
|
|
def save_report(report: BugReport) -> str:
|
|
db.insert(report.model_dump())
|
|
return f"Bug #{db.last_id} filed: {report.title}"
|
|
|
|
mcp.add_provider(FormInput(model=BugReport, on_submit=save_report))
|
|
```
|
|
|
|
The callback receives a validated model instance and returns a string that becomes the tool result.
|
|
|
|
## Configuration
|
|
|
|
```python
|
|
FormInput(
|
|
model=BugReport, # Required: the Pydantic model
|
|
name="BugTracker", # App name (default: model name)
|
|
title="File a Bug", # Card heading (default: model name)
|
|
tool_name="file_bug", # Tool name (default: collect_{model})
|
|
submit_text="Submit Report", # Button label (default: "Submit")
|
|
on_submit=save_report, # Optional callback
|
|
send_message=True, # Push result as a chat message
|
|
)
|
|
```
|
|
|
|
Set `send_message=True` to push the result back into the conversation via `SendMessage`, triggering the LLM's next turn. Without it, the result is just the tool return value.
|
|
|
|
## Multiple forms
|
|
|
|
Add multiple providers for different models — each gets its own tool:
|
|
|
|
```python
|
|
mcp = FastMCP(
|
|
"My Server",
|
|
providers=[
|
|
FormInput(model=ShippingAddress),
|
|
FormInput(model=BugReport),
|
|
FormInput(model=ContactInfo),
|
|
],
|
|
)
|
|
```
|