<br />

Web features: [Form-associated WebMCP attributes](https://webstatus.dev/features/declarative-webmcp)

> [!NOTE]
> **Note:** These guides are authored for AI coding agents (apologies for the robotic tone!). To have your coding agent adopt these patterns automatically, check out [Modern Web Guidance](https://github.com/GoogleChrome/modern-web-guidance).

> [!CAUTION]
> **Caution: Origin Trial features require explicit project opt-in.**
>
> This guide covers an active Origin Trial, which is experimental and subject to change. To prevent coding agents from adopting unstable APIs without developer consent, the Modern Web Guidance skill gates this guidance by default. See the [ChromeStatus entry](https://chromestatus.com/feature/5117755740913664) for current trial status and timeline.
>
> To enable experimental Origin Trial guidance for your project, run this command in your terminal:
>
> ```bash
> npx modern-web-guidance@latest set-allow-origin-trials
> ```
>
> This writes `{"allowOriginTrials": true}` to your project's `.mwgrc` configuration.

The Declarative API transforms standard HTML `<form>` elements into WebMCP tools via attributes. The browser synthesizes a JSON Schema from the form inputs and handles agent interactions.

**Angular Signal Forms:** **DO NOT** add `toolname`/`tooldescription` to forms built with `form()` from `@angular/forms/signals`. Instead, add `provideExperimentalWebMcpForms()` to the app providers and pass the `experimentalWebMcpTool: { name, description }` option to `form()`. Angular then registers the form through the Imperative API, building the schema from the signal model and wiring it to validation and submission. Using both approaches registers the same form twice.

## Form Attributes

- `toolname`: Unique name for the tool.
- `tooldescription`: What the tool does and when an agent should use it. Do not list the form's fields, options, or limits: the browser already includes them in the schema it builds from the form controls.
- `toolautosubmit`: (Optional) If present, the agent can submit the form without waiting for user interaction.
- `toolparamdescription`: (Optional) Provides a way to define a property description within the JSON Schema. Use it to explain what the value means (for example, with sample values), not to repeat the control's options or limits.
  - **Resolution Order** : The browser uses `toolparamdescription` if present. In its absence, it uses the `textContent` of the associated `<label>` (skipping labelable descendants). If no label exists, it falls back to the `aria-description`.
  - **Grouping (Fieldsets)** : To attach a description to a group of related elements (like `<input type="radio">` buttons), place `toolparamdescription` on the nearest parent `<fieldset>` element so it applies to the parameter group as a whole.

### Example

```html
<form toolname="search-cars" 
      tooldescription="Perform a car make/model search" 
      toolautosubmit>
  <label for="make">Vehicle Make</label>
  <input type="text" id="make" name="make" required>
  
  <label for="model">Vehicle Model</label>
  <input type="text" id="model" name="model" toolparamdescription="e.g., 330i, F-150" required>
  
  <button type="submit">Search</button>
</form>
```

## Handling Submissions in JavaScript

When an agent submits the form, the `SubmitEvent` includes `agentInvoked` (boolean) and `respondWith(promise)`.

```javascript
document.querySelector('form').addEventListener('submit', (event) => {
  event.preventDefault();

  // Validate the form
  const formValidationErrors = myFormIsValid();

  if (formValidationErrors.length > 0) {
    if (event.agentInvoked) {
      const errorString =
        'Validation failed: ' +
        formValidationErrors
          .map((err) => `${err.field} (${err.message})`)
          .join(', ');

      event.respondWith(Promise.resolve(errorString));
    }
    return;
  }

  const resultPromise = performAsyncSearch(new FormData(event.target));

  // Return the result directly to the agent without navigation
  if (event.agentInvoked) {
    event.respondWith(resultPromise);
  }
});
```

## Lifecycle Events

`document.modelContext` emits events when agents start or stop interacting with a tool: `toolactivated` fires when tool execution starts, and `toolcancel` fires when it is canceled.

```javascript
// Starting in Chrome 156, these events are dispatched on `document.modelContext`.
// Older versions dispatch them on `window`. Feature-detect the event handler
// property to pick the right target for backward compatibility.
const targetFor = (type, listener, options) =>
  (`on${type}` in (document.modelContext ?? {}) ? document.modelContext : window)
    .addEventListener(type, listener, options);

targetFor('toolactivated', ({ toolName }) => {
  console.log(`Tool "${toolName}" started execution.`);
});

targetFor('toolcancel', ({ toolName }) => {
  console.log(`Tool "${toolName}" execution is cancelled.`);
});
```

## Visual Feedback (CSS)

Use pseudo-classes to highlight forms when an agent interacts with them:

- `:tool-form-active`: Applied to the `<form>` element actively used by the agent.
- `:tool-submit-active`: Applied to the submit button when the browser pauses for user review (if `toolautosubmit` is omitted).

```css
form:tool-form-active {
  outline: 2px dashed blue;
  background-color: rgba(0, 0, 255, 0.05);
}

button:tool-submit-active {
  outline: 2px dashed red;
  animation: pulse 2s infinite;
}
```

## Form Suitability (When to Avoid)

The Declarative API is best for self-contained, standard forms. It is a poor choice in these scenarios:

- **Highly Dependent Fields**: Forms where inputs change options or visibility based on other inputs. The synthesized schema cannot express these dependencies well.
- **Custom UI Components**: Forms relying on non-standard inputs (e.g., canvas, rich text editors) that don't auto-serialize values.
- **Multi-Step Wizards**: Complex workflows requiring multiple form submissions. The Imperative API or standard DOM interaction is better suited here.

## When to use toolautosubmit

- **Read-Only Operations \& Queries**: Searches, filters, fetching details, or checking status (e.g., a car model search, searching a directory, checking stock availability).
- **Low-Risk, Reversible Actions**: Form actions that can easily be undone or refined by the user manually (e.g., adding items to a cart, applying a coupon code, saving a draft, or setting temporary layout options).

## When to omit toolautosubmit

- **Destructive or Irreversible Actions**: Deleting records, resetting system configurations, or clearing databases.
- **Financial \& Transactional Actions**: Submitting a checkout form, transferring funds, authorizing subscription payments, or final order placements.
- **High-Impact User Communication**: Submitting a final job application, sending emails/messages to other real users, or publishing public-facing content.
- **Sensitive Account Settings**: Changing passwords, modifying user roles/permissions, or updating billing/profile info.

## Fallback strategies

<iframe src="https:///frame/docs/modern-web-guidance/guides/webmcp/agentic-forms_bf19c1e1bd8c8eecebdf5b5aa8de27f85c5968bd856cb91dcb4655c67c585671.frame" class="framebox inherit-locale " allow="clipboard-write https://" allowfullscreen is-upgraded></iframe>

The WebMCP Declarative API is safe to use in all browsers. Browsers that do not support WebMCP will ignore the `tool*` attributes, and the `<form>` will continue to function as a normal HTML form. No feature detection is required.
Source: [agentic-forms guide on GitHub](https://github.com/GoogleChrome/modern-web-guidance-src/blob/main/guides/webmcp/agentic-forms/guide.md)