MCP Server
Run CBrowser as an MCP server for Claude Desktop integration.
Looking for Remote MCP? See Remote MCP Server for deploying CBrowser as a remote MCP server for claude.ai custom connectors. No local installation required!
What is MCP?
MCP (Model Context Protocol) is Anthropic's standard for connecting AI assistants to external tools. CBrowser implements an MCP server that gives Claude direct browser automation capabilities.
Why Use MCP?
| Without MCP | With MCP |
|---|---|
| Copy-paste commands manually | Claude executes directly |
| View results separately | Results inline in conversation |
| No context awareness | Claude sees page state |
| Manual iteration | Autonomous workflows |
Setup
1. Install CBrowser
npm install -g cbrowser
2. Configure Claude Desktop
Edit claude_desktop_config.json at the path for your OS:
| Platform | Config Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
Tip: You can also open this file via Settings > Developer > Edit Config in Claude Desktop.
Note: If the folder or file doesn't exist, create it. On Windows, use double backslashes (
\\) in paths.
Add the CBrowser MCP server:
{
"mcpServers": {
"cbrowser": {
"command": "npx",
"args": ["cbrowser", "mcp-server"]
}
}
}
3. Restart Claude Desktop
The CBrowser tools will appear in Claude's tool list.
Available Tools
Once configured, Claude can use these tools:
Navigation
| Tool | Description |
|---|---|
navigate |
Navigate to URL and screenshot |
screenshot |
Take screenshot of current page |
Interaction
| Tool | Description |
|---|---|
click |
Click element by selector |
smart_click |
AI-powered click with retry |
fill |
Fill form field |
Analysis
| Tool | Description |
|---|---|
assert |
Natural language assertion |
analyze_page |
Analyze page structure |
generate_tests |
Generate test scenarios |
extract |
Extract data from page |
Sessions
| Tool | Description |
|---|---|
save_session |
Save browser session |
load_session |
Load saved session |
Self-Healing
| Tool | Description |
|---|---|
heal_stats |
Selector cache stats |
Security
| Tool | Description |
|---|---|
security_audit |
Scan MCP tools for prompt injection patterns |
Screen Capture
| Tool | Description |
|---|---|
capture_start |
Start recording the screen to GIF/WebP/video |
capture_stop |
Stop the recording, encode the formats, return paths and a contact sheet |
capture_status |
Report the running or most recent capture |
Session Continuity
Browser tools accept an optional _browserToken. It is how one tool call reaches the page a previous call left behind.
The remote MCP servers issue a short token (cb_ plus a random suffix) and echo it in the tool response. Pass that value back on the next call and you get the same browser β same cookies, same scroll position, same running capture. Omit it and you get a blank new browser.
Three things to know about the token:
- It is good for 10 minutes from when it is issued β an absolute lifetime, not a sliding window reset by reuse β and the browser behind it is dropped after 5 minutes with no calls. Continuity ends at whichever comes first, after which the same token quietly starts a fresh browser.
- An unknown or expired token is not an error. The server quietly creates a new session, so a call that should have continued starts over on a blank page instead.
- The local stdio server (
npx cbrowser mcp-server) keeps one browser for the whole conversation and issues no tokens._browserTokenis accepted and ignored there.
Screen capture is keyed by the same token. Two tokens are two independent captures, and capture_stop only finds the capture started under the token you pass it. If a capture is running somewhere else β another token on the same server, or the CLI in another process β capture_status reports it under also_running_elsewhere rather than pretending nothing is recording.
Screen Capture Tools
capture_start, capture_stop and capture_status record PIXELS over time. They are distinct from the record command family, which records user ACTIONS for test generation; the two share no output format.
Capture runs in the background. Call capture_start, drive the page with the ordinary tools (navigate, click, fill, scroll), then call capture_stop.
capture_start
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| url | string | No | β | URL to navigate to before capturing. Omit to capture the current page. |
| fps | number | No | 10 | Target frames per second |
| duration | string | No | β | Auto-stop after this long: 5s, 2m, 1500ms. Omit for an open-ended capture stopped by capture_stop. |
| viewport | string | No | β | WIDTHxHEIGHT (e.g. 1280x720) or a preset name β mobile, tablet, desktop, desktop-lg and more; an unknown name lists them all in the error |
| region | string | No | β | Fixed region as x,y,width,height. Clamped to the viewport. |
| element | string | No | β | CSS selector to capture. Resolved to the element's bounding box once at start; the region does not follow the element if it moves. |
| padding | number | No | 0 | Padding in pixels around the element region |
| format | string | No | gif |
Comma-separated output formats: gif,webp,mp4,webm |
| quality | number | No | 80 | JPEG quality for captured frames, 1-100 |
| max_frames | number | No | 3000 | Hard cap on retained frames |
| name | string | No | β | Capture name / slug |
| out_dir | string | No | ~/.cbrowser/videos/<session>/<slug> |
Output directory |
| _browserToken | string | No | β | Browser session token from a previous tool call |
Pass region or element, not both. Starting a second capture under the same token fails with A capture is already running (<slug>). Call capture_stop before starting another.
The response confirms the recording is live:
{
"success": true,
"state": "recording",
"slug": "mcpprobe",
"out_dir": "/home/you/.cbrowser/videos/<session>/mcpprobe",
"capture_method": "cdp-screencast",
"engine": "chromium",
"note": "Capture is event-driven: a page that never repaints emits no frames, and still stretches are reported as frame_gaps rather than padded out. Interact with the page (navigate, click, scroll) to produce frames, then call capture_stop."
}
An element capture adds an element_note saying the region was resolved once and is fixed for the run. The CLI's capture start --element tracks a moving element; the MCP element parameter does not.
capture_stop and capture_status
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| _browserToken | string | No | β | Browser session token from a previous tool call |
capture_stop on a session with no capture returns {"success": false, "error": "No capture has been started on this browser session. Call capture_start first."}. capture_status on a fresh session returns state: "idle"; after a stop it returns state: "stopped" with the most recent completed capture, so a finished recording never reads as one that never happened.
Response Shape
A recording is hundreds of frames and tens of megabytes of video, and none of that can cross an MCP boundary. capture_stop returns paths plus one inlined contact sheet β an evenly spaced visual sample of the whole run β so the response is the same small size whether you recorded three seconds or ten minutes.
Real capture_stop response from a 27-frame capture:
{
"success": true,
"slug": "mcpprobe",
"manifest_path": "/home/you/.cbrowser/videos/<session>/mcpprobe/manifest.json",
"out_dir": "/home/you/.cbrowser/videos/<session>/mcpprobe",
"frames": 27,
"target_fps": 10,
"actual_fps": 10.526315789473685,
"duration_ms": 2565,
"capture_method": "cdp-screencast",
"engine": "chromium",
"output_dims": { "width": 1280, "height": 800 },
"target": { "kind": "viewport" },
"region_clamped": false,
"artifacts": { "gif": "mcpprobe.gif" },
"change_points": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26],
"change_points_total": 26,
"frame_gaps": [],
"frame_gaps_total": 0,
"console_errors": [],
"console_errors_total": 0,
"network_requests_total": 0,
"frames_dir": "/home/you/.cbrowser/videos/<session>/mcpprobe/frames",
"contact_sheet": "/home/you/.cbrowser/videos/<session>/mcpprobe/contact-sheet.jpg",
"note": "Individual frames and video artifacts are on disk, not inlined β read them by path. The contact sheet is an evenly spaced visual sample of the recording."
}
What the shape does:
- The frame array is excluded.
framesis a count andframes_dirnames the directory; the per-frame paths, crops, SSIM scores and console/network records stay inmanifest.jsonon disk. - Unbounded lists are truncated with their true totals alongside.
change_pointscaps at 200,frame_gapsat 50,console_errorsat 20 β so you can tell "3 change points" from "200 shown of 4,812" by readingchange_points_total. - Encoded video is a path.
artifactsmaps each requested format to its filename insideout_dir. A format that fails to encode appears inencode_errorswhile the formats that did encode still ship. - Only the contact sheet is inlined. It is built to whatever is left of the 150 KB response target after the JSON payload is measured, and it is skipped entirely if that leaves less than roughly 12 KB β in which case
contact_sheet_notesays why. - The budget is enforced, not assumed. Before returning, the server measures the serialized content blocks and sheds the image first, then the text, rather than emitting an over-budget response.
The remote servers (demo.cbrowser.ai, enterprise.cbrowser.ai) inline the contact sheet as an image block, because claude.ai cannot read the server's filesystem. The local stdio server returns the contact_sheet path only β open it yourself.
Example Conversations
Basic Navigation
You: "Go to github.com and take a screenshot"
Claude: Uses navigate tool
"I've navigated to GitHub. Here's what I see: [screenshot] The page shows the GitHub homepage with trending repositories and a search bar."
Form Filling
You: "Fill out the contact form on example.com/contact with my info"
Claude: Uses navigate, fill, smart_click tools
"I've filled out the contact form:
- Name: [your name]
- Email: [your email]
- Message: [your message]
Should I submit it?"
Page Analysis
You: "Analyze the login page at myapp.com/login"
Claude: Uses analyze_page tool
"Here's my analysis of the login page:
- 1 form with 3 fields (email, password, remember me)
- Login button labeled 'Sign In'
- 'Forgot Password' link present
- Social login options: Google, GitHub
- No CAPTCHA detected
I can generate test scenarios for this page if you'd like."
Test Generation
You: "Generate tests for the checkout flow"
Claude: Uses navigate, analyze_page, generate_tests tools
"I've analyzed the checkout flow and generated these test scenarios:
# Test: Guest Checkout
go to https://myapp.com/cart
click 'Proceed to Checkout'
fill email with '[email protected]'
click 'Continue as Guest'
verify url contains '/shipping'
...
Want me to run these tests?"
Capturing an Animation
You: "Record the menu animation on myapp.com as a GIF"
Claude: Uses capture_start, click, capture_stop tools
"Recorded 27 frames over 2.6s (10.5 fps actual vs 10 requested), 26 change points β the menu repainted on almost every frame.
- GIF:
~/.cbrowser/videos/<session>/menu/menu.gif - Manifest:
~/.cbrowser/videos/<session>/menu/manifest.json - Frames:
~/.cbrowser/videos/<session>/menu/frames/
Here's the contact sheet so you can see the motion without opening the GIF: [contact sheet]"
Session Persistence
MCP sessions can persist browser state:
You: "Log into my GitHub account and save the session"
Claude: Uses navigate, fill, smart_click, save_session tools
"I've logged into GitHub. Session saved as 'github-logged-in'.
In future conversations, I can load this session to skip the login step."
Later...
You: "Load my GitHub session and check my notifications"
Claude: Uses load_session, navigate, extract tools
"Loaded your GitHub session. You have 3 unread notifications:
- New PR review on repo/project
- Issue mention in org/repo
- Release published for lib/package"
Safety in MCP
Constitutional safety applies to all MCP operations:
You: "Delete all my GitHub repositories"
Claude: "I can't do that. Deleting repositories is a Red Zone action that could cause irreversible data loss.
If you're certain, you can use the --force flag, but I recommend:
- First listing what would be deleted
- Creating backups
- Confirming each deletion individually
Would you like me to list your repositories instead?"
Configuration
Environment Variables
Set in Claude Desktop config:
{
"mcpServers": {
"cbrowser": {
"command": "npx",
"args": ["cbrowser", "mcp-server"],
"env": {
"CBROWSER_HEADLESS": "true",
"CBROWSER_TIMEOUT": "60000"
}
}
}
}
Persistent Context
Keep browser open between tool calls:
{
"mcpServers": {
"cbrowser": {
"command": "npx",
"args": ["cbrowser", "mcp-server", "--persistent"]
}
}
}
Troubleshooting
Tools Not Appearing
- Check Claude Desktop config syntax (valid JSON)
- Restart Claude Desktop completely
- Check CBrowser is installed:
npx cbrowser --version
"Browser not starting"
- Install Playwright browsers:
npx playwright install chromium - Check for display issues (Linux): Set
DISPLAYenvironment variable
Timeout Errors
Increase timeout in config:
{
"env": {
"CBROWSER_TIMEOUT": "120000"
}
}
Permission Errors
If running on Linux without display:
{
"env": {
"CBROWSER_HEADLESS": "true"
}
}
Comparison to Other Browser MCPs
| Feature | CBrowser MCP | Playwright MCP | Browser-Use |
|---|---|---|---|
| Self-healing selectors | β | β | β |
| Constitutional safety | β | β | β |
| Session persistence | β | β οΈ | β οΈ |
| Persona simulation | β | β | β |
| Test generation | β | β | β |
| Natural language assertions | β | β | β |
Related
- Getting Started - Basic CBrowser setup
- Constitutional Safety - Safety in automation
- CLI Reference - All available commands
Copyright: (c) 2026 Alexa Eden.
License: MIT License
Contact: [email protected]