https://github.com/asouqi/webmcp-forms
AI-powered form tools for WebMCP. Enables AI assistants to fill, validate, clear, and submit web forms through the Model Context Protocol
https://github.com/asouqi/webmcp-forms
ai assistant browser form-filling form-validation formik forms mcp model-context-protocol tools validation webmcp
Last synced: about 2 months ago
JSON representation
AI-powered form tools for WebMCP. Enables AI assistants to fill, validate, clear, and submit web forms through the Model Context Protocol
- Host: GitHub
- URL: https://github.com/asouqi/webmcp-forms
- Owner: asouqi
- License: mit
- Created: 2026-04-16T17:54:45.000Z (3 months ago)
- Default Branch: master
- Last Pushed: 2026-06-04T21:30:41.000Z (about 2 months ago)
- Last Synced: 2026-06-04T21:34:00.013Z (about 2 months ago)
- Topics: ai, assistant, browser, form-filling, form-validation, formik, forms, mcp, model-context-protocol, tools, validation, webmcp
- Language: TypeScript
- Homepage:
- Size: 326 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# webmcp-forms
AI-powered form tools for WebMCP. Enables AI assistants to fill, validate, clear, and submit web forms through the Model Context Protocol.
## 🧠 What is webmcp-forms?
`webmcp-forms` builds on top of [`webmcp-adapter`](https://github.com/asouqi/webmcp-adapter) to expose your web forms as a set of typed, validated AI tools. Once registered, an AI assistant can fill fields, validate the form, and submit it — all through natural language.
## 🚀 Installation
```bash
npm install webmcp-forms webmcp-adapter
```
For React applications:
```bash
npm install webmcp-forms webmcp-adapter webmcp-adapter-react
```
---
## ⚡ Quick Start
```tsx
import { useState } from 'react'
import { useTools } from 'webmcp-adapter-react'
import { createFormTools } from 'webmcp-forms'
const fields = {
name: { type: 'string', label: 'Full Name', required: true, minLength: 2 },
email: { type: 'string', label: 'Email', required: true, pattern: '^[^@]+@[^@]+\\.[^@]+$' },
}
function ContactForm() {
const [values, setValues] = useState({ name: '', email: '' })
useTools({
tools: createFormTools({
formId: 'contact',
fields,
getValues: () => values,
onChange: (field, value) => setValues(prev => ({ ...prev, [field]: value })),
onSubmit: () => console.log('Submitted:', values),
}),
deps: [values]
})
return (
setValues(p => ({ ...p, name: e.target.value }))} placeholder="Full Name" />
setValues(p => ({ ...p, email: e.target.value }))} placeholder="Email" />
Submit
)
}
```
---
## 🛠 API Reference
### `createFormTools(options)`
Creates an array of `ToolDefinition[]` for AI interaction. Pass the result directly to `registerBatch` or `useTools`.
```typescript
function createFormTools(options: CreateFormToolsOptions): ToolDefinition[]
```
#### Options
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `formId` | `string` | Yes | Unique identifier for the form. Used as a prefix for all generated tool names (e.g. `fill_contact_field`) |
| `fields` | `Record` | Yes | Field definitions describing each form field and its constraints |
| `getValues` | `() => Record` | Yes | Function that returns the current form values |
| `onChange` | `(field: string, value: JsonValue) => void` | Yes | Callback invoked when the AI sets a field value |
| `onSubmit` | `() => void \| Promise` | No | Called when the AI invokes the submit tool |
| `onReset` | `() => void` | No | Called when the AI invokes the reset tool |
| `validationSchema` | `{ form?: StandardSchema, fillField?: StandardSchema, fillMultipleField?: StandardSchema }` | No | Per-tool Standard Schema validators (Zod, Valibot, ArkType). Each key targets a specific tool — `form` for `validate-form`, `fillField` for `fill-field`, `fillMultipleField` for `fill-multiple-field`. When a key is provided it replaces the built-in JSON Schema validation for that tool |
| `selectedTools` | `Set` | No | Specific tools to include. Defaults to all tools |
| `customTools` | `ToolDefinition[]` | No | Additional custom tools to register alongside the built-in form tools |
---
### `FormField`
Describes a single form field and its validation constraints.
| Property | Type | Description |
|----------|------|-------------|
| `type` | `'string' \| 'number' \| 'boolean' \| 'array' \| 'object'` | Field type — **required** |
| `label` | `string` | Human-readable label used in validation error messages |
| `required` | `boolean` | Whether the field must have a non-empty value |
| `options` | `string[]` | Restricts the value to an enum list |
| `min` / `max` | `number` | Min/max range for `number` fields |
| `minLength` / `maxLength` | `number` | Length constraints for `string` fields |
| `minItems` / `maxItems` | `number` | Length constraints for `array` fields |
| `step` | `number` | Step constraint for `number` fields (`multipleOf` in JSON Schema) |
| `pattern` | `string` | Regex pattern for `string` field validation |
| `placeholder` | `string` | UI hint — not used in validation |
| `defaultValue` | `JsonValue` | Value used when the field is reset |
```typescript
const fields = {
// String with length and required constraints
name: {
type: 'string',
label: 'Full Name',
required: true,
minLength: 2,
maxLength: 50
},
// String with regex pattern
email: {
type: 'string',
label: 'Email',
required: true,
pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
},
// Number with range
age: {
type: 'number',
label: 'Age',
required: true,
min: 18,
max: 120
},
// Boolean
subscribe: {
type: 'boolean',
label: 'Subscribe to newsletter'
},
// String with enum options
country: {
type: 'string',
label: 'Country',
required: true,
options: ['US', 'UK', 'CA', 'DE', 'FR']
},
// Array with item count constraints
interests: {
type: 'array',
label: 'Interests',
minItems: 1,
maxItems: 5
},
// Nested object with default value
address: {
type: 'object',
label: 'Address',
defaultValue: { street: '', city: '', zip: '' }
}
}
```
---
### `FormTools`
Available tool identifiers for `selectedTools`:
| Tool ID | Generated Tool Name | Description |
|---------|---------------------|-------------|
| `fill-field` | `fill_{formId}_field` | Fill a single form field with a value |
| `fill-multiple-field` | `fill_{formId}_multiple_fields` | Fill multiple fields at once |
| `clear-field` | `clear_{formId}_field` | Clear a field to its default empty value |
| `get-form-state` | `get_{formId}_state` | Get all current form values |
| `get-field-value` | `get_{formId}_field_value` | Get a specific field's current value |
| `validate-form` | `validate_{formId}_form` | Validate all fields without submitting |
| `submit-form` | `submit_{formId}_form` | Submit the form |
| `reset-form` | `reset_{formId}_form` | Reset all fields to their default values |
---
## 📖 Usage
### With React
```tsx
import { useState } from 'react'
import { useTools } from 'webmcp-adapter-react'
import { createFormTools } from 'webmcp-forms'
const fields = {
name: { type: 'string', label: 'Full Name', required: true, minLength: 2 },
email: { type: 'string', label: 'Email', required: true, pattern: '^[^@]+@[^@]+\\.[^@]+$' },
age: { type: 'number', label: 'Age', min: 18, max: 120 },
subscribe: { type: 'boolean', label: 'Subscribe to newsletter' }
}
function ContactForm() {
const [values, setValues] = useState({
name: '',
email: '',
age: null,
subscribe: false
})
useTools({
tools: createFormTools({
formId: 'contact',
fields,
getValues: () => values,
onChange: (field, value) => {
setValues(prev => ({ ...prev, [field]: value }))
},
onSubmit: () => {
console.log('Submitted:', values)
},
onReset: () => {
setValues({ name: '', email: '', age: null, subscribe: false })
}
}),
deps: [values]
})
return (
e.preventDefault()}>
setValues(prev => ({ ...prev, name: e.target.value }))}
placeholder="Full Name"
/>
setValues(prev => ({ ...prev, email: e.target.value }))}
placeholder="Email"
/>
setValues(prev => ({
...prev,
age: e.target.value ? Number(e.target.value) : null
}))}
placeholder="Age"
/>
setValues(prev => ({ ...prev, subscribe: e.target.checked }))}
/>
Subscribe to newsletter
Submit
)
}
```
---
### With a Custom Validation Schema (Zod, Valibot, ArkType)
Pass any [Standard Schema](https://github.com/standard-schema/standard-schema)-compatible schema via `validationSchema` for stricter validation with cross-field rules, custom refinements, or richer error messages. When provided, it replaces the built-in per-field JSON Schema validation.
```tsx
import { z } from 'zod'
import { createFormTools } from 'webmcp-forms'
import { useTools } from 'webmcp-adapter-react'
const fieldsDefinitions = {
name: z.string().min(2, 'Full Name must be at least 2 characters'),
email: z.string().email('Must be a valid email address'),
age: z.number().min(18, 'Must be at least 18').max(120),
subscribe: z.boolean().optional(),
}
// Used by validate-form — validates the flat values object
const formSchema = z.object(fieldsDefinitions)
// Used by fill-field — validates { field: 'name', value: '...' }
const fieldSpecificSchemas = Object.entries(fieldsDefinitions).map(([key, schema]) =>
z.object({ field: z.literal(key), value: schema })
) as [ReturnType, ...ReturnType[]]
const fillFieldSchema = z.union(fieldSpecificSchemas)
// Used by fill-multiple-field — validates { fields: { name?, email?, ... } }
const fillMultipleFieldSchema = z.object({ fields: formSchema.partial() })
useTools({
tools: createFormTools({
formId: 'contact',
fields,
getValues: () => values,
onChange: (field, value) => setValues(prev => ({ ...prev, [field]: value })),
validationSchema: {
form: formSchema, // ← validate-form
fillField: fillFieldSchema, // ← fill-field
fillMultipleField: fillMultipleFieldSchema // ← fill-multiple-field
}
}),
deps: [values]
})
```
---
### Selecting Specific Tools
By default, all tools are created. Use `selectedTools` to include only the tools you need:
```tsx
import { createFormTools } from 'webmcp-forms'
import type { FormTools } from 'webmcp-forms'
useTools({
tools: createFormTools({
formId: 'contact',
fields,
getValues: () => values,
onChange: (field, value) => setValues(prev => ({ ...prev, [field]: value })),
selectedTools: new Set(['fill-field', 'validate-form', 'submit-form'])
}),
deps: [values]
})
```
---
### Adding Custom Tools
Add your own tools alongside the built-in form tools:
```tsx
import { defineTool } from 'webmcp-adapter'
import { createFormTools } from 'webmcp-forms'
const autofillTool = defineTool({
name: 'autofill_contact',
description: 'Auto-fill the contact form with sample data',
inputSchema: { type: 'object', properties: {}, required: [] },
execute: () => {
setValues({
name: 'John Doe',
email: 'john@example.com',
age: 30,
subscribe: true
})
return {
content: [{ type: 'text', text: 'Form auto-filled with sample data!' }],
structuredContent: { success: true }
}
}
})
useTools({
tools: createFormTools({
formId: 'contact',
fields,
getValues: () => values,
onChange: (field, value) => setValues(prev => ({ ...prev, [field]: value })),
customTools: [autofillTool]
}),
deps: [values]
})
```
---
### Vanilla JavaScript
```javascript
import { createFormTools } from 'webmcp-forms'
import { registerBatch } from 'webmcp-adapter'
let formValues = { name: '', email: '' }
const tools = createFormTools({
formId: 'contact',
fields: {
name: { type: 'string', label: 'Full Name', required: true },
email: { type: 'string', label: 'Email', required: true }
},
getValues: () => formValues,
onChange: (field, value) => {
formValues[field] = value
document.querySelector(`[name="${field}"]`).value = value
},
onSubmit: () => {
console.log('Submitted:', formValues)
}
})
const unregister = registerBatch(tools)
// Later, to clean up:
// unregister()
```
---
## 📦 Exported Types
```typescript
// Core function
export { createFormTools } from './createFormTools'
// Types
export type { CreateFormToolsOptions } from './createFormTools'
export type { FormConfig, FormState, FormField, FormTools, FieldType } from './types'
// Individual tool creators (for advanced usage)
export {
createFillFieldTool,
createFillMultipleFieldsTool,
createGetFormStateTool,
createGetFieldValueTool,
createSubmitFormTool,
createResetFormTool,
createClearFieldTool,
createValidateFormTool,
} from './tools'
```
### `CreateFormToolsOptions`
```typescript
interface CreateFormToolsOptions {
formId: string
fields: Record
getValues: () => Record
onChange: (field: string, value: JsonValue) => void
onSubmit?: () => void | Promise
onReset?: () => void
validationSchema?: {
form?: StandardSchema // validate-form tool
fillField?: StandardSchema // fill-field tool
fillMultipleField?: StandardSchema // fill-multiple-field tool
}
selectedTools?: Set
customTools?: ToolDefinition[]
}
```
### `FormField`
```typescript
interface FormField {
type: 'string' | 'number' | 'boolean' | 'array' | 'object'
label?: string
required?: boolean
options?: string[]
min?: number
max?: number
step?: number
minLength?: number
maxLength?: number
minItems?: number
maxItems?: number
pattern?: string
placeholder?: string
defaultValue?: JsonValue
}
```
### `FormTools`
```typescript
type FormTools =
| 'fill-field'
| 'fill-multiple-field'
| 'get-form-state'
| 'get-field-value'
| 'submit-form'
| 'reset-form'
| 'clear-field'
| 'validate-form'
```
---
## 🔗 Related Packages
- [`webmcp-adapter`](https://github.com/asouqi/webmcp-adapter) — Core adapter for defining and registering tools
- [`webmcp-adapter-react`](https://github.com/asouqi/webmcp-adapter-react) — React hooks for tool registration
## License
MIT