Docs
API 1.39
Status
Guides

Coding agents (MCP)

Connect Claude Code, Codex, Cursor or any MCP client to Kaabist and let it build, test and maintain programs in a real Kaabist browser.

Kaabist runs a hosted Model Context Protocol server at https://mcp.kaab.ist/mcp that lets a coding agent build programs for you in a real Kaabist browser on Kaabist's pool, not its own. The agent clicks, fills and reads a condensed page view with ranked locator candidates, tries extracts on the live page, turns what it did into a draft program, lints and tests it, and follows jobs and healing proposals afterwards.

#When to use it

Connect an agent when you already work with one (Claude Code, Codex, Cursor or any MCP client) and want it to write and maintain programs: describing a site in a sentence and reviewing the program it produces is often faster than picking every field by hand. The agent works with your role and within limits you set, and everything it does is visible in the panel.

Prefer the program builder when you want to pick fields yourself, and the SDKs when your own code runs programs in production. An agent is a way to author programs, not a runtime.

#Connect

Claude Code

claude mcp add --transport http kaab https://mcp.kaab.ist/mcp

Codex, in ~/.codex/config.toml:

[mcp_servers.kaab]
url = "https://mcp.kaab.ist/mcp"

Cursor, in .cursor/mcp.json:

{ "mcpServers": { "kaab": { "url": "https://mcp.kaab.ist/mcp" } } }

The first time the agent connects, your browser opens Kaabist's consent page.

The consent page opens in the panel (sign in first if you are not). It is a single card that names your agent ("… wants to use Kaabist"), with the address it will send you back to underneath, and four choices:

  • Organisation: the agent works in one organisation (your current one is preselected), with your role in it. It can never do more than you can, and if you leave the organisation it stops at once.
  • Mode: Test (the default: free test jobs on a small daily quota, results kept 24 hours) or Live (real jobs that spend credits). Choosing Live shows a warning that the agent will spend credits and act on real sites with your organisation's sessions.
  • Allow the agent to: one checkbox per scope.
    CheckboxScopeLets the agentTicked by default
    Readkaab:readread programs, jobs, proposals, sessions, usage and your credit balanceyes
    Browsekaab:browseopen Kaabist browsers you can watch and take overyes
    Runkaab:runsave draft programs and run test jobsyes
    Publishkaab:publishpublish program versions and move aliasesno
    Approvekaab:approveapprove fixes and make them permanentno
    Side effectskaab:side_effectslet test runs perform steps marked as side effects (orders, sends, deletes)no
  • Credits per agent session: the most one agent session may spend (100 by default, at most 10 000).

Allow sends you back to the agent; Deny refuses. Where two-factor authentication is required, the page asks you to enrol an authenticator first. A grant never manages keys, members, billing, webhooks or BYO providers, and never takes over a job.

Settings → Connected apps lists every agent you connected in a table (app, organisation, mode, scopes, when it connected, when it was last used) and, above it, the agent browsers open now. Revoke asks for confirmation and stops the agent's tokens at once.

#Credits

Browser time is billed while a browser is open, in test mode too, because test mode's free quota covers jobs, not browsers. Each session stops at its cap. The estimate tool tells the agent what a job and a browser minute cost; credits shows your balance and what the session spent.

#Watching and taking over

Every browser an agent opens appears in the panel's top bar, under the N live button that lists open browsers as "Agent browser", and on Connected apps. Open it to watch: the page shows the browser on the left with its address and connection status, and the banner "Agent is driving" with the line "You are watching". A rail on the right shows what has been recorded so far, with Take control and Close the browser. Take control hands the browser to you; the agent's browser tools then answer controlled_by_person until you press Return control. What you do while in control is recorded like the agent's actions.

#Without OAuth

An agent that cannot run the OAuth flow can send an API key instead: Authorization: Bearer sk_test_…. The key's own mode and scopes apply (read reads; run also browses, runs, publishes and approves; admin adds side effects), with a 100-credit cap per session.

#Tools

ToolDoes
browser_openopen a Kaabist browser on a URL; returns its browser_id, the watch link and a page view
browser_navigate, browser_click, browser_fill, browser_select, browser_scroll, browser_press, browser_waitact on the page (targets are page-view refs like e12 or DSL targets); each answers what it did (effects) and what still covers the page (obstacles_after)
browser_page_viewthe condensed page: obstacles, actions, outline, landmarks, forms, lists, text elements, JSON paths
browser_screenshota JPEG of the viewport, or of a whole long page as tiles
browser_evaluate, browser_downloadrun JavaScript in the page, or download a file into the browser's artifacts; both recorded as steps
browser_closeclose the browser and settle what it cost
browser_to_programturn what was done into a draft program
try_extractrun an extract on the live page (or on a URL, as a job)
lint_program, push_program, diff_versionscheck, save (a draft unless allowed to publish) and compare versions
test_programrun a version as a job: a dry run unless told otherwise
answer_inputanswer a job waiting for input (a one-time code)
get_job, list_jobs, cancel_job, resume_jobfollow jobs, cancel them and act on parked ones; a resume within minutes of the park carries on in the same page and keeps the data and files from before it
list_proposals, get_proposalread healing proposals
get_artifacta file a job or a browser kept: a link, and the file itself up to 1 MB
estimate, creditsprices and balance

Resources: kaab://docs/dsl-quickref, kaab://schemas/program-1.json, kaab://programs/{name}. Prompts: build_program_for_site (a url and a goal) and fix_failing_job (a job_id).

#Reading a page

A page view leads with what an agent needs before it acts:

  • obstacles: what covers the page, such as a consent banner, a dialog or a tour. Each says its kind, the vendor when Kaabist recognises the framework, whether it covers the whole viewport or part of it, and up to three dismiss controls (reject first, then close, then accept) by ref. Kaabist never dismisses anything for the agent; clicking one of those refs is recorded like any other click.
  • actions: every visible link and button, in page order, with where it sits (in: header, nav, main, footer, dialog) and up to three locator candidates. A button repeated with the same text and link is listed once with a count.
  • Then the outline (headings h1 to h3), landmarks, forms (their fields, never their values), repeating lists with sample texts, other text elements, and the paths found in embedded_json (such as ld+json blocks) and network_json (JSON responses the page loaded).

A view never exceeds its byte budget (max_bytes, 20 000 by default); truncated names the sections that were shortened, the text elements first, the obstacles last. Refs such as e12 are valid until the next page view.

Every action answers changed and effects (whether it navigated, added or removed nodes, scrolled, cleared an obstacle, or opened or closed a dialog), so the agent rarely needs a screenshot to know what happened. A long page is read with browser_scroll { by: "page" } until at_end (these relative scrolls are not recorded), and seen with browser_screenshot { full_page: true }: the page is revealed first, then returned as tiles up to 1 600 px tall, six per call, continued with from_tile.

#Worked example

Take the home page of https://app.example.com, a long marketing page: a sticky header, 45 headings, two large ld+json blocks, a carousel, lazy images and a Cookiebot consent banner over the bottom of the screen. Ask your agent: "Open https://app.example.com/ and find where Start building leads."

The page view. browser_open answers with a view whose title is "Example Cloud: cloud runtime for AI agents" and whose obstacles holds one entry: kind: "consent", vendor: "cookiebot", covers: "partial", with a reject control labelled "Reject all". Its ref also appears in actions with in: "dialog", next to "Show details". The other actions read in page order: the header's links (Docs, Pricing, Blog and Changelog in: "nav", Sign in), then "Start building" in: "main" with count: 2 (the page shows it twice), "Talk to an engineer", the carousel's "Previous slide" and "Next slide" buttons, and the footer's links. The outline keeps 40 of the 45 headings, every h1 and h2 and the first h3s, and the ld+json paths are cut to a sample; both are named in truncated, so the agent knows there is more.

Acting on it. The agent clicks the "Reject all" ref. The answer says obstacle_cleared: true and obstacles_after is empty. It scrolls by page until at_end to read every heading, then clicks "Start building": effects.navigated is true and the URL ends in /start. A click on the carousel's "Next slide" would instead answer changed: true with navigated: false, because the slides move inside the page.

Building a program. On a page with data, such as https://shop.example.com/p/1, the agent continues with try_extract to check fields against the live page, browser_to_program to turn its steps into a draft, lint_program, push_program and test_program, which runs the draft as a dry run. You see the browser in the panel's top bar the whole time, and the draft under Programs.

To see which tools a bearer may call without an MCP client, open a session and list them. The list depends on the scopes: a read key gets the reading tools only.

TypeScript
const headers = {
  authorization: `Bearer ${apiKey}`, // an sk_ key, or an OAuth access token
  "content-type": "application/json",
  accept: "application/json, text/event-stream",
};
const rpc = (id: number, method: string, params: object = {}) =>
  JSON.stringify({ jsonrpc: "2.0", id, method, params });

// 1. initialize opens a session; its id comes back in Mcp-Session-Id.
const init = await fetch(endpoint, {
  method: "POST",
  headers,
  body: rpc(1, "initialize", {
    protocolVersion: "2025-11-25",
    capabilities: {},
    clientInfo: { name: "kaab-example", version: "1.0.0" },
  }),
});
const session = init.headers.get("mcp-session-id") ?? "";
const hello = await readMessage(init);
console.log(`connected to ${hello.result?.serverInfo?.name}`);

const sessionHeaders = { ...headers, "mcp-session-id": session };
await fetch(endpoint, {
  method: "POST",
  headers: sessionHeaders,
  body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }),
});

// 2. tools/list: only the tools this bearer's scopes allow.
const listed = await readMessage(
  await fetch(endpoint, { method: "POST", headers: sessionHeaders, body: rpc(2, "tools/list") }),
);
for (const tool of listed.result?.tools ?? []) console.log(`${tool.name}`);

#Pitfalls

  • Live mode by accident. Choose Test on the consent page unless the agent must do real work; live browsers and jobs spend real credits.
  • Giving kaab:side_effects to explore. A test run with it places real orders and sends real messages. Leave it off until a program's side effects are what you want.
  • Expecting the agent to dismiss banners on its own. Kaabist reports obstacles and their controls; the agent has to click one.
  • Stale refs. A ref is valid until the next page view; after a navigation, read the page again.
  • Hitting the credit cap mid-task. The session stops at its cap. Raise it on the consent page when you reconnect, or close browsers the agent no longer needs.

#Reference

Was this page helpful?