{"id":50658613,"url":"https://github.com/asouqi/webmcp-forms","last_synced_at":"2026-06-08T01:05:40.640Z","repository":{"id":355451232,"uuid":"1212764121","full_name":"asouqi/webmcp-forms","owner":"asouqi","description":"AI-powered form tools for WebMCP. Enables AI assistants to fill, validate, clear, and submit web forms through the Model Context Protocol","archived":false,"fork":false,"pushed_at":"2026-06-04T21:30:41.000Z","size":334,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-04T21:34:00.013Z","etag":null,"topics":["ai","assistant","browser","form-filling","form-validation","formik","forms","mcp","model-context-protocol","tools","validation","webmcp"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/asouqi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-16T17:54:45.000Z","updated_at":"2026-06-04T21:30:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/asouqi/webmcp-forms","commit_stats":null,"previous_names":["asouqi/webmcp-forms"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/asouqi/webmcp-forms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asouqi%2Fwebmcp-forms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asouqi%2Fwebmcp-forms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asouqi%2Fwebmcp-forms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asouqi%2Fwebmcp-forms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asouqi","download_url":"https://codeload.github.com/asouqi/webmcp-forms/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asouqi%2Fwebmcp-forms/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34043826,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-07T02:00:07.652Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","assistant","browser","form-filling","form-validation","formik","forms","mcp","model-context-protocol","tools","validation","webmcp"],"created_at":"2026-06-08T01:05:40.524Z","updated_at":"2026-06-08T01:05:40.634Z","avatar_url":"https://github.com/asouqi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# webmcp-forms\n\nAI-powered form tools for WebMCP. Enables AI assistants to fill, validate, clear, and submit web forms through the Model Context Protocol.\n\n## 🧠 What is webmcp-forms?\n\n`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.\n\n## 🚀 Installation\n\n```bash\nnpm install webmcp-forms webmcp-adapter\n```\n\nFor React applications:\n\n```bash\nnpm install webmcp-forms webmcp-adapter webmcp-adapter-react\n```\n\n---\n\n## ⚡ Quick Start\n\n```tsx\nimport { useState } from 'react'\nimport { useTools } from 'webmcp-adapter-react'\nimport { createFormTools } from 'webmcp-forms'\n\nconst fields = {\n    name: { type: 'string', label: 'Full Name', required: true, minLength: 2 },\n    email: { type: 'string', label: 'Email', required: true, pattern: '^[^@]+@[^@]+\\\\.[^@]+$' },\n}\n\nfunction ContactForm() {\n    const [values, setValues] = useState({ name: '', email: '' })\n\n    useTools({\n        tools: createFormTools({\n            formId: 'contact',\n            fields,\n            getValues: () =\u003e values,\n            onChange: (field, value) =\u003e setValues(prev =\u003e ({ ...prev, [field]: value })),\n            onSubmit: () =\u003e console.log('Submitted:', values),\n        }),\n        deps: [values]\n    })\n\n    return (\n        \u003cform\u003e\n            \u003cinput value={values.name} onChange={e =\u003e setValues(p =\u003e ({ ...p, name: e.target.value }))} placeholder=\"Full Name\" /\u003e\n            \u003cinput value={values.email} onChange={e =\u003e setValues(p =\u003e ({ ...p, email: e.target.value }))} placeholder=\"Email\" /\u003e\n            \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n        \u003c/form\u003e\n    )\n}\n```\n\n---\n\n## 🛠 API Reference\n\n### `createFormTools(options)`\n\nCreates an array of `ToolDefinition[]` for AI interaction. Pass the result directly to `registerBatch` or `useTools`.\n\n```typescript\nfunction createFormTools(options: CreateFormToolsOptions): ToolDefinition[]\n```\n\n#### Options\n\n| Option | Type | Required | Description |\n|--------|------|----------|-------------|\n| `formId` | `string` | Yes | Unique identifier for the form. Used as a prefix for all generated tool names (e.g. `fill_contact_field`) |\n| `fields` | `Record\u003cstring, FormField\u003e` | Yes | Field definitions describing each form field and its constraints |\n| `getValues` | `() =\u003e Record\u003cstring, JsonValue\u003e` | Yes | Function that returns the current form values |\n| `onChange` | `(field: string, value: JsonValue) =\u003e void` | Yes | Callback invoked when the AI sets a field value |\n| `onSubmit` | `() =\u003e void \\| Promise\u003cvoid\u003e` | No | Called when the AI invokes the submit tool |\n| `onReset` | `() =\u003e void` | No | Called when the AI invokes the reset tool |\n| `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 |\n| `selectedTools` | `Set\u003cFormTools\u003e` | No | Specific tools to include. Defaults to all tools |\n| `customTools` | `ToolDefinition[]` | No | Additional custom tools to register alongside the built-in form tools |\n\n---\n\n### `FormField`\n\nDescribes a single form field and its validation constraints.\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `type` | `'string' \\| 'number' \\| 'boolean' \\| 'array' \\| 'object'` | Field type — **required** |\n| `label` | `string` | Human-readable label used in validation error messages |\n| `required` | `boolean` | Whether the field must have a non-empty value |\n| `options` | `string[]` | Restricts the value to an enum list |\n| `min` / `max` | `number` | Min/max range for `number` fields |\n| `minLength` / `maxLength` | `number` | Length constraints for `string` fields |\n| `minItems` / `maxItems` | `number` | Length constraints for `array` fields |\n| `step` | `number` | Step constraint for `number` fields (`multipleOf` in JSON Schema) |\n| `pattern` | `string` | Regex pattern for `string` field validation |\n| `placeholder` | `string` | UI hint — not used in validation |\n| `defaultValue` | `JsonValue` | Value used when the field is reset |\n\n```typescript\nconst fields = {\n    // String with length and required constraints\n    name: {\n        type: 'string',\n        label: 'Full Name',\n        required: true,\n        minLength: 2,\n        maxLength: 50\n    },\n    // String with regex pattern\n    email: {\n        type: 'string',\n        label: 'Email',\n        required: true,\n        pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$'\n    },\n    // Number with range\n    age: {\n        type: 'number',\n        label: 'Age',\n        required: true,\n        min: 18,\n        max: 120\n    },\n    // Boolean\n    subscribe: {\n        type: 'boolean',\n        label: 'Subscribe to newsletter'\n    },\n    // String with enum options\n    country: {\n        type: 'string',\n        label: 'Country',\n        required: true,\n        options: ['US', 'UK', 'CA', 'DE', 'FR']\n    },\n    // Array with item count constraints\n    interests: {\n        type: 'array',\n        label: 'Interests',\n        minItems: 1,\n        maxItems: 5\n    },\n    // Nested object with default value\n    address: {\n        type: 'object',\n        label: 'Address',\n        defaultValue: { street: '', city: '', zip: '' }\n    }\n}\n```\n\n---\n\n### `FormTools`\n\nAvailable tool identifiers for `selectedTools`:\n\n| Tool ID | Generated Tool Name | Description |\n|---------|---------------------|-------------|\n| `fill-field` | `fill_{formId}_field` | Fill a single form field with a value |\n| `fill-multiple-field` | `fill_{formId}_multiple_fields` | Fill multiple fields at once |\n| `clear-field` | `clear_{formId}_field` | Clear a field to its default empty value |\n| `get-form-state` | `get_{formId}_state` | Get all current form values |\n| `get-field-value` | `get_{formId}_field_value` | Get a specific field's current value |\n| `validate-form` | `validate_{formId}_form` | Validate all fields without submitting |\n| `submit-form` | `submit_{formId}_form` | Submit the form |\n| `reset-form` | `reset_{formId}_form` | Reset all fields to their default values |\n\n---\n\n## 📖 Usage\n\n### With React\n\n```tsx\nimport { useState } from 'react'\nimport { useTools } from 'webmcp-adapter-react'\nimport { createFormTools } from 'webmcp-forms'\n\nconst fields = {\n    name: { type: 'string', label: 'Full Name', required: true, minLength: 2 },\n    email: { type: 'string', label: 'Email', required: true, pattern: '^[^@]+@[^@]+\\\\.[^@]+$' },\n    age: { type: 'number', label: 'Age', min: 18, max: 120 },\n    subscribe: { type: 'boolean', label: 'Subscribe to newsletter' }\n}\n\nfunction ContactForm() {\n    const [values, setValues] = useState({\n        name: '',\n        email: '',\n        age: null,\n        subscribe: false\n    })\n\n    useTools({\n        tools: createFormTools({\n            formId: 'contact',\n            fields,\n            getValues: () =\u003e values,\n            onChange: (field, value) =\u003e {\n                setValues(prev =\u003e ({ ...prev, [field]: value }))\n            },\n            onSubmit: () =\u003e {\n                console.log('Submitted:', values)\n            },\n            onReset: () =\u003e {\n                setValues({ name: '', email: '', age: null, subscribe: false })\n            }\n        }),\n        deps: [values]\n    })\n\n    return (\n        \u003cform onSubmit={e =\u003e e.preventDefault()}\u003e\n            \u003cinput\n                value={values.name}\n                onChange={e =\u003e setValues(prev =\u003e ({ ...prev, name: e.target.value }))}\n                placeholder=\"Full Name\"\n            /\u003e\n            \u003cinput\n                type=\"email\"\n                value={values.email}\n                onChange={e =\u003e setValues(prev =\u003e ({ ...prev, email: e.target.value }))}\n                placeholder=\"Email\"\n            /\u003e\n            \u003cinput\n                type=\"number\"\n                value={values.age ?? ''}\n                onChange={e =\u003e setValues(prev =\u003e ({\n                    ...prev,\n                    age: e.target.value ? Number(e.target.value) : null\n                }))}\n                placeholder=\"Age\"\n            /\u003e\n            \u003clabel\u003e\n                \u003cinput\n                    type=\"checkbox\"\n                    checked={values.subscribe}\n                    onChange={e =\u003e setValues(prev =\u003e ({ ...prev, subscribe: e.target.checked }))}\n                /\u003e\n                Subscribe to newsletter\n            \u003c/label\u003e\n            \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n        \u003c/form\u003e\n    )\n}\n```\n\n---\n\n### With a Custom Validation Schema (Zod, Valibot, ArkType)\n\nPass 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.\n\n```tsx\nimport { z } from 'zod'\nimport { createFormTools } from 'webmcp-forms'\nimport { useTools } from 'webmcp-adapter-react'\n\nconst fieldsDefinitions = {\n    name: z.string().min(2, 'Full Name must be at least 2 characters'),\n    email: z.string().email('Must be a valid email address'),\n    age: z.number().min(18, 'Must be at least 18').max(120),\n    subscribe: z.boolean().optional(),\n}\n\n// Used by validate-form — validates the flat values object\nconst formSchema = z.object(fieldsDefinitions)\n\n// Used by fill-field — validates { field: 'name', value: '...' }\nconst fieldSpecificSchemas = Object.entries(fieldsDefinitions).map(([key, schema]) =\u003e\n    z.object({ field: z.literal(key), value: schema })\n) as [ReturnType\u003ctypeof z.object\u003e, ...ReturnType\u003ctypeof z.object\u003e[]]\nconst fillFieldSchema = z.union(fieldSpecificSchemas)\n\n// Used by fill-multiple-field — validates { fields: { name?, email?, ... } }\nconst fillMultipleFieldSchema = z.object({ fields: formSchema.partial() })\n\nuseTools({\n    tools: createFormTools({\n        formId: 'contact',\n        fields,\n        getValues: () =\u003e values,\n        onChange: (field, value) =\u003e setValues(prev =\u003e ({ ...prev, [field]: value })),\n        validationSchema: {\n            form: formSchema,               // ← validate-form\n            fillField: fillFieldSchema,     // ← fill-field\n            fillMultipleField: fillMultipleFieldSchema  // ← fill-multiple-field\n        }\n    }),\n    deps: [values]\n})\n```\n\n---\n\n### Selecting Specific Tools\n\nBy default, all tools are created. Use `selectedTools` to include only the tools you need:\n\n```tsx\nimport { createFormTools } from 'webmcp-forms'\nimport type { FormTools } from 'webmcp-forms'\n\nuseTools({\n    tools: createFormTools({\n        formId: 'contact',\n        fields,\n        getValues: () =\u003e values,\n        onChange: (field, value) =\u003e setValues(prev =\u003e ({ ...prev, [field]: value })),\n        selectedTools: new Set\u003cFormTools\u003e(['fill-field', 'validate-form', 'submit-form'])\n    }),\n    deps: [values]\n})\n```\n\n---\n\n### Adding Custom Tools\n\nAdd your own tools alongside the built-in form tools:\n\n```tsx\nimport { defineTool } from 'webmcp-adapter'\nimport { createFormTools } from 'webmcp-forms'\n\nconst autofillTool = defineTool({\n    name: 'autofill_contact',\n    description: 'Auto-fill the contact form with sample data',\n    inputSchema: { type: 'object', properties: {}, required: [] },\n    execute: () =\u003e {\n        setValues({\n            name: 'John Doe',\n            email: 'john@example.com',\n            age: 30,\n            subscribe: true\n        })\n        return {\n            content: [{ type: 'text', text: 'Form auto-filled with sample data!' }],\n            structuredContent: { success: true }\n        }\n    }\n})\n\nuseTools({\n    tools: createFormTools({\n        formId: 'contact',\n        fields,\n        getValues: () =\u003e values,\n        onChange: (field, value) =\u003e setValues(prev =\u003e ({ ...prev, [field]: value })),\n        customTools: [autofillTool]\n    }),\n    deps: [values]\n})\n```\n\n---\n\n### Vanilla JavaScript\n\n```javascript\nimport { createFormTools } from 'webmcp-forms'\nimport { registerBatch } from 'webmcp-adapter'\n\nlet formValues = { name: '', email: '' }\n\nconst tools = createFormTools({\n    formId: 'contact',\n    fields: {\n        name: { type: 'string', label: 'Full Name', required: true },\n        email: { type: 'string', label: 'Email', required: true }\n    },\n    getValues: () =\u003e formValues,\n    onChange: (field, value) =\u003e {\n        formValues[field] = value\n        document.querySelector(`[name=\"${field}\"]`).value = value\n    },\n    onSubmit: () =\u003e {\n        console.log('Submitted:', formValues)\n    }\n})\n\nconst unregister = registerBatch(tools)\n\n// Later, to clean up:\n// unregister()\n```\n\n---\n\n## 📦 Exported Types\n\n```typescript\n// Core function\nexport { createFormTools } from './createFormTools'\n\n// Types\nexport type { CreateFormToolsOptions } from './createFormTools'\nexport type { FormConfig, FormState, FormField, FormTools, FieldType } from './types'\n\n// Individual tool creators (for advanced usage)\nexport {\n    createFillFieldTool,\n    createFillMultipleFieldsTool,\n    createGetFormStateTool,\n    createGetFieldValueTool,\n    createSubmitFormTool,\n    createResetFormTool,\n    createClearFieldTool,\n    createValidateFormTool,\n} from './tools'\n```\n\n### `CreateFormToolsOptions`\n\n```typescript\ninterface CreateFormToolsOptions {\n    formId: string\n    fields: Record\u003cstring, FormField\u003e\n    getValues: () =\u003e Record\u003cstring, JsonValue\u003e\n    onChange: (field: string, value: JsonValue) =\u003e void\n    onSubmit?: () =\u003e void | Promise\u003cvoid\u003e\n    onReset?: () =\u003e void\n    validationSchema?: {\n        form?: StandardSchema           // validate-form tool\n        fillField?: StandardSchema      // fill-field tool\n        fillMultipleField?: StandardSchema  // fill-multiple-field tool\n    }\n    selectedTools?: Set\u003cFormTools\u003e\n    customTools?: ToolDefinition[]\n}\n```\n\n### `FormField`\n\n```typescript\ninterface FormField {\n    type: 'string' | 'number' | 'boolean' | 'array' | 'object'\n    label?: string\n    required?: boolean\n    options?: string[]\n    min?: number\n    max?: number\n    step?: number\n    minLength?: number\n    maxLength?: number\n    minItems?: number\n    maxItems?: number\n    pattern?: string\n    placeholder?: string\n    defaultValue?: JsonValue\n}\n```\n\n### `FormTools`\n\n```typescript\ntype FormTools =\n    | 'fill-field'\n    | 'fill-multiple-field'\n    | 'get-form-state'\n    | 'get-field-value'\n    | 'submit-form'\n    | 'reset-form'\n    | 'clear-field'\n    | 'validate-form'\n```\n\n---\n\n## 🔗 Related Packages\n\n- [`webmcp-adapter`](https://github.com/asouqi/webmcp-adapter) — Core adapter for defining and registering tools\n- [`webmcp-adapter-react`](https://github.com/asouqi/webmcp-adapter-react) — React hooks for tool registration\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasouqi%2Fwebmcp-forms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasouqi%2Fwebmcp-forms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasouqi%2Fwebmcp-forms/lists"}