Skip to main content
Glama
README.md
<img src="assets/icon.svg" width="80" alt="weblab icon">

# weblab

weblab is an MCP server that drives real browsers, so AI agents can test and explore web apps. An agent opens named sessions (each a browser of its own pointing at an address), runs steps on them, and reads back what happened as text and screenshots.

## Install

```sh
curl -fsSL https://raw.githubusercontent.com/dittofleet/weblab/main/install.sh | sh
```

This puts one binary at `~/.local/bin/weblab` (set `WEBLAB_INSTALL_DIR` to change that). weblab runs on macOS, on Apple silicon and Intel, and drives a browser already on the machine: Google Chrome by default, or another Chromium browser.

To update, run `weblab update`. A running weblab looks for a newer release once a day, and says so in the reply to `new` when there is one.

## Register it with an MCP client

weblab speaks MCP over stdio, so the client starts it:

```sh
claude mcp add weblab -- weblab
codex mcp add weblab -- weblab
```

In a client's JSON config, the server entry is `{ "command": "weblab" }`. Sessions last as long as that weblab process does: when the client goes, every session ends, and a server weblab started for them stops unless another weblab is still using it.

## The tools

| Tool | What it does |
| --- | --- |
| `new` | Opens a session: a browser of its own, with a name, pointing at an address. Runs the `start` command it is given if nothing answers there. |
| `run` | Runs steps on a session, in order, stopping at the first that fails. Replies with each step's outcome, what it handed back, and its screenshots. |
| `end` | Ends one session, or all of them. Writes a video still recording and traces, and stops a server nobody else is using. |
| `list` | The sessions that are open, where each one is, and whether steps are running on it. |
| `docs` | The reference pages below, readable from inside the client, whole or a section at a time: `{ "section": "mock" }` is one step's options. They are also offered as MCP resources (`weblab://docs/<page>`). |

## An example

`new`

```json
{ "address": 5173, "start": "pnpm vite --port 5173", "path": "/settings" }
```

```text
session main  at http://localhost:5173 (server started by weblab: pnpm vite --port 5173)
files $TMPDIR/weblab/shop-20261003-101600
started the server at http://localhost:5173 (pnpm vite --port 5173 in ~/code/shop); it stops when the last session on it ends
ok    1 goto (1840ms)
url   http://localhost:5173/settings
title Settings

console since the last reply:
  [console.log] app mounted (http://localhost:5173/src/main.tsx)
```

`run`

```json
{
  "steps": [
    { "click": { "role": "button", "name": "Appearance" } },
    { "click": { "label": "Dark" } },
    { "expect": { "js": "document.documentElement.classList.contains('dark')" } },
    { "js": "localStorage.getItem('theme')" },
    { "shot": "appearance" }
  ]
}
```

```text
ok    1 click (41ms)
ok    2 click (37ms)
ok    3 expect (12ms)
ok    4 js (3ms)
"dark"
ok    5 shot (95ms)
shot  $TMPDIR/weblab/shop-20261003-101600/shots/main-appearance.png
```

The screenshot also comes back as an image in the same reply. A step that fails is shown as `FAIL  3 expect: ...` with a screenshot of the page at that moment, and the session stays open for the next call.

## What it can do

- Start the app with the command it is given when nothing answers at its address, share it among every session pointing there, and stop it when the last one ends. A server it didn't start is used as it is and left running. It never guesses how a project is run.
- Run any number of sessions at once: two users, copies of an app on several ports, Chrome, Edge, WebKit and Firefox side by side.
- Join a browser or Electron app that is already running, and leave it as it was found. Run code in an Electron app's main process too.
- Read the page as an accessibility tree with refs to act on, as text, or as HTML.
- Act and check: click, type, fill, drag, upload, and `expect` waits for text, elements, URLs, requests, console messages or any JavaScript.
- Shape what the page sees: fake API responses, colour scheme, viewport, locale, a saved sign-in, a slow network.
- See a React app the way React DevTools does: its components, where each one's code is, and what rendered and why. Change props, state and boundaries on the spot.
- Run JavaScript in the page, Playwright code against it, or raw Chrome DevTools Protocol commands, for anything the built-in steps don't cover.
- Keep screenshots, compare one with an earlier one, capture native menus from the real screen, record video and Playwright traces, and log the console and network.

## Documentation

| Page | What's in it |
| --- | --- |
| [Tools](docs/tools.md) | Every argument of `new`, `run`, `end`, `list` and `docs`, what each reply holds, servers, attaching, long runs, and where files go. |
| [Steps](docs/steps.md) | Every step and its options, targeting elements, refs, `expect`, `include` and placeholders. |
| [Sessions](docs/sessions.md) | More than one session: two users, copies of an app, running browsers and Electron apps, other engines, saved sign-ins. |
| [Code](docs/code.md) | `js`, `css`, `playwright`, `cdp` and `electron`, and step files written as code. |
| [Recipes](docs/recipes.md) | Short answers to common tasks, as the steps to run. |

## Development

```sh
bun install
bun test              # end-to-end tests, in the installed Chrome
bun run build         # dist/weblab, a single binary
```

`src/main.ts` is the entry point and `src/mcp.ts` defines the tools. Each step lives in `src/steps/`, grouped as [Steps](docs/steps.md) lists them. A release is a `vX.Y.Z` tag pushed on a commit on `main`, and nothing else: the release workflow builds the binaries, stamps the tag in as their version, and publishes them. No file in the repository holds the version, so there is nothing to bump.

The API is designed for how it reads now, not for what an earlier version took. Agents learn it from the tools' own descriptions and the docs each time they connect, so nothing depends on an old name the way a script would. When a clearer name or shape turns up, change it.

Maintenance

ActivityMaintained
ResponsivenessNo issues