Are you the author? Sign in to claim
Token-efficient browser automation MCP server for AI agents. Web scraping, monitoring & testing with 12x cost savings v
An MCP (Model Context Protocol) server that exposes the full Pinchtab browser API to AI coding agents. Built with token efficiency in mind — perfect for data extraction, web scraping, and automated testing workflows.
🙏 Credits: This wrapper is built on top of the excellent Pinchtab project by Luigi Agosti and the Pinchtab team. Pinchtab is a lightweight 12MB Go binary that provides browser automation via HTTP API with accessibility-first snapshots.
When AI agents need to browse the web, efficiency matters. Pinchtab delivers 5-13x cost savings compared to traditional browser automation.
| Task | Traditional Browser | Pinchtab | Savings |
|---|---|---|---|
| Extract article text | ~10,000 tokens (full DOM) | ~800 tokens | 12.5x cheaper |
| Find interactive elements | ~10,500 tokens | ~3,600 tokens | 3x cheaper |
| 50-page monitoring task | ~$0.30 | ~$0.01 | 30x cheaper |
1. Data Extraction & Web Scraping
2. Website Change Monitoring
diff=true returns only changed elements since last snapshot3. Async Multi-Tab Operations
4. Stable Automation
e0, e1) survive CSS changescurl -fsSL https://raw.githubusercontent.com/BDuba/pinchtab-mcp-wrapper/main/install.sh | bash
Requirements: Docker, Node.js 18+, npm
Then restart your AI agent (OpenCode, Claude Code, etc.)
Open https://example.com and take a screenshot
Or use commands:
/browse https://example.com
/screenshot
Problem: Extract product prices from 100 e-commerce pages
Traditional approach:
Pinchtab approach:
// Extract structured text only
pinchtab_read_page({url: "https://store.com/product"})
// Returns clean text with prices, descriptions
Problem: Monitor competitor prices or news updates
// First visit - establish baseline
snapshot1 = pinchtab_snapshot({url: "https://competitor.com/prices"})
// Later visits - get only changes
diff = pinchtab_snapshot({
url: "https://competitor.com/prices",
diff: true
})
// Returns only modified elements (50-200 tokens vs 10,000)
Benefits:
Problem: Gather information from 10+ documentation sites simultaneously
// Open multiple tabs in parallel
tab1 = pinchtab_tab_open({url: "https://docs.api1.com"})
tab2 = pinchtab_tab_open({url: "https://docs.api2.com"})
tab3 = pinchtab_tab_open({url: "https://docs.api3.com"})
// Extract text from all tabs
text1 = pinchtab_read_page({tabId: tab1.tabId})
text2 = pinchtab_read_page({tabId: tab2.tabId})
text3 = pinchtab_read_page({tabId: tab3.tabId})
Benefits:
Problem: Automate login/checkout flows that break on website updates
Traditional selectors break:
// Brittle - breaks when CSS changes
await page.click('#login-btn') // ❌
Pinchtab stable refs:
// Stable - survives redesigns
pinchtab_action({
tabId: "...",
kind: "click",
ref: "e5" // ✅ Persistent reference
})
Built-in accessibility tree:
// Get only interactive elements
interactives = pinchtab_list_interactives()
// Returns: buttons, links, inputs with labels
| Tool | Purpose |
|---|---|
pinchtab_tab_open | Open URL in new tab |
pinchtab_read_page | Extract page text (token-efficient) |
pinchtab_list_interactives | Get clickable elements |
pinchtab_snapshot | Get accessibility tree |
pinchtab_action | Click, type, fill forms |
pinchtab_screenshot | Take JPEG screenshot |
pinchtab_evaluate | Run JavaScript |
pinchtab_download | Download files using browser session (preserves cookies, auth, stealth) |
pinchtab_upload | Upload files to file inputs (local paths, base64, or data URLs) |
pinchtab_tab_lock | Lock tab for exclusive access |
Add to ~/.config/opencode/opencode.json:
{
"\$schema": "https://opencode.ai/config.json",
"mcp": {
"pinchtab": {
"type": "local",
"command": [
"/usr/bin/node",
"~/.pinchtab-mcp-wrapper/dist/index.js"
],
"environment": {
"PINCHTAB_MODE": "external",
"PINCHTAB_URL": "http://127.0.0.1:9867",
"PINCHTAB_TOKEN": "opencode-browser-token-secure",
"MCP_TRANSPORT": "stdio",
"LOG_LEVEL": "info"
},
"enabled": true
}
},
"agent": {
"browser": {
"description": "Browser automation specialist",
"prompt": "Use pinchtab MCP tools for all web browsing tasks. Prefer text extraction over screenshots for efficiency.",
"tools": {
"pinchtab*": true,
"playwright*": false
}
}
},
"default_agent": "browser"
}
Prerequisites: Ensure Pinchtab Docker container is running:
docker ps | grep pinchtab # Check if running
docker start pinchtab # Start if stopped
Add to .mcp.json:
{
"mcpServers": {
"pinchtab": {
"command": "bash",
"args": ["~/.pinchtab-mcp-wrapper/run-mcp.sh"]
}
}
}
Claude Code Skill (Experimental): We also provide a skill file for Claude Code CLI users. See CLAUDE_CODE_SKILL.md for detailed installation and usage instructions in Spanish. You can save this file to ~/.claude/commands/pinchtab.md and use /pinchtab to access the full reference directly in your CLI.
Add to Cursor's MCP settings (Settings → Features → MCP):
{
"mcpServers": {
"pinchtab": {
"type": "stdio",
"command": "bash",
"args": ["~/.pinchtab-mcp-wrapper/run-mcp.sh"]
}
}
}
Add to ~/.config/zed/settings.json:
{
"assistant": {
"version": "2",
"enabled": true
},
"context_servers": {
"pinchtab": {
"command": "bash",
"args": ["~/.pinchtab-mcp-wrapper/run-mcp.sh"]
}
}
}
The installer now automatically detects and configures pinchtab for multiple AI agents:
~/.config/opencode/opencode.json)~/.mcp.json or ./.mcp.json)~/.config/Cursor/User/settings.json)~/.config/zed/settings.json)If a config file already exists, the installer will:
.backup.YYYYMMDD_HHMMSS)No manual editing required - just run the installer and restart your AI agent!
The install script now supports automatic mode detection and graceful fallback:
The installer automatically detects your environment and chooses the best mode:
curl -fsSL https://raw.githubusercontent.com/BDuba/pinchtab-mcp-wrapper/main/install.sh | bash
What happens:
docker modeexternal modeRecommended for most users. Requires Docker to be installed.
export PINCHTAB_MODE=docker
curl -fsSL https://raw.githubusercontent.com/BDuba/pinchtab-mcp-wrapper/main/install.sh | bash
For systems without Docker. The installer automatically downloads the Pinchtab binary for your architecture.
export PINCHTAB_MODE=external
curl -fsSL https://raw.githubusercontent.com/BDuba/pinchtab-mcp-wrapper/main/install.sh | bash
The installer automatically detects Docker in the following locations:
/opt/homebrew/bin/docker (Homebrew on Apple Silicon)/usr/local/bin/docker (Homebrew on Intel)/Applications/OrbStack.app/Contents/MacOS/../bin/docker (OrbStack)/Applications/Docker.app/Contents/Resources/bin/docker (Docker Desktop)~/.docker/bin/docker (Docker Desktop alternative)You can also manually specify the Docker path:
export DOCKER_PATH=/opt/homebrew/bin/docker
curl -fsSL https://raw.githubusercontent.com/BDuba/pinchtab-mcp-wrapper/main/install.sh | bash
# Clone
git clone https://github.com/BDuba/pinchtab-mcp-wrapper.git
cd pinchtab-mcp-wrapper
# Build
npm install && npm run build
# Build Docker image
docker build -f pinchtab.Dockerfile -t pinchtab:local .
# Create wrapper
cat > run-mcp.sh << 'EOF'
#!/bin/bash
export PINCHTAB_MODE=docker
export PINCHTAB_TOKEN=opencode-browser-token-secure
export PINCHTAB_DOCKER_IMAGE=pinchtab:local
exec node "$(dirname "$0")/dist/index.js"
EOF
chmod +x run-mcp.sh
When using delivery: "file", you can now use relative paths and auto-naming:
{
"tool": "screenshot",
"params": {
"delivery": "file"
// Auto-saved to: ~/Pictures/Screenshots/2026-02-21T12-34-56-tab-123.jpg
}
}
{
"tool": "screenshot",
"params": {
"delivery": "file",
"path": "google/homepage.jpg"
// Saved to: ~/Pictures/Screenshots/google/homepage.jpg
}
}
{
"tool": "screenshot",
"params": {
"delivery": "file",
"path": "/absolute/path/to/screenshot.png"
// Absolute paths still work as before
}
}
| Variable | Description | Default |
|---|---|---|
SCREENSHOTS_DIR | Base directory for screenshots | OS-specific (~/Pictures/Screenshots) |
SCREENSHOTS_AUTO_CREATE | Auto-create directories | true |
SCREENSHOTS_PATTERN | Filename pattern | {timestamp}-{tabId}.jpg |
# Transport (v0.5.0+)
MCP_TRANSPORT=stdio # stdio | streamable-http | sse
MCP_HTTP_PORT=3000 # HTTP server port
MCP_HTTP_HOST=0.0.0.0 # HTTP server host
MCP_AUTH_TYPE=none # none | bearer | api-key
MCP_AUTH_TOKEN=secret-token # Auth token for HTTP mode
MCP_ALLOWED_ORIGINS=* # CORS origins
# Pinchtab connection
PINCHTAB_MODE=docker # docker | external
PINCHTAB_TOKEN=secret-token # Auth token
DEFAULT_SNAPSHOT_FORMAT=compact # compact | text | json
DEFAULT_MAX_TOKENS=2500 # Token budget
SCREENSHOT_DEFAULT_DELIVERY=base64 # base64 | s3 | file
Pinchtab MCP Wrapper now supports Streamable HTTP transport for remote/cloud deployments.
Use cases for HTTP mode:
Quick start with HTTP:
# Terminal 1: Start MCP server in HTTP mode
export MCP_TRANSPORT=streamable-http
export MCP_HTTP_PORT=3000
export MCP_AUTH_TYPE=bearer
export MCP_AUTH_TOKEN=your-secret-token
npm start
# Terminal 2: Test the HTTP endpoint
curl http://localhost:3000/health
HTTP Mode Configuration:
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT | Transport type | stdio |
MCP_HTTP_PORT | HTTP server port | 3000 |
MCP_HTTP_HOST | HTTP server host | 0.0.0.0 |
MCP_HTTP_PATH | MCP endpoint path | /mcp |
MCP_AUTH_TYPE | Auth type: none, bearer, api-key | none |
MCP_AUTH_TOKEN | Auth token (required for bearer/api-key) | - |
MCP_ALLOWED_ORIGINS | CORS allowed origins (comma-separated) | * |
MCP_ENABLE_SESSIONS | Enable stateful sessions | true |
MCP_SESSION_TIMEOUT | Session timeout in seconds | 3600 |
Security best practices for HTTP mode:
MCP_AUTH_TYPE=bearer)MCP_ALLOWED_ORIGINS=https://yourdomain.com)When running in HTTP mode, the MCP server exposes:
| Endpoint | Method | Description |
|---|---|---|
http://host:port/mcp | POST/GET | Main MCP Streamable HTTP endpoint |
http://host:port/health | GET | Health check endpoint |
http://host:port/health | GET | |
http://host:port/status | GET | Status endpoint (alias for health) |
For LobeChat v2 (and other HTTP-based MCP clients):
./run-mcp-http-all.sh
# or
export MCP_TRANSPORT=streamable-http
export MCP_HTTP_HOST=0.0.0.0
export MCP_HTTP_PORT=3001
export MCP_AUTH_TYPE=none
npm start
Configure in LobeChat:
pinchtabHTTP (or Streamable HTTP)http://172.21.0.1:3001/mcp (adjust IP based on your Docker network)NoneFinding the correct IP address:
docker network inspect bridge172.17.0.1 - default Docker bridge172.21.0.1 - custom networkshost.docker.internal - Docker Desktop (Mac/Windows)Note: The run-mcp-http-all.sh script listens on 0.0.0.0 to allow connections from any Docker container.
Example MCP Client Configuration:
// MCP Client Streamable HTTP configuration
{
"mcpServers": {
"pinchtab": {
"transport": "streamable-http",
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer your-secret-token"
}
}
}
}
HTTP Headers:
| Header | Required | Description |
|---|---|---|
Authorization | If auth enabled | Bearer <token> or raw token for api-key |
Content-Type | Yes | application/json |
Mcp-Session-Id | Optional | Session ID for stateful mode |
Authentication Examples:
# Bearer token auth
curl -H "Authorization: Bearer your-secret-token" \
http://localhost:3000/mcp
# API key auth (header)
curl -H "Authorization: your-api-key" \
http://localhost:3000/mcp
# API key auth (query param)
curl "http://localhost:3000/mcp?api_key=your-api-key"
Connecting from AI Agents:
Most MCP clients support Streamable HTTP natively. Configure your AI agent with:
{
"mcp": {
"pinchtab": {
"type": "http",
"url": "http://your-server:3000/mcp",
"headers": {
"Authorization": "Bearer your-secret-token"
}
}
}
}
Scenario: You have multiple AI agents (OpenCode, LobeChat, Claude Code, Cursor, etc.) and want to use a single Pinchtab Docker container for all of them.
Problem: Each AI agent may require a different MCP transport (stdio for CLI agents, HTTP for server-based agents).
Solution: Use one Pinchtab container with multiple MCP servers:
┌─────────────────────────────────────────────────────────────┐
│ Pinchtab Docker Container │
│ (http://127.0.0.1:9867) │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ MCP Wrapper HTTP Server │
│ (http://0.0.0.0:3001/mcp) │
│ • LobeChat ───────┐ • Other HTTP clients ───┐ │
│ • Remote agents ──┘ • Cloud services ───────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ MCP Wrapper stdio Servers │
│ • OpenCode ───────┐ • Claude Code ───────┐ │
│ • Cursor ─────────┘ • Zed ───────────────┘ │
└─────────────────────────────────────────────────────────────┘
Setup Steps:
docker run -d \
--name pinchtab \
-p 127.0.0.1:9867:9867 \
-e PINCHTAB_TOKEN=opencode-browser-token-secure \
pinchtab:local
export PINCHTAB_MODE=external
export PINCHTAB_URL=http://127.0.0.1:9867
export PINCHTAB_TOKEN=opencode-browser-token-secure
export MCP_TRANSPORT=streamable-http
export MCP_HTTP_PORT=3001
export MCP_HTTP_HOST=0.0.0.0
export MCP_AUTH_TYPE=none
export MCP_ENABLE_SESSIONS=true
node dist/index.js
Configure CLI agents (OpenCode, Claude Code, Cursor, Zed) to use stdio:
~/.config/opencode/opencode.json (see OpenCode section).mcp.json (see Claude Code section)~/.config/zed/settings.json (see Zed section)Configure server-based agents (LobeChat) to use HTTP:
http://172.21.0.1:3001/mcpStreamable HTTPNoneBenefits:
Making HTTP MCP server persistent:
sudo tee /etc/systemd/system/pinchtab-mcp.service << 'EOF'
[Unit]
Description=Pinchtab MCP HTTP Server
After=network.target docker.service
[Service]
Type=simple
User=root
WorkingDirectory=/root/.pinchtab-mcp-wrapper
ExecStart=/bin/bash -c 'export PINCHTAB_MODE=external && export PINCHTAB_URL=http://127.0.0.1:9867 && export PINCHTAB_TOKEN=opencode-browser-token-secure && export MCP_TRANSPORT=streamable-http && export MCP_HTTP_PORT=3001 && export MCP_HTTP_HOST=0.0.0.0 && export MCP_AUTH_TYPE=none && export MCP_ENABLE_SESSIONS=true && node dist/index.js'
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable pinchtab-mcp
sudo systemctl start pinchtab-mcp
PINCHTAB_MODE=docker # docker | external
PINCHTAB_TOKEN=secret-token # Auth token
DEFAULT_SNAPSHOT_FORMAT=compact # compact | text | json
DEFAULT_MAX_TOKENS=2500 # Token budget
SCREENSHOT_DEFAULT_DELIVERY=base64 # base64 | s3 | file
BRIDGE_STEALTH=full # Bypass bot detection
BRIDGE_BLOCK_IMAGES=true # Faster loading
BRIDGE_NO_ANIMATIONS=true # Consistent snapshots
BRIDGE_TIMEOUT=30 # Action timeout (seconds)
| Issue | Solution |
|---|---|
| "Connection closed" | Check docker ps, verify container running |
| "MCP error -32000" | Restart AI agent completely |
| Health check timeout | docker logs pinchtab for errors |
| 401 errors | Verify PINCHTAB_TOKEN matches |
Best practices for minimizing costs:
/text for reading - 800 tokens vs 10,000 for DOMdiff=true - Only changed elements (50-200 tokens)npm install
npm run build
npm test
See CHANGELOG.md for detailed version history and changes.
Latest release: v0.6.1 (2026-03-19)
Previous release (v0.6.0):
Previous releases:
This MCP wrapper is built on Pinchtab by Luigi Agosti and contributors.
MIT License
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases
Official GitHub integration for repos, issues, PRs, and CI/CD workflows