To make an HTML form usable by AI agents, add the WebMCP attributes: toolname and tooldescription on the form element, and a toolparamdescription on any field whose name does not explain itself. Chrome turns the form into a tool with a typed schema, the agent fills it from that schema instead of guessing at the page, and the person confirms before it is sent. Handle agentInvoked in the submit event if you want to return a structured result instead of a thank-you page.
Why do agents need anything special?
An assistant operating a browser reads your page the way a first-time visitor does. It finds a field labelled "Your details", decides whether that wants a name or an address, and moves on. Most of the time it guesses right. When it does not, you get a submission with the phone number in the message box, or none at all because a required field was never found.
WebMCP gives the agent the same thing an API gives a developer: a name for the action, a sentence saying what it does, and a description of each parameter. The browser builds the schema from your existing form, so field names, types, required flags and options come for free.
Which attributes does a form need?
<form action="https://send.webforms.to/wft_your_key" method="POST"
toolname="request_quote"
tooldescription="Ask Acme Plumbing for a quote. We reply within one working day.">
<input name="name" required>
<input type="email" name="email" required
toolparamdescription="Where the quote is sent">
<select name="job" toolparamdescription="The kind of work needed">
<option>Leak</option><option>Boiler</option><option>Bathroom fit</option>
</select>
<textarea name="details"></textarea>
<button>Request a quote</button>
</form>- toolname: a short, unique, verb-first name such as request_quote or book_table.
- tooldescription: what happens when the form is sent, in one or two sentences. Mention anything the agent should tell the person, like response times.
- toolparamdescription: optional, per field. Without it Chrome uses the field's label. Add it where the label is vague or the format matters.
- toolautosubmit: optional. Leave it off for anything that commits the person to something, so they always confirm.
What happens when an agent submits?
The browser fires the normal submit event with an extra property, agentInvoked. A page that wants to talk back cancels the default navigation and hands the agent a result instead. This matters more than it sounds: a thank-you page is written for people, and an agent has to scrape it to find out whether the submission worked. A JSON answer tells it directly, including which fields to fix.
form.addEventListener("submit", (event) => {
if (!event.agentInvoked) return; // people get the normal flow
event.preventDefault();
event.respondWith(
fetch(form.action, {
method: "POST",
body: new FormData(form),
headers: { Accept: "application/json" },
}).then((r) => r.json()), // { ok: true, id: "sub_..." } or the fields to fix
);
});What goes wrong in practice?
- Double submission: if your page already sends the form with its own JavaScript, a second handler for agents sends it twice. Handle agentInvoked in the one handler you have.
- Vague descriptions: "Contact form" tells an agent nothing. Say what the form does and what happens next.
- Drift: hand-written descriptions go stale when the form changes. Generating them from the same field list you validate against keeps them true.
- Treating agents as people: an agent submission is a person delegating. Tag it so it can be routed and replied to accordingly.
Doing it with one script tag
WebForms makes any form posting to it agent-ready with one line. The script reads the form's schema, adds toolname, tooldescription and the field descriptions you wrote in the dashboard (never overwriting attributes already in your HTML), answers agent submissions with the JSON result, and tags those submissions as browser agent so you can route them separately.
<script src="https://send.webforms.to/webforms.js" defer></script>