@aemforms/af-webmcp
v1.0.9
Published
WebMCP adapter that registers Adaptive Forms tools on the browser modelContext
Keywords
Readme
@aemforms/af-webmcp
Expose Adaptive Forms model capabilities as WebMCP tools for compatible browser hosts and custom integrations.
This package registers tools for inspecting, filling, navigating, and submitting an Adaptive Form. The tools operate on the live @aemforms/af-core model rather than scraping the rendered page. The adapter manages registration and cleanup; it does not render forms, provide an AI agent, or implement a remote-agent transport.
Installation
npm install @aemforms/af-core @aemforms/af-webmcpThe package provides CommonJS and ES module builds, plus TypeScript declarations.
Quick start
Run this example in a browser application with a compatible WebMCP host:
import {createFormInstance} from '@aemforms/af-core';
import {registerFormWebMCP} from '@aemforms/af-webmcp';
const form = createFormInstance({
id: 'travel-request',
title: 'Travel request',
fieldType: 'form',
properties: {'fd:webMcpEnabled': true},
items: [{
id: 'destination',
name: 'destination',
fieldType: 'text-input',
type: 'string',
label: {value: 'Destination'},
required: true
}]
});
const unregister = registerFormWebMCP(form);Keep the returned cleanup function and call it when the form is removed or its owner unmounts:
unregister();For an existing rendered form, pass its existing model to registerFormWebMCP instead of creating a second model. Registration alone does not render the example form.
Opt-in
Registration is disabled by default. The adapter reads form.webMcpEnabled, which reflects the authored properties['fd:webMcpEnabled'] value. Boolean true and string "true" opt the form in.
An explicit enabled option takes precedence:
const unregisterOverride = registerFormWebMCP(form, {enabled: true});Use {enabled: false} to prevent registration for that call, even when the form opts in. To revoke an existing registration, call its cleanup function.
Available tools
The adapter exposes one page-level discovery tool and twelve form-bound tools:
| Tool | Purpose |
| --- | --- |
| list_forms | List the active opted-in forms and their registration IDs. |
| get_form_summary | Read the form title and the current state of its fields. |
| get_field_value | Read one field's value, display value, and known validity. |
| explain_field | Read a field's state, options, help text, and constraints. |
| validate_form_completeness | Inspect missing required values and known-invalid fields without running validation or changing UI error state. |
| list_repeatable_instances | Read a repeatable section's instance count and limits. |
| focus_field | Request focus on a field through the model and optional renderer bridge. |
| navigate_to_panel | Activate a panel, tab, or wizard step through the model. |
| set_field_value | Set one field through its model value setter. |
| apply_prefill | Apply a list of {field, value} pairs and report each field's result. |
| add_repeatable_instance | Add an instance within the repeatable section's limits. |
| remove_repeatable_instance | Remove an instance by its zero-based index, respecting the minimum count. |
| submit_form | Prepare configured automatic CAPTCHA handling, run model validation, and await the form's submission outcome. |
validate_form_completeness is an inspection, not a guarantee that submission will pass validation. submit_form uses the form's full validation and submission lifecycle. A pending submission result is not confirmation of success; visible CAPTCHA still requires user/provider interaction.
Field values and metadata are supplied by the form model. Built-in tools return structured results with success; unsuccessful results include error or validation information.
Registration API
import type {
AdditionalToolsFactory,
RegisterFormWebMCPOptions
} from '@aemforms/af-webmcp';registerFormWebMCP(form, options?): () => void
Registers an Adaptive Forms model with the selected host and returns an idempotent cleanup function.
| Option | Description |
| --- | --- |
| enabled | Boolean override of the form's WebMCP opt-in. |
| modelContext | Explicit registration host implementing registerTool. Highest priority. |
| transports | Ordered fallback factories returning a compatible registration host, undefined, or null. Used only when no explicit or native host is available. |
| exposedTo | Origin allow-list forwarded to the host's registerTool options. Enforcement belongs to the host. |
| onRequestApproval | Callback receiving {name, args} for tools annotated consequentialHint. Returns a boolean or a promise of a boolean. |
| onFocusRequest | Renderer callback receiving a field ID. Focus that field in this form's view and return whether DOM focus changed. |
| additionalTools | AdditionalToolsFactory: a function receiving the form and returning additional WebMcpTool objects from @aemforms/af-core. |
Host resolution order is:
- A usable explicit
modelContext. - Native
document.modelContext, thennavigator.modelContext. - The first usable host returned by a
transportsfactory.
A compatible host implements registerTool(tool, options?). Registration may return an unregister handle directly or through a promise. For the adapter to remove tools from the host, the host must honor registration abort signals, return a handle with unregister(), or implement unregisterTool(name).
Cleanup revokes routing to the removed form. Cleaning up one form leaves other registered forms available. Compatible duplicate registrations of the same model share ownership, so each owner must call its own cleanup function. Use consistent callback/factory references for duplicate owners and consistent exposedTo policies for forms sharing a host.
Additional tools
Additional tools extend rather than replace the built-in catalog. They receive the same form routing, approval handling, structured execution-error handling, and lifecycle cleanup.
Custom tool names must be unique and must not collide with built-in names. list_forms and the input property form_id are reserved. A custom tool name shared across forms must have compatible descriptors and schemas.
Multiple forms and field targeting
With one active form, form-bound tools can omit form_id. With multiple forms, call list_forms and pass the selected registration ID to subsequent tools:
{
"form_id": "travel-request",
"field": "destination",
"value": "Paris"
}These are example arguments for set_field_value. Omitting form_id when multiple forms are active returns an ambiguity error rather than selecting an arbitrary form. Use the IDs returned by list_forms; default model IDs receive distinct adapter registration IDs. Duplicate active authored form IDs are rejected.
Field and panel references can use an ID, qualified name, or an unambiguous name. For repeatable fields, prefer an instance-specific ID or qualified name such as $form.dependents[1].depName; a name shared by multiple instances cannot identify the intended field.
Consent and data handling
The built-in value-write, repeatable-instance-change, and submission tools are annotated with consequentialHint. A compatible host should obtain user confirmation before executing them.
For an adapter-side approval gate, supply onRequestApproval:
const unregisterWithApproval = registerFormWebMCP(form, {
onRequestApproval: ({name}) =>
window.confirm(`Allow the form operation "${name}"?`)
});Use this registration instead of the quick-start registration when approval is required. The callback is awaited before a consequential tool executes. If it returns a falsy value or throws, the adapter refuses the operation with {success: false, error: 'user consent required'}. Tools without consequentialHint, including reads and built-in navigation, bypass this callback.
Tool results can contain entered field values and personal information. The configured host or transport determines where those results go. Review that integration's data handling before enabling access to sensitive forms. This package does not select an AI provider or guarantee that results remain on the device.
get_form_summary, get_field_value, explain_field, and validate_form_completeness carry untrustedContentHint. Not every tool returning authored text carries this hint: list_forms returns authored form titles but is annotated only with readOnlyHint. Tool annotations are advisory metadata, not sanitization or access control. Treat returned text as untrusted content, not instructions, regardless of whether the hint is present.
Compatibility
Native WebMCP availability depends on the browser and host. The adapter does not install a polyfill or enable browser features. Without opt-in or a compatible registration host, registration returns a no-op cleanup function.
Calling the adapter in an unsupported browser or server-side environment is safe when no host is available. An explicit modelContext or fallback transport can supply a compatible host without native browser support.
Model navigation requires a renderer that responds to active-child changes. Supply onFocusRequest when the renderer needs an explicit DOM-focus bridge. A headless model has no rendered elements to focus.
Remote/server-side agent communication is the integrator's responsibility. The modelContext and transports options accept a host supplied by that integration; they do not create its communication channel.
License
Adobe Proprietary. See the LICENSE file included with the package for the applicable terms.
