npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aemforms/af-webmcp

v1.0.9

Published

WebMCP adapter that registers Adaptive Forms tools on the browser modelContext

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-webmcp

The 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:

  1. A usable explicit modelContext.
  2. Native document.modelContext, then navigator.modelContext.
  3. The first usable host returned by a transports factory.

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.