Skip to content

Magnet Integration

Scott C. Krause edited this page Sep 26, 2026 · 1 revision

Magnet Integration

Let an AI agent use your MachFive Magnet the way a visitor would.

A Magnet is an interactive widget that automates conversational lead generation. machvive-m5t-magnet bridges one to WebMCP, so an agent can discover what the widget collects and fill it in — instead of guessing at the DOM, or ignoring it entirely.

<machvive-m5t-magnet app-guid="your-app-guid"></machvive-m5t-magnet>
import '@machfivetechchicago/machvive-webmcp-ai/m5t-magnet';

That is the whole integration. The element loads the magnet snippet, waits for the runtime, and registers tools. It renders nothing — your magnet already draws its own launcher, and a second visible surface would compete with it.


The tools come from your magnet

Nothing here is hardcoded. A magnet already declares what it collects — each step's field, type, prompt, and options — and that declaration is an agent interface. The component reads it and generates the tools.

Configure a step in your magnet admin and it appears to agents. No code change.

Against a magnet asking product interest, name, and email:

Tool What it does
magnet_describe What the form asks, and whether it can schedule
magnet_options Allowed choices for a multiple-choice field
magnet_start Open the form with answers filled in
magnet_status Has the visitor submitted yet

magnet_options only appears if something actually has choices. This matters more than it sounds: an agent shown a tool that returns nothing useful wastes a turn discovering that, and may distrust the rest of the surface.

Here is magnet_describe against a real booking-enabled magnet:

Book time with Nicholas — Thirty minutes with me, booked in one step.

It asks:
- product_interest (single_select): "What do you want to talk about?"
    choices: Mach Five Group | Mach Five Tech | Mach Five Marketing | ...
- first_name (text): "What's your name?"
- email (email): "What's the best email to reach you?"

It can schedule "30-min meeting" via ms_bookings. The visitor books it from the
widget — you cannot book on their behalf, and the times come from a live calendar.

The agent fills in; the visitor submits

magnet_start prefills the widget and opens it. It does not submit.

This is deliberate, and it is the most important line in the integration. An agent posting a person's email address without that person seeing it is a consent problem, and lead capture is precisely where it matters. The magnet's own open({ prefill }) API reads as designed for this handoff: the agent gathers what it can from the conversation, the widget shows the visitor what will be sent, and the visitor confirms.

What the agent gets back says so plainly:

Opened the enquiry form for the visitor with product_interest, email filled in.
They will be asked for: first_name. They must review and submit it themselves.

Two booking shapes

A magnet can schedule in either of two ways, and the component reads both:

  • A booking step in mag_macro_steps — the calendar is part of the flow.
  • A book action in mag_actions — the magnet hands off to an external calendar such as Microsoft Bookings, while its steps collect something else.

The second shape is easy to miss. A magnet whose entire purpose is booking may have no booking step at all — its steps collect a name and an email, and the booking lives in mag_actions with config.source: "ms_bookings". Reading only the steps reports "cannot schedule" on exactly the magnets that can.

Some things the agent must not pre-answer

Prefillable step types are an allowlist: text, email, phone, number, single_select, multi_select. Everything else is described to the agent and left for the visitor.

A booking step is the clearest case — its slots come from a live calendar and change by the minute, so a pre-filled time would be stale or invalid by the time anyone saw it. But the same rule covers step types released after this component was written. An unrecognised type degrades to "the visitor completes this", which is the honest default for something we do not understand:

The visitor completes these in the widget — you cannot pre-answer them:
- meeting_time (booking) — a live calendar; they pick a real slot

Validation comes back as data

An invalid value does not throw. It returns a result the agent can act on, naming what would have worked:

"Nope" is not a choice for product_interest.
Options: Evaluating MachVive | Building with it and need help | ...

An unknown field name gets the same treatment. Agents self-correct from this in a single turn; an exception would end the run.

An empty value means "I do not know this" — a legitimate thing for an agent to say — and is dropped rather than rejected.


Events and properties

magnet-ready tools registered; detail carries the magnet id and tool names
magnet-capture the visitor submitted
magnet-error the runtime never loaded
.config the magnet definition this element bound to
.captures captures observed this session
document.querySelector('machvive-m5t-magnet')
  .addEventListener('magnet-capture', (e) => console.log('lead captured', e.detail));

Attributes

app-guid required unless you load the magnet snippet yourself
magnet-id pick a specific magnet when the app defines several; defaults to the home magnet
src override the snippet origin

If the page already carries a coreSnippet script, the component uses it rather than loading a second copy.


Requirements

A secure context. WebMCP is [SecureContext], so this needs https:// or localhost. Over plain HTTP there is no navigator.modelContext and no tools.

Your magnet must allow the origin. The instance is configured with permitted origins; localhost needs to be among them for local development.

Browser only. Like every component in this package, importing it during a server render throws — use a client-only import in Next.js, Nuxt, Astro, SvelteKit, or Remix.


Known limits

Stated plainly, because some of this was learned by reading the magnet runtime rather than from a specification:

  • The prefillable allowlist is conservative by choice. It covers the types seen in real magnets. A type outside it is described but not pre-answered, which is safe but may be stricter than necessary.
  • open({ prefill }) appears to cap at 40 keys and coerce values to strings. That was inferred from the runtime, not documented.
  • Only the capture event is observed. If the runtime emits others, richer status reporting is possible.
  • There is no agent-side submit, by design. If a programmatic submit exists, exposing it would be a product decision about consent, not a technical one.

Verified against two real magnets: one that collects details for email follow-up, and one that books through Microsoft Bookings.


See also