Skip to main content
Glama

browser-flow-mcp

npm CI license · Live demo

Write a browser task once in YAML. Run it from your terminal or cron, or give it to AI agents as an MCP tool.

Logging in to a portal, downloading a report, checking a price, filling the same form every week: describe the steps once and they become:

  • a command: npx @tirthlabs/browser-flow-mcp run flows/orders.yml date=2026-10-17

  • a scheduled job that posts results to Slack, n8n or Zapier: --every 1h --webhook <url>

  • a tool that Claude, Cursor, VS Code or any MCP client can call, with typed inputs, JSON output and screenshots

Unlike a general "AI drives the browser" server, the agent can't wander. It can only run the flows you wrote, with the inputs you allowed. That makes it fast, repeatable and safe to hand to an agent.

Install

npm i -D @tirthlabs/browser-flow-mcp playwright
npx playwright install chromium
npx browser-flow-mcp init          # creates flows/ with working examples
npx browser-flow-mcp run flows/hn-top.yml limit=5

Related MCP server: Browserbeam MCP Server

A flow

name: export_orders
description: Download the orders CSV for a date from the supplier portal.
session: supplier-portal           # keeps cookies, so later runs skip the login
inputs:
  date: { type: string, description: Date as YYYY-MM-DD }
steps:
  - goto: https://portal.example.com/orders
  - if: { visible: "input[type=password]" }
    then:
      - fill:
          "input[name=email]": ${PORTAL_EMAIL}        # from the environment, never in the file
          "input[type=password]": ${PORTAL_PASSWORD}
      - click: button[type=submit]
      - wait: { url: /orders }
  - fill: { "#date": "{{date}}" }
  - click: text=Apply
  - download: { click: "text=Export CSV", saveAs: "downloads/orders-{{date}}.csv" }
    as: file
  - extract:
      total: { selector: ".summary .total", number: true }
      rows:
        selector: table tbody tr
        fields: { id: td:nth-child(1), customer: td:nth-child(2), amount: td:nth-child(3) }

Result:

{ "file": "/home/me/flows/downloads/orders-2026-10-17.csv", "total": 1840.5, "rows": [{ "id": "A-1", "customer": "…", "amount": "…" }] }

Use it from AI agents (MCP)

Every .yml file in the folder becomes a tool. Its inputs become the tool's JSON Schema.

Claude Desktop / Cursor (claude_desktop_config.json / .cursor/mcp.json):

{
  "mcpServers": {
    "browser-flows": {
      "command": "npx",
      "args": ["-y", "@tirthlabs/browser-flow-mcp", "serve", "/absolute/path/to/flows"],
      "env": { "PORTAL_EMAIL": "me@company.com", "PORTAL_PASSWORD": "…" }
    }
  }
}

Claude Code:

claude mcp add browser-flows -- npx -y @tirthlabs/browser-flow-mcp serve ./flows
  • Edit or add flows while the server runs. Clients are told the tool list changed.

  • One browser is shared between calls, and each call gets a clean context.

  • When a step fails, the agent gets the step, the error, the page URL and a screenshot, so it can explain what went wrong. run saves that screenshot as a PNG and puts its path in the result.

  • Cancelling a call from the client stops the flow before its next step.

  • Session files (~/.browser-flow/sessions) hold cookies, so they are created readable only by you.

  • screenshot: {} with no path returns the image to the agent.

  • readOnly: true marks a tool as read-only for clients that ask before running anything that changes data.

Steps

Step

Example

goto

goto: https://site.com/{{path}}. Fails on HTTP 4xx/5xx unless { url: …, allowHttpErrors: true }. Sets {{status}}

click / dblclick / hover

click: "text=Sign in" or { selector: ".item", nth: 2 }

fill

fill: { "#email": "{{email}}", "#name": "Tirth" }

type

type: { selector: "#search", text: "{{q}}", delay: 50 }

press

press: Enter or { selector: "#q", key: Enter }

select / check / uncheck

select: { selector: "#country", value: AE }

upload

upload: { selector: "input[type=file]", files: [invoice.pdf] }

scroll

scroll: bottom or a selector

wait

wait: 1000, wait: ".loaded", wait: { url: /done }, wait: { text: Saved }

extract

extract: { price: { selector: .price, number: true }, links: { selector: a, attr: href, all: true }, title: { title: true }, url: { url: true } }. Options: attr, html, value, number, all, fields, title, url

eval

eval: document.title with as: title. ${…} here is plain JavaScript, not an environment variable

screenshot / pdf

screenshot: { path: out/page.png, fullPage: true }

download

download: { click: "#export", saveAs: out/file.csv }

assert

assert: { visible: ".dashboard" }, { url: /home }, { textContains: Paid, selector: .status }

if

if: { exists: ".cookie-banner" } with then: / else:

repeat

repeat: { max: 10, while: { visible: "a.next" }, steps: [...] } (gives {{index}})

set / log

set: { page: 1 }

Any step can have optional: true (skip if it fails), timeout: 5000 and as: name.

{{name}} is an input or variable, and ${NAME} is an environment variable (write $${NAME} for a literal ${NAME}).

Flow options: browser (chromium, firefox or webkit), channel (chrome to use the installed Chrome), headless, viewport, userAgent, locale, timeout, session, vars, output (shape the result with {{vars}}).

Commands

browser-flow-mcp init [dir]               example flows
browser-flow-mcp run <flow.yml> [k=v…]    --headed --out result.json --every 1h --webhook <url>
browser-flow-mcp serve <dir|file>         MCP server over stdio
browser-flow-mcp list <dir|file>          tools and their inputs
browser-flow-mcp check <dir|file>         validate (good for CI)
browser-flow-mcp steps                    step reference

From code

import { loadFlow, runFlow } from '@tirthlabs/browser-flow-mcp';
const res = await runFlow(await loadFlow('flows/orders.yml'), { inputs: { date: '2026-10-17' } });
if (res.ok) console.log(res.output); else console.error(res.failedStep, res.error);

Options for runFlow: inputs, headless, pool (share one browser between runs with browserPool()), onLog(message) for live step logs, images: true to collect every screenshot as base64, and onContext(context) to adjust the Playwright context first (block requests, add cookies, start a trace).

License

MIT © Tirth Parikh, tirthparikh.com

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Chrome extension + MCP server. Lets coding agents (Claude Code, Codex CLI) drive your real Chrome — sessions intact, 2FA stays with the user. 26 browser tools: form fill on React/CodeMirror/Monaco, privileged fetch that bypasses page CSP, authenticated downloads, in-extension docx parsing. Battle-tested by 400+ hours of real agentic browser work before public v0.9 release.
    19 npm
    3
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables real browser automation as tools in Cursor, Claude Desktop, Windsurf, and any MCP-compatible client, allowing AI agents to interact with web pages through natural language.
    2 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Headless browser automation for LLM agents via REST API or MCP tools. Enables navigating pages, reading structured content, clicking elements, filling forms, and executing JavaScript.
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables local Chrome control for AI clients over MCP stdio, HTTP, or CLI, exposing 20 tools to extract page text, number and click elements, type text, scroll, manage tabs, capture screenshots, and bind uploaded files to file inputs. Operations run entirely on the local machine with origin allowlists and refusal of untrusted URLs, without calling a cloud model or consuming model tokens.
    28 npm
    MIT