Browser automation and content extraction as MCP (Model Context Protocol) tools. Use Playwright to navigate, extract structured content, click elements, and run multi-step workflows—with local caching and auto-summarization.
AutoFlow MCP is an MCP server that exposes browser automation as tools. LLM applications (Claude, Cursor, etc.) can call these tools to:
- Open URLs and read page structure
- Extract main content, tables, forms, and links
- Click elements by selector or visible text
- Run ordered sequences of navigations and clicks
- Cache and summarize pages for faster reuse
All tools are invoked over the Model Context Protocol via stdio, so any MCP-capable client can use them.
| Feature | Description |
|---|---|
| MCP tools | Six tools: navigate, extract_content, click_element, run_workflow, cache_list, plugin_info |
| Playwright | Headless Chromium for navigation, DOM access, and interaction |
| Smart extraction | Main content (article, main, .content, etc.), tables (headers + rows), forms (action, method, inputs), links, and meta tags |
| Auto-summarization | Short text summaries for extracted pages, suitable for prompts or previews |
| Local cache | Visited pages stored under data/page-cache with configurable TTL; extract_content and run_workflow read and write the cache |
| Plugins | Add tools by implementing the plugin contract and registering in src/plugins/index.ts |
- Node.js 18 or higher
- Playwright Chromium: installed via
npx playwright install chromium
git clone <repository-url>
cd AutoFlow-MCP # or your project directory
npm install
npx playwright install chromium
npm run buildStart the MCP server on stdio:
npm run mcpOr run the built entrypoint directly:
node dist/mcp/stdio.jsAfter building, you can also use the autflow-mcp binary:
npx autflow-mcpPoint your MCP client at the server command. Examples:
In claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"autflow-mcp": {
"command": "node",
"args": ["/path/to/AutoFlow-MCP/dist/mcp/stdio.js"]
}
}
}Or, if the project is on your PATH and built:
{
"mcpServers": {
"autflow-mcp": {
"command": "npx",
"args": ["autflow-mcp"]
}
}
}In Cursor MCP settings, add a server with:
- Command:
node - Args:
["/absolute/path/to/AutoFlow-MCP/dist/mcp/stdio.js"]
Replace the path with your project root. The server must be built (npm run build) before use.
Opens a URL in a headless browser and returns the final URL and page title.
| Argument | Type | Default | Description |
|---|---|---|---|
url |
string (URL) | required | Target URL to open |
waitUntil |
"load" | "domcontentloaded" | "networkidle" |
"domcontentloaded" |
When to consider navigation complete |
Example: { "url": "https://example.com", "waitUntil": "networkidle" }
Fetches a URL, extracts structured content (main blocks, tables, forms, links, meta), and optionally uses the local cache and adds a text summary.
| Argument | Type | Default | Description |
|---|---|---|---|
url |
string (URL) | required | URL to extract from |
useCache |
boolean | true |
Use cached result when valid |
cacheMaxAgeMs |
number | 3600000 (1h) |
Max age for cached entries (ms) |
includeSummary |
boolean | true |
Include a short text summary in the result |
Output: JSON with url, title, main, tables, forms, links, meta, extractedAt, and optionally summary and cached: true|false.
Navigates to a URL, then clicks an element by CSS selector or by visible text. Returns the resulting URL and title.
| Argument | Type | Default | Description |
|---|---|---|---|
url |
string (URL) | required | Page URL to open first |
selector |
string | — | CSS selector (e.g. button.primary, #submit) |
text |
string | — | Visible text to match (first match is clicked); provide selector or text |
waitAfterMs |
number | 500 |
Milliseconds to wait after the click |
Runs a sequence of navigate and click steps, then optionally extracts and summarizes the final page. Results are cached.
| Argument | Type | Default | Description |
|---|---|---|---|
steps |
array | required | List of step objects (see below) |
extractFinal |
boolean | true |
Extract and return content from the final page |
Step object:
| Field | Type | Description |
|---|---|---|
action |
"navigate" | "click" |
What to do in this step |
url |
string (URL) | For navigate: URL to open. For click: not used |
selector |
string | For click: CSS selector |
text |
string | For click: visible text (alternative to selector) |
waitMs |
number | 500 |
Example:
{
"steps": [
{ "action": "navigate", "url": "https://example.com" },
{ "action": "click", "text": "Sign in", "waitMs": 1000 },
{ "action": "click", "selector": "#submit" }
],
"extractFinal": true
}Lists cached page entries or removes a URL from the cache.
| Argument | Type | Default | Description |
|---|---|---|---|
action |
"list" | "remove" |
"list" |
list: return cached entries; remove: delete one URL |
url |
string (URL) | — | Required when action is "remove" |
Example plugin tool that returns plugin metadata. Arguments: format ("json" | "text", default "json").
extract_content and run_workflow (when extractFinal is true) return an extraction object with:
main— Text blocks from semantic regions (article,main,.content,#content,section, etc.), orbodyif nothing else matchestables—{ headers: string[], rows: string[][] }for each tableforms—{ action?, method?, inputs: { name, type, value? }[] }for each formlinks—{ href, text }[](first 200)meta—{ description?, robots? }from<meta>tagsextractedAt— ISO timestamp
When includeSummary (or the workflow’s summary) is enabled, a summary string is added with a concise text version of the above.
- Directory:
data/page-cache/(created on first use) - Keys: Normalized URL (no fragment, normalized path and ports)
- TTL:
extract_contentusescacheMaxAgeMs(default 1 hour); older entries are ignored - Write:
extract_contentandrun_workflowwrite to the cache after a fresh fetch
Use cache_list to inspect or clear cached pages.
src/
├── core/
│ ├── browser.ts # Playwright lifecycle: launch, context, page, navigate
│ ├── cache.ts # Filesystem cache (data/page-cache)
│ ├── extraction.ts # DOM extraction: main, tables, forms, links, meta
│ └── summarizer.ts # Text summarization for extracted pages
├── mcp/
│ ├── registry.ts # Loads built-in + plugin tools, registers with MCP
│ ├── server.ts # createAndConnect(transport)
│ └── stdio.ts # STDIO entrypoint (dist/mcp/stdio.js)
├── tools/
│ ├── navigate.ts
│ ├── extract.ts
│ ├── click.ts
│ ├── workflow.ts
│ └── cache_list.ts
└── plugins/
├── index.ts # loadPlugins() — add new plugins here
└── example.ts # plugin_info example
-
Create a tool module under
src/plugins/that exports:definition:{ name, title, description, inputSchema }whereinputSchemais a Zod recordhandler: async(args) => { content: [{ type: "text", text: string }]; isError?: boolean }
-
Register it in
src/plugins/index.tsby importing the module and appending{ definition, handler }to the array returned fromloadPlugins().
See src/plugins/example.ts for a minimal plugin.
# Build once
npm run build
# Watch mode (recompile on change)
npm run dev
# Run MCP server (after build)
npm run mcpMIT — see LICENSE.