Write Tools by Hand
Full control over every field. Best for auth-protected pages, complex logic, or precise DOM targeting.
When to write by hand
- Your page is behind a login (AI generation can't scrape it)
- You need specific DOM selectors that AI wouldn't guess
- You want deterministic, well-tested
executeJslogic
The input schema
The input schema defines what parameters the tool accepts. It follows JSON Schema format.
Using the Form Builder
Add each parameter with a name, type, and optional description. The required toggle marks a field as mandatory.
Supported types: string, number, boolean, array, object.
Using Raw JSON
Switch to Raw JSON mode for full schema control:
{
"type": "object",
"properties": {
"productId": {
"type": "string",
"description": "The product SKU, e.g. shoe-01"
},
"quantity": {
"type": "number",
"description": "Number of items to add. Defaults to 1 if omitted."
}
},
"required": ["productId"]
}Write clear description values. AI agents read these to understand what to pass. "Product ID" is vague. "The product SKU from the URL, e.g. shoe-01" is useful.
The executeJs field
JavaScript that runs in the visitor's browser when the tool is called.
Available globals:
args: the input parameters, typed per your schemadocument,window,fetch: full browser environment- No Node.js APIs (no
require,fs,process)
Return value: A plain object returned to the AI agent as the tool result. Always return something meaningful.
// Click a button
const btn = document.querySelector('#submit-btn')
if (!btn) return { success: false, error: 'Button not found' }
btn.click()
return { success: true }// Call an internal API
const res = await fetch('/api/cart/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId: args.productId, quantity: args.quantity ?? 1 })
})
const data = await res.json()
return { success: res.ok, ...data }// Read a value from the page
const price = document.querySelector('[data-price]')?.textContent
return { price: price?.trim() ?? null }Tools that navigate the page
If executeJs sets window.location (directly, via .href, .assign(), .replace()) or submits a form, the page can start unloading before the calling agent gets a result back. The editor warns you inline if it detects this pattern, but the warning can't guarantee the call actually completes, unload timing is up to the browser.
If you know a tool is meant to navigate (e.g. goToCheckout), that's fine, just be aware the agent may see the call as failed or timed out even though the navigation itself succeeded. Aigentably does best-effort detection of this: if the page unloads while a call is still in flight, it's logged as Interrupted in Recent Calls instead of silently disappearing, so at least you can tell it happened.
For tools where the agent needs a reliable result (confirmation of an action, data to act on), avoid navigating in executeJs and read/write through fetch instead.
Allowed origins: scoping across frames, not across agents
WebMCP's exposedTo option controls which documents in your page's own frame tree can see a tool, not which AI agent or service is allowed to call it. If your page embeds a cross-origin iframe, a third-party widget, an embedded checkout, an ad, and you don't want a tool registered on the parent page visible inside that iframe (or the reverse), list the iframe's origin in Allowed origins.
There's no equivalent control for restricting an external agent by identity: once a tool is exposed to a document, any script running there, including whatever agent tooling that page has loaded, can call it. Most sites don't have cross-origin frames at all, in which case this field does nothing and should stay blank, including for sensitive actions like submitSupportTicket or applyCoupon. If you want to restrict who can trigger those, do it the way you'd protect any other client-triggered action: require the visitor to be authenticated, or gate the change server-side, rather than through tool registration.
Path patterns scope a tool to specific pages of your site. Allowed origins scope a tool to specific frames within a page. Neither one authenticates the caller.
Tool history and rollback
Every time a tool is created, edited, or reverted, Aigentably saves a full snapshot. Click the history icon on any tool to see:
- What changed between versions, field by field
- Whether a change has been marked as reviewed
- A Revert to this button on any past version
Reverting doesn't erase history, it creates a new version whose content matches the one you reverted to, so the full trail stays intact. Use this if a change turns out to be wrong, or if you want to confirm nobody else with dashboard access modified a tool's executeJs without you knowing.
Security warnings
The editor shows live warnings for dangerous patterns. See executeJs Reference for the full list.