cf-webmcp
Forms

Two ways to expose a form to an agent.

The W3C WebMCP draft defines four declarative attributes - toolname, tooldescription, toolautosubmit, toolparamdescription - that turn an ordinary <form> into a WebMCP tool. There are two ways to put them on a form: let cf-webmcp inject them at the edge from one TOML block, or hand-stamp them in your origin HTML. Same contact form, both approaches, side by side below.

Submitted (demo only)

  

Contact form cf-webmcp injects

This first form has no WebMCP attributes in the origin HTML. The publisher kept their template clean. cf-webmcp stamps the four attributes onto the <form> and onto each <input> at the edge using a [[forms]] block in webmcp.toml. View source on this page to see the injected attributes appear inline on the form below.

What cf-webmcp does: matches the form by CSS selector at request time, sets toolname, tooldescription, optional toolautosubmit, and a toolparamdescription on each declared input. Honours the publisher's hand-stamps if any already exist (does not overwrite).

What cf-webmcp does not do: generate the form, change its layout, alter the submit handler, or hide the form from non-agent visitors. It only adds attributes the browser interprets as a WebMCP tool registration.

Get in touch

Contact form hand-stamped

This second form is identical in shape, but the publisher has stamped the WebMCP attributes directly into the HTML themselves. No TOML block is needed - the browser reads the attributes from origin and registers the tool. This is the path for teams that prefer to manage agent-exposed surfaces from inside their CMS or template.

What cf-webmcp does: nothing extra for this form. It passes the attributes through cleanly along with the rest of the response.

What cf-webmcp does not do: modify or remove the attributes. The publisher owns this form's WebMCP surface end to end.

Send feedback


How to test

You can verify each form three ways:

  1. View source on this page. Both forms show their attributes inline. The first form's attributes are stamped by the Worker; the second form's attributes came from origin. Same end result in the HTML.
  2. List tools from devtools. Enable chrome://flags/#enable-webmcp-testing and run in the console on this page:
    await navigator.modelContextTesting.listTools()
    Look for contact (from the injected form) and contact_alt (from the hand-stamped form) alongside the imperative tools registered by the cf-webmcp bootstrapper.
  3. Invoke one as an agent. Still in devtools:
    await navigator.modelContextTesting.executeTool(
      "contact",
      JSON.stringify({ name: "Ada", email: "ada@example.com", message: "hi" })
    )
    The page's submit handler catches the agent-invoked submission via SubmitEvent.agentInvoked and responds with a canned JSON envelope. Nothing is actually posted to a server - this is a pure demonstration. A real publisher would replace the canned response with their own server-side handling.

What the publisher gets