openmcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@openmcpgo to example.com and take a screenshot"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
openmcp ๐
The Ultimate MCP Server for AI Agents
Supercharge your AI coding assistants with powerful web automation
๐ฏ What is openmcp?
openmcp is a production-ready MCP (Model Context Protocol) server that gives AI agents superpowers for web automation. Whether you're using Cursor, Claude, ChatGPT, or any other AI assistant, openmcp provides secure, scalable access to browser automation capabilities.
๐ Perfect for AI-Powered Development
๐ฅ Cursor Integration - Let Cursor automate web testing and scraping
๐ค Claude Desktop - Give Claude the ability to browse and interact with websites
๐ป VS Code Extensions - Power up your AI coding assistants
๐ง Custom AI Agents - Build agents that can navigate the web
๐ Data Collection - Automate web scraping and form filling
๐งช Testing Automation - Let AI write and run web tests
Related MCP server: blowsh-mcp
โจ Key Features
๐ Enterprise Ready
API Key Authentication - Secure access control
Localhost Development Mode - No auth required from localhost
Mock API Key Support - Easy testing with
openmcp-localhost-authPermission Management - Fine-grained service access
Rate Limiting - Prevent abuse and overuse
Audit Logging - Track all AI agent activities
๐ Universal Access
Official MCP Protocol - FastMCP with streamable-http & SSE transports
Legacy REST API - Works with any language/tool
Native MCP Clients - Direct support for official MCP clients
Real-time Streaming - Server-Sent Events for live updates
Remote Access - Agents connect from anywhere
Load Balancer Ready - Scale horizontally
๐ง Powerful Automation
Browser Sessions - Manage multiple browser instances
Element Interaction - Click, type, scroll, navigate
Screenshot Capture - Visual feedback for AI agents
Form Automation - Fill and submit complex forms
๐ Developer Friendly
5-Minute Setup - Get running instantly
Docker Support - Deploy anywhere
Rich Documentation - Comprehensive guides
Multiple Examples - Copy-paste ready code
๐ Quick Start (5 Minutes)
1. Install openmcp
# Clone and install
git clone https://github.com/openmcp-pro/openmcp.git
cd openmcp
pip install -e .2. Initialize and Start
# Create configuration and get your API key
openmcp init-config
# Start the server (FastMCP with streamable-http transport)
openmcp serve๐ That's it! Your OpenMCP FastMCP server is running on http://localhost:8000
๐ก Transport Options
Choose your transport protocol:
# Default: Official MCP with streamable-http transport (recommended)
openmcp serve
# Official MCP with SSE transport (real-time streaming)
openmcp serve --transport sse
# Legacy REST API (for custom integrations)
openmcp serve --transport rest --port 90003. Use the Super Simple Interface
import asyncio
import openmcp
async def main():
# Super simple - just one line!
mcp = openmcp.MCP("browseruse")
# Create a browser session
session = await mcp.create_session()
# Navigate and take screenshot
await session.navigate("https://example.com")
await session.screenshot("example.png")
# Clean up
await session.close()
# Or even simpler with context manager:
async def even_simpler():
async with openmcp.browser() as browser:
await browser.navigate("https://example.com")
await browser.click("#some-button")
await browser.screenshot("result.png")
# One-liner screenshot
async def one_liner():
await openmcp.screenshot("https://example.com", "quick.png")
asyncio.run(main())๐ Authentication & Development Mode
openmcp supports multiple authentication modes to make development easy while keeping production secure:
๐ Development Mode (Localhost)
No API key required when connecting from localhost! Perfect for development:
# From localhost - no auth needed!
import httpx
async def localhost_example():
# Direct API calls without authentication
async with httpx.AsyncClient() as client:
response = await client.get("http://localhost:9000/api/v1/services")
print(response.json())
# Or with the simple interface
import openmcp
mcp = openmcp.MCP("browseruse") # No API key needed from localhost!๐งช Mock API Key for Testing
Use the built-in mock API key openmcp-localhost-auth for testing from any location:
# Works from anywhere - great for CI/CD
import openmcp
# Using mock API key
mcp = openmcp.MCP("browseruse", api_key="openmcp-localhost-auth")
# Or direct HTTP with mock key
headers = {"Authorization": "Bearer openmcp-localhost-auth"}๐ Production API Keys
For production use, generate secure API keys:
# Generate production API key
openmcp init-config # Shows your API key
# Use in production
export OPENMCP_API_KEY="bmcp_your-production-key-here"๐ ๏ธ Configuration Options
Control authentication behavior in your config:
# config.yaml
auth:
allow_localhost: true # Enable localhost bypass (default: true)
mock_api_key: "openmcp-localhost-auth" # Mock key for testing
secret_key: "your-secret-key" # JWT secret๐ฏ Which Mode to Use?
๐ Local Development: No API key needed - just run and go!
๐งช Testing/CI: Use
openmcp-localhost-authmock key๐ Production: Generate and use secure
bmcp_API keys๐ Restricted: Disable localhost mode in production configs
โก Super Simple Interface
NEW! openmcp now has an incredibly simple Python interface:
import openmcp
# Just one line to get started!
mcp = openmcp.MCP("browseruse")๐ฏ Three Ways to Use openmcp
1. Session-based (Full Control)
mcp = openmcp.MCP("browseruse")
session = await mcp.create_session()
await session.navigate("https://example.com")
await session.click("#button")
await session.screenshot("result.png")
await session.close()2. Context Manager (Recommended)
async with openmcp.browser() as browser:
await browser.navigate("https://example.com")
await browser.type("#search", "openmcp")
await browser.click("#submit")
await browser.screenshot("search_results.png")
# Automatically cleaned up!3. One-Liners (Super Quick)
# Quick screenshot
await openmcp.screenshot("https://example.com", "page.png")
# Quick form test
await openmcp.test_form("https://example.com/contact", {
"#name": "John Doe",
"#email": "john@example.com"
})๐ค Perfect for AI Assistants
Ask Cursor or Claude:
"Create a script using openmcp.browser() to test our login form"
"Use openmcp to take screenshots of all our product pages"
"Write a openmcp script that fills out contact forms automatically"
They'll generate clean, simple code using the new interface!
๐ฅ Using openmcp with Cursor
Method 1: Super Simple Interface (Recommended)
Just add this to your project and ask Cursor to use it:
import openmcp
# Cursor will generate code like this:
async def test_website():
async with openmcp.browser() as browser:
await browser.navigate("https://yoursite.com")
await browser.click("#login-button")
await browser.type("#email", "test@example.com")
await browser.screenshot("login_page.png")Method 2: Direct HTTP Integration
Add this to your Cursor project to give your AI assistant web automation powers:
# cursor_openmcp.py - Add this to your project
import httpx
import asyncio
from typing import Dict, Any, Optional
class CursorWebAutomation:
"""Web automation helper for Cursor AI assistant."""
def __init__(self, api_key: str = "", base_url: str = "http://localhost:9000"):
self.api_key = api_key
self.base_url = base_url
# Only add auth header if API key is provided (localhost mode doesn't need it)
self.headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
self.session_id: Optional[str] = None
async def start_browser(self, headless: bool = True) -> str:
"""Start a browser session for automation."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "create_session",
"arguments": {"headless": headless, "timeout": 30}
}
)
result = response.json()
if result["success"]:
self.session_id = result["result"]["session_id"]
return self.session_id
raise Exception(f"Failed to start browser: {result}")
async def navigate(self, url: str) -> Dict[str, Any]:
"""Navigate to a URL."""
if not self.session_id:
await self.start_browser()
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "navigate",
"arguments": {"url": url},
"session_id": self.session_id
}
)
return response.json()
async def find_and_click(self, selector: str) -> Dict[str, Any]:
"""Find and click an element."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "click_element",
"arguments": {"selector": selector},
"session_id": self.session_id
}
)
return response.json()
async def type_text(self, selector: str, text: str) -> Dict[str, Any]:
"""Type text into an input field."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "type_text",
"arguments": {"selector": selector, "text": text},
"session_id": self.session_id
}
)
return response.json()
async def screenshot(self, save_path: str = "screenshot.png") -> str:
"""Take a screenshot and save it."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/services/browseruse/call",
headers=self.headers,
json={
"tool_name": "take_screenshot",
"arguments": {},
"session_id": self.session_id
}
)
result = response.json()
if result["success"]:
import base64
screenshot_data = base64.b64decode(result["result"]["screenshot"])
with open(save_path, "wb") as f:
f.write(screenshot_data)
return save_path
raise Exception("Screenshot failed")
# Usage example for Cursor
async def demo_for_cursor():
"""Demo function that Cursor can call."""
# No API key needed from localhost! For remote use: api_key="openmcp-localhost-auth"
automation = CursorWebAutomation() # Empty for localhost, or use mock key
# Navigate to a website
await automation.navigate("https://example.com")
# Take a screenshot
screenshot_path = await automation.screenshot("example_page.png")
print(f"Screenshot saved: {screenshot_path}")
# You can now ask Cursor to:
# - Automate form filling
# - Scrape website data
# - Test web applications
# - Generate web automation scripts
# Run this in Cursor's terminal
if __name__ == "__main__":
asyncio.run(demo_for_cursor())Method 2: Official MCP Integration (Recommended)
For native MCP support in Cursor, add this configuration:
// .cursor/mcp_config.json
{
"mcpServers": {
"openmcp": {
"command": "openmcp",
"args": ["serve", "--transport", "sse"],
"env": {}
}
}
}Note: Uses the new FastMCP SSE transport for real-time streaming support.
๐ฏ Cursor Use Cases
Ask Cursor to:
"Create a script that logs into this website and downloads all PDFs"
"Write a test that fills out this contact form and verifies submission"
"Build a scraper that extracts product prices from this e-commerce site"
"Automate taking screenshots of our website on different screen sizes"
๐ค Using openmcp with Claude Desktop
Setup Claude Desktop Integration
Install Claude Desktop from Anthropic
Configure MCP Server in Claude's settings:
// Claude Desktop MCP Configuration
{
"mcpServers": {
"openmcp-browser": {
"command": "openmcp",
"args": ["serve", "--transport", "sse"]
}
}
}Note: Uses FastMCP with SSE transport for optimal Claude Desktop integration.
Restart Claude Desktop - openmcp tools will appear automatically
๐ฏ Claude Desktop Use Cases
Ask Claude:
"Please navigate to GitHub and take a screenshot of the trending repositories"
"Fill out this job application form with my resume details"
"Check if my website loads correctly and take screenshots"
"Find all the contact forms on this website and test them"
Example Claude Conversation
You: "Please help me test the contact form on https://example.com"
Claude: I'll help you test the contact form. Let me:
1. Create a browser session
2. Navigate to the website
3. Find the contact form
4. Fill it out with test data
5. Take screenshots of the process
[Claude automatically uses openmcp tools to complete the task]๐ Transport Protocols
OpenMCP supports three transport protocols to meet different integration needs:
๐ฏ Streamable-HTTP (Default & Recommended)
# Start with streamable-http transport
openmcp serve
# or explicitly:
openmcp serve --transport streamable-httpโ Best for:
Official MCP clients (Cursor, Claude Desktop, custom clients)
Production deployments - Reliable HTTP-based communication
Load balancers - Standard HTTP protocol
Firewall-friendly - Uses standard HTTP ports
๐ Connect with:
from mcp.client.streamable_http import streamablehttp_client
from mcp.client.session import ClientSession
async with streamablehttp_client('http://localhost:8000/') as (read_stream, write_stream, session_id):
session = ClientSession(read_stream, write_stream)
async with session:
await session.initialize()
tools = await session.list_tools()โก Server-Sent Events (SSE)
# Start with SSE transport
openmcp serve --transport sseโ Best for:
Real-time applications - Live progress updates
Streaming operations - Long-running tasks with progress
Web dashboards - Browser-based monitoring
Development & debugging - Live operation visibility
๐ Connect with:
from mcp.client.sse import sse_client
from mcp.client.session import ClientSession
async with sse_client('http://localhost:8000/sse') as (read_stream, write_stream):
session = ClientSession(read_stream, write_stream)
async with session:
await session.initialize()
tools = await session.list_tools()๐ง REST API (Legacy)
# Start with REST transport
openmcp serve --transport rest --port 9000โ Best for:
Custom integrations - Direct HTTP API access
Any programming language - Standard REST endpoints
Existing applications - Drop-in replacement for web automation
Quick prototyping - Simple curl commands
๐ Connect with:
import httpx
# Direct REST API calls
async with httpx.AsyncClient() as client:
response = await client.get("http://localhost:9000/api/v1/services")
services = response.json()
# Create browser session
response = await client.post(
"http://localhost:9000/api/v1/services/browseruse/call",
json={"tool_name": "create_session", "arguments": {"headless": True}}
)๐๏ธ Transport Comparison
Feature | Streamable-HTTP | SSE | REST API |
MCP Protocol | โ Official | โ Official | โ Custom |
Official Clients | โ Full support | โ Full support | โ Not supported |
Real-time Updates | โ Request/Response | โ Live streaming | โ Request/Response |
HTTP Compatibility | โ Standard HTTP | โ Standard HTTP | โ Standard HTTP |
Custom Integrations | โ ๏ธ MCP required | โ ๏ธ MCP required | โ Any language |
Production Ready | โ Recommended | โ Good | โ Legacy support |
๐ก Choosing the Right Transport
๐ฏ Starting fresh? Use streamable-http (default)
โก Need real-time? Use SSE transport
๐ง Custom integration? Use REST API transport
๐ค Official MCP clients? Use streamable-http or SSE
๐ง Available Tools
Tool | Description | Example Use Case |
create_session | Start new browser | "Start a browser for testing" |
navigate | Go to URL | "Open the login page" |
find_elements | Locate page elements | "Find all the buttons on this page" |
click_element | Click buttons/links | "Click the submit button" |
type_text | Fill input fields | "Enter my email address" |
take_screenshot | Capture page image | "Take a screenshot for documentation" |
close_session | End browser session | "Clean up when done" |
๐ Real-World Examples
Example 1: Automated Testing with Cursor
# test_automation.py - Generated by Cursor with openmcp
import asyncio
from cursor_openmcp import CursorWebAutomation
async def test_login_flow():
"""Test user login functionality."""
automation = CursorWebAutomation() # No auth needed from localhost!
# Navigate to login page
await automation.navigate("https://yourapp.com/login")
# Fill login form
await automation.type_text("#email", "test@example.com")
await automation.type_text("#password", "testpass123")
# Submit form
await automation.find_and_click("#login-button")
# Verify success
await asyncio.sleep(2) # Wait for redirect
screenshot = await automation.screenshot("login_success.png")
print(f"Login test completed. Screenshot: {screenshot}")
# Cursor can generate and run this automatically!
asyncio.run(test_login_flow())Example 2: Data Collection with Claude
You: "Please collect all product names and prices from https://shop.example.com"
Claude: I'll help you scrape the product data. Let me:
1. Navigate to the shop website
2. Find all product elements
3. Extract names and prices
4. Save the data to a CSV file
[Uses openmcp tools automatically]
Here's the collected data:
- Product A: $29.99
- Product B: $39.99
- Product C: $19.99
Data saved to products.csvExample 3: Form Automation
# Generated by AI assistant using openmcp
async def automate_job_application():
automation = CursorWebAutomation() # Localhost = no auth required!
# Navigate to job application
await automation.navigate("https://company.com/careers/apply")
# Fill personal information
await automation.type_text("#first-name", "John")
await automation.type_text("#last-name", "Doe")
await automation.type_text("#email", "john@example.com")
# Upload resume (if file upload is supported)
await automation.find_and_click("#resume-upload")
# Take screenshot for verification
await automation.screenshot("application_filled.png")
print("Job application automated successfully!")๐ Advanced Configuration
Custom Service Configuration
# config.yaml
server:
host: "0.0.0.0"
port: 9000
debug: false
auth:
secret_key: "your-secret-key"
services:
- name: "browseruse"
enabled: true
config:
headless: true
timeout: 30
max_sessions: 10 # Allow more concurrent sessions
# Add more services here
- name: "future_service"
enabled: falseEnvironment Variables
# .env
OPENMCP_SECRET_KEY=your-production-secret
OPENMCP_HOST=0.0.0.0
OPENMCP_PORT=9000
OPENMCP_MAX_SESSIONS=20๐ณ Production Deployment
Docker Deployment
# Build and run
docker build -t openmcp .
docker run -p 9000:9000 -e OPENMCP_SECRET_KEY=your-secret openmcpDocker Compose
# docker-compose.yml
version: '3.8'
services:
openmcp:
build: .
ports:
- "9000:9000"
environment:
- OPENMCP_SECRET_KEY=${SECRET_KEY}
volumes:
- ./config.yaml:/app/config.yaml
restart: unless-stoppedCloud Deployment
Deploy to any cloud platform:
AWS ECS/Fargate - Container-ready
Google Cloud Run - Serverless scaling
Azure Container Instances - Easy deployment
DigitalOcean Apps - Simple setup
Railway/Render - One-click deploy
๐ Security Best Practices
API Key Management
# Generate secure API keys
openmcp create-key "production-agent" --expires 365
# Rotate keys regularly
openmcp create-key "new-key" --expires 90
# Update your applications
# Revoke old keyNetwork Security
# config.yaml - Production settings
server:
host: "127.0.0.1" # Only local access
port: 9000
auth:
allow_localhost: false # Disable localhost bypass in production
mock_api_key: "" # Disable mock key in production
# Use reverse proxy (nginx/traefik) for HTTPS
# Enable firewall rules
# Use VPN for remote access๐ Monitoring & Observability
Health Checks
# Monitor server health
curl http://localhost:9000/health
# Check service status
curl -H "Authorization: Bearer $API_KEY" \
http://localhost:9000/api/v1/services/browseruse/statusLogging
# Structured logging is built-in
import structlog
logger = structlog.get_logger()
# All API calls are automatically logged
# Browser actions are tracked
# Errors are captured with context๐ช Git Hooks
This repository includes git hooks to maintain clean commit history:
Claude Keyword Filter
Automatically removes lines containing "Claude" from commit messages to keep them professional:
# Input commit message:
"Add new feature
Claude helped with implementation
Fix authentication bug"
# Automatically filtered to:
"Add new feature
Fix authentication bug"Features:
๐ Auto-Detection - Finds "Claude" keyword (case-insensitive)
๐งน Smart Filtering - Removes only problematic lines
๐ Safe Fallback - Never leaves empty commit messages
๐ Visual Feedback - Shows what was filtered
See GIT_HOOKS.md for complete documentation.
๐ก Server-Sent Events (SSE) Streaming
OpenMCP supports real-time streaming of long-running operations using Server-Sent Events:
๐ Real-Time Browser Automation
Stream browser operations with live progress updates:
import asyncio
import httpx
import json
async def stream_browser_session():
async with httpx.AsyncClient() as client:
async with client.stream(
"POST",
"http://localhost:9000/api/v1/services/browseruse/stream",
json={
"tool_name": "create_session",
"arguments": {"headless": True}
}
) as response:
async for line in response.aiter_lines():
if line.startswith("data: "):
event = json.loads(line[6:])
print(f"{event['type']}: {event['message']}")
if event['type'] == 'progress':
print(f"Progress: {event.get('progress', 0)}%")
asyncio.run(stream_browser_session())๐ SSE Event Types
start- Operation beginsprogress- Progress updates with percentagesuccess- Operation completed successfullyerror- Operation failedcomplete- Final completion event
๐ Web Dashboard
Open examples/sse_web_demo.html in your browser for a live web interface:
โ Real-time progress bars
โ Live operation logs
โ Interactive controls
โ No API key needed (localhost)
โก Quick SSE Examples
# Python streaming examples
python examples/simple_sse_demo.py
python examples/sse_streaming_example.py
# Web interface
open examples/sse_web_demo.html๐ง SSE Endpoints
All MCP services support streaming via /stream endpoints:
POST /api/v1/services/{service_name}/stream
Content-Type: application/json
{
"tool_name": "navigate",
"arguments": {"url": "https://example.com"},
"session_id": "session-id-here"
}Perfect for:
Long-running operations (web crawling, form automation)
Real-time dashboards (monitoring browser sessions)
Progress tracking (screenshot capture, navigation)
Live debugging (step-by-step operation visibility)
๐ค Contributing & Extending
Adding New Services
# my_custom_service.py
from openmcp.services.base import BaseMCPService
class MyCustomService(BaseMCPService):
def get_tools(self):
return [{
"name": "my_tool",
"description": "My custom automation tool",
"parameters": {
"type": "object",
"properties": {
"input": {"type": "string"}
}
}
}]
async def call_tool(self, tool_name, arguments, session_id=None):
if tool_name == "my_tool":
# Implement your custom logic
return {"result": f"Processed: {arguments['input']}"}Community Extensions
Planned Services:
๐ง Email Automation - Send/read emails
๐ฑ Mobile Testing - Appium integration
๐๏ธ Database Operations - SQL query execution
๐ API Testing - REST/GraphQL testing
๐ SEO Analysis - Website optimization
๐ Troubleshooting
Common Issues
Server won't start?
# Check port availability
netstat -an | grep 9000
# Try different port
openmcp serve --port 8001Browser automation fails?
# Install Chrome/Chromium
# Ubuntu/Debian:
sudo apt-get install chromium-browser
# macOS:
brew install --cask google-chrome
# Windows: Download from GoogleAPI authentication errors?
# From localhost? No auth needed!
curl http://localhost:9000/api/v1/services
# Use mock key for testing
curl -H "Authorization: Bearer openmcp-localhost-auth" \
http://localhost:9000/api/v1/services
# Regenerate API key for production
openmcp init-config --force
# Check key format (should start with 'bmcp_')
echo $API_KEYCursor/Claude not connecting?
# Verify MCP server starts with correct transport
openmcp serve --transport sse
# Check MCP configuration syntax in your client
# Restart Cursor/Claude Desktop after configuration changes
# Test official MCP client connection
python -c "
from mcp.client.sse import sse_client
import asyncio
async def test():
async with sse_client('http://localhost:8000/sse') as streams:
print('โ
MCP connection successful')
asyncio.run(test())
"๐ Documentation & Resources
๐ REST API Documentation - Interactive OpenAPI docs (when using
--transport rest)๐ฏ MCP Protocol Reference - Official MCP specification
๐ฏ MCP Examples Guide - Comprehensive usage examples
โก Quick Start Guide - 5-minute setup
๐ง Configuration Reference - All settings explained
๐ Troubleshooting Guide - Common issues & solutions
๐ Community & Support
๐ Official Website - Documentation and resources
๐ฌ GitHub Discussions - Community Q&A
๐ Issue Tracker - Bug reports & features
๐ง Email Support - Direct help
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
Built with love using:
FastAPI - Modern Python web framework
Selenium - Web browser automation
Pydantic - Data validation
Typer - CLI interface
Structlog - Structured logging
๐ Ready to supercharge your AI agents with web automation?
Get Started Now โข View Examples โข Join Community โข Documentation
Made with โค๏ธ for the AI development community
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/openmcp-pro/openmcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server