<wmcp-button>

The first interaction primitive. Where the form controls expose a value an agent can set, a button exposes an action an agent can trigger. With no agent present (the common case today) it is simply a good, accessible button.

<wmcp-button variant="primary">Save</wmcp-button>

Both a real click and an agent's tool call route through the same inner button, so the click handlers you already wrote run either way — and type="submit" / type="reset" drive the surrounding form. A disabled button can be activated by neither.

Element attributes

AttributeTypeDefaultDescription
variantstringprimaryVisual style: primary, secondary, destructive, outline, ghost (reflected).
sizestringmdsm, md, or lg (reflected).
typestringbuttonbutton, submit, or reset. submit/reset act on the containing form.
disabledbooleanfalseDisables the button for humans and agents alike (reflected).
labelstringAccessible name. Falls back to the slotted text; set it for icon-only buttons.
namestringIdentifier used for the default tool name (click_<name>).
exposebooleanfalseRegister a WebMCP tool that activates this button.
tool-namestringOverride the generated tool name.
tool-descriptionstringOverride the generated tool description.

The visible label is provided as the element's content (slotted), not via an attribute:

<wmcp-button variant="destructive">Delete account</wmcp-button>

Form participation

A native <button type="submit"> inside a shadow root can't reach the page's form. <wmcp-button> is form-associated, so it does — submitting and resetting work as you'd expect:

<form>
  <wmcp-input name="email" type="email" required></wmcp-input>
  <wmcp-button type="submit">Sign up</wmcp-button>
  <wmcp-button type="reset" variant="ghost">Clear</wmcp-button>
</form>

Tool shape

The exposed tool takes no arguments — calling it is the action:

{
  "type": "object",
  "properties": {}
}

When the agent calls it, the button activates exactly as a click would. The tool result is the agent's only feedback channel, so it reports the outcome the button observed — never the outcome it merely intended. A type="submit" call is reported as submitted only if the form's submit event actually fired; if a page handler calls preventDefault() on that event, it still counts as submitted, because the form was submitted as far as the DOM is concerned.

In every message below, <noun> is the button's label, else its trimmed text content, else its name, else "button".

CaseOutcomeMessage
disabled (any type)errorThe "<noun>" button is disabled and can't be activated.
type="button"successClicked the "<noun>" button.
type="submit", form submitssuccessClicked the "<noun>" button and submitted the form.
type="submit", not inside a formerrorClicked the "<noun>" button, but it is not inside a form — nothing was submitted.
type="submit", form fails validationerrorClicked the "<noun>" button, but the form failed validation and was not submitted. Fix the invalid fields and try again.
type="reset", inside a formsuccessClicked the "<noun>" button and reset the form.
type="reset", not inside a formerrorClicked the "<noun>" button, but it is not inside a form — nothing was reset.

"error" means the result comes back with isError: true, so an agent orchestrator can branch on it without parsing the message text. Note that in the "not inside a form" cases the click still runs — light-DOM click handlers fire as normal — only the form step is skipped.

Theming

Every visual is a CSS custom property, defaulting through the design tokens to the shadcn base palette. Override per variant:

:root {
  --button-primary-bg: var(--brand);
  --button-primary-text: var(--brand-foreground);
  --button-radius: 9999px; /* pill buttons */
}