Skip to main content
Glama
TrueNix
by TrueNix

kitesurf-bridge

Drive Cloudflare Kitesurf — the agent-first browser that runs in V8 isolates on Cloudflare Workers — from anywhere. Zero dependencies, no local Chrome.

Ships four ways to use one engine:

Surface

Install

Use it for

MCP server

npx -y github:TrueNix/kitesurf-bridge mcp

Claude Code, Cursor, Codex, any MCP client

CLI

npx -y github:TrueNix/kitesurf-bridge markdown <url>

shells, scripts, CI

Library

import { withSession } from 'kitesurf-bridge'

your own Node code

DSH / Cordis plugin

composition row

native tools in a DSH harness

Install commands below use the GitHub spec, which works today with no registry account. Once published to npm as @truenix/kitesurf-bridge, every github:TrueNix/kitesurf-bridge shortens to @truenix/kitesurf-bridge.

npx -y github:TrueNix/kitesurf-bridge markdown https://news.ycombinator.com

That renders a real page in a real browser engine, on Cloudflare's network, with no browser installed locally and no API token.


Why this exists

Kitesurf is not open source and cannot run on your machine. Cloudflare says they intend to open source it "once we're ready", and even then the stated goal is for customers to "deploy their own version of Kitesurf on their own accounts" — still on Workers.

There is also no local Kitesurf in the dev loop: wrangler dev launches your local Chrome, not Kitesurf. Kitesurf only exists behind browser=kitesurf on remote endpoints.

So the practical question is not "can I run it locally" but "can I drive it from local code". This package is that bridge.

Install

As an MCP server

claude mcp add kitesurf -- npx -y github:TrueNix/kitesurf-bridge mcp
{
  "mcpServers": {
    "kitesurf": {
      "command": "npx",
      "args": ["-y", "github:TrueNix/kitesurf-bridge", "mcp"]
    }
  }
}
{
  "mcpServers": {
    "kitesurf": {
      "command": "npx",
      "args": ["-y", "github:TrueNix/kitesurf-bridge", "mcp"],
      "env": {
        "CLOUDFLARE_ACCOUNT_ID": "your-account-id",
        "CLOUDFLARE_API_TOKEN": "your-browser-run-token"
      }
    }
  }
}

Tools exposed: kitesurf_markdown, kitesurf_text, kitesurf_html, kitesurf_links, kitesurf_screenshot, kitesurf_evaluate, kitesurf_accessibility_tree, kitesurf_probe.

As a DSH / Cordis plugin

# in an agent preset composition
- '@truenix/kitesurf-bridge/cordis':
    cli: npx -y github:TrueNix/kitesurf-bridge
    timeoutMs: 120000

The plugin registers the same tools on the host. It deliberately shells out to the CLI: a dynamic Cordis host half has no WebSocket, fetch or node:* access, so CDP cannot be opened inside the sandbox. See cordis/plugin.mjs.

As a library

npm install github:TrueNix/kitesurf-bridge
import { withSession } from '@truenix/kitesurf-bridge';

const md = await withSession({}, async (session) => {
  await session.navigate('https://example.com');
  return session.markdown();
});

CLI

kitesurf-bridge <command> [options]

  markdown <url>     Extract the page as Markdown (main content by default)
  text <url>         Visible text only
  html <url>         Full serialized DOM after JS runs
  links <url>        Every anchor as JSON
  screenshot <url>   PNG/JPEG   (-o file, --full)
  pdf <url>          PDF        (-o file)
  a11y <url>         Filtered accessibility tree
  eval <url> <expr>  Evaluate JS in the page
  probe              Endpoint + engine capability report
  mcp                Run as an MCP server on stdio

Useful options: --main, --raw, --full, --width, --height, --json, --endpoint, --account, --token, --timeout.

Endpoints

Playground (default)

Account

URL

wss://kitesurf.cloudflare.app/devtools/page/kitesurf

wss://api.cloudflare.com/.../devtools/browser?browser=kitesurf

Auth

none

Authorization: Bearer <token>

Target

page

browser (a page is created + attached automatically)

Suitable for

evaluation

production

Set CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN (or CF_*) to switch. Supplying an account id without a token is a hard error rather than a silent downgrade to the shared playground.

WARNING

The playground is a free, shared, unauthenticated resource with no SLA. Fine for evaluation and local agent work — do not build production on it.

Things worth knowing about Kitesurf

These are verified against the live service, not copied from docs. kitesurf-bridge probe reproduces them.

Kitesurf does not run V8 for page script — it runs Boa, a Rust JS engine. Boa enforces a much lower recursion limit and throws RuntimeLimit: exceeded maximum number of recursive calls. A natural recursive DOM walk dies on any large page (Wikipedia, docs sites). This package's Markdown converter therefore walks the DOM with an explicit stack, keeping JS call depth at O(1). If you use kitesurf_evaluate, prefer iterative expressions.

Navigation failures arrive as Cloudflare edge status codes, not CDP errors. Page.navigate returns a normal frameId/loaderId even for a nonexistent host, and no Network.loadingFailed fires. A missing domain shows up as HTTP 530, a broken origin as 520, leaving a ~16-character placeholder document. Trusting Page.navigate hands an agent a blank page and calls it success — so this package classifies outcomes from the Network domain and throws when a >=400 status comes with an empty document, while still returning real error pages (with status) that have readable content.

Capability flags (verified):

✅ canvas2d, WebAssembly, shadow DOM, localStorage, cookies, fetch/XHR, IntersectionObserver, MutationObserver

WebGL, ServiceWorker, video/audio playback, real TLS-fingerprint bot-challenge handshakes, long-lived authenticated sessions

For those, use Browser Run's default Chromium browser instead.

Performance trade (Cloudflare's own figures): Kitesurf uses 3–7× less CPU and memory than warm Chromium, but is 1.7–1.8× slower in wall time. That win is on Cloudflare's bill for bursty cloud agent workloads — it saves nothing on your own hardware. If you just want local browser automation and already have Chrome, local Playwright is faster and does WebGL and video.

Zero dependencies

package.json has an empty dependencies block, including for the WebSocket transport.

Node's global WebSocket (WHATWG) cannot send request headers, and the account endpoint needs Authorization: Bearer …. undici is not importable as a standalone module. So src/ws.mjs implements the RFC 6455 client directly over node:http(s) — handshake, masking, continuation fragments, 64-bit lengths, ping/pong, close — which is everything CDP needs, with header support.

Tests

npm test                        # live tests against the playground
KITESURF_SKIP_NETWORK=1 npm test   # offline only

The suite hits the real service on purpose: the interesting failures (Boa's recursion limit, pipe truncation, edge status codes) only appear against the real thing.

Requirements

Node ≥ 18. No browser, no API token, no build step.

License

MIT

-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.

  • Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TrueNix/kitesurf-bridge'

If you have feedback or need assistance with the MCP directory API, please join our Discord server