🚀 MCProxy
MCProxy 是一个基于 MCP(模型上下文协议)的项目,为 SaladCloud 提供远程无头浏览器会话服务。该项目允许 AI 代理控制运行在地理分布式 SaladCloud 容器上的浏览器,可用于区域价格检查、地理定位内容验证以及特定位置的网页自动化等场景。
🚀 快速开始
1. 安装依赖
npm install
2. 构建项目
npm run build
3. 本地测试
使用 Docker 在本地启动浏览器服务器:
docker compose up --build
仓库中包含一个预配置好的 .mcp.json 文件,可用于与 Docker Compose 设置配合使用。若要与 Claude Code 或其他支持工作区配置的 MCP 客户端一起使用,只需在此目录下运行即可。
若要手动测试:
MCPROXY_AUTH_TOKEN=dev-secret-token node mcp-server/dist/index.js
4. 使用 MCP 检查器进行测试
MCPROXY_AUTH_TOKEN=dev-secret-token npx @modelcontextprotocol/inspector node mcp-server/dist/index.js
然后在 ws://localhost:3000 创建一个会话。
✨ 主要特性
- 多浏览器支持:每个会话可在 Chromium、Firefox 或 WebKit(Safari)之间进行选择。
- 移动设备模拟:可模拟 100 多种移动设备(如 iPhone、Pixel、iPad、Galaxy 等),具备准确的视口、用户代理和触摸支持。
- 位置感知会话:每个会话会报告其地理位置(IP、城市、州/地区、国家、时区、互联网服务提供商)。代理可以按位置引用会话(例如,“使用犹他州的会话”)。
- 隐身模式:通过 WebGL 欺骗、导航器覆盖和逼真的浏览器指纹等高级反检测技术。
- 人性化交互:点击、输入和滚动等操作可选择模拟人类行为,避免被检测为机器人。
- Cloudflare 自动等待:自动等待 Cloudflare 挑战完成。
- Cookie 持久化:保存和恢复 Cookie 以进行会话管理和身份验证。
- 逼真的用户代理:使用最新的浏览器指纹数据自动生成逼真的用户代理。
- 会话亲和性:WebSocket 连接将会话固定到特定的容器副本。
- 心跳保活:每 30 秒发送一次心跳包以保持连接(Salad 网关的空闲超时时间为 100 秒)。
- 多区域支持:连接到不同的 Salad 部署,实现地理分布式浏览。
- 版本兼容性:具备能力报告和自动版本不匹配检测功能。
- 33 个 MCP 工具:提供完整的浏览器自动化功能,包括基于坐标的点击,适用于视觉代理。
📦 安装指南
前提条件
- Docker(推荐)或 Node.js 20+
- SaladCloud 账户(用于生产部署)
AI 辅助设置
将以下提示复制并粘贴到您的 AI 代理中,以帮助您配置 mcproxy:
Help me set up mcproxy for remote browser automation.
MCP Client: [Claude Desktop / Claude Code / Cursor / Windsurf / other]
SaladCloud Endpoint: [your endpoint URL, or "none" if you need to create one]
Setup steps:
1. Check if I have Docker installed
2. If Docker is available, use the pre-built images from ghcr.io/saladtechnologies/mcproxy
3. If Docker is not available, clone and build from https://github.com/SaladTechnologies/mcproxy
4. Configure the MCP server JSON for my client
5. Generate a secure AUTH_TOKEN
6. Test by creating a browser session
Notes:
- If my endpoint is HTTP/HTTPS, convert it to WSS (wss://...)
- If I don't have an endpoint, guide me to https://portal.salad.com to create a container group
- For local testing without SaladCloud, help me run a local browser server with Docker
使用预构建的 Docker 镜像
GitHub 容器注册表上提供了两个组件的预构建 Docker 镜像。
Docker 镜像
| 组件 |
镜像 |
平台 |
| 浏览器服务器 |
ghcr.io/saladtechnologies/mcproxy/browser-server:latest |
linux/amd64 |
| MCP 服务器 |
ghcr.io/saladtechnologies/mcproxy/mcp-server:latest |
linux/amd64, linux/arm64 |
使用 Docker 运行浏览器服务器
docker run -d \
--name mcproxy-browser-server \
-p 3000:3000 \
-e AUTH_TOKEN=your-secret-token \
ghcr.io/saladtechnologies/mcproxy/browser-server:latest
使用 Docker 运行 MCP 服务器
MCP 服务器使用标准输入输出进行通信,因此需要使用 -i 标志以交互模式运行:
docker run --rm -i \
--network=host \
-e MCPROXY_AUTH_TOKEN=your-secret-token \
-e MCPROXY_DEFAULT_ENDPOINT=ws://localhost:3000 \
ghcr.io/saladtechnologies/mcproxy/mcp-server:latest
使用 Docker 配置 MCP 客户端
将您的 MCP 客户端配置为使用 Docker 镜像,而不是从源代码运行:
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"mcproxy": {
"command": "docker",
"args": [
"run", "--rm", "-i", "--network=host",
"-e", "MCPROXY_AUTH_TOKEN=your-secret-token",
"-e", "MCPROXY_DEFAULT_ENDPOINT=wss://your-salad-endpoint.salad.cloud",
"ghcr.io/saladtechnologies/mcproxy/mcp-server:latest"
]
}
}
}
Claude Code (.mcp.json):
{
"mcpServers": {
"mcproxy": {
"command": "docker",
"args": [
"run", "--rm", "-i", "--network=host",
"-e", "MCPROXY_AUTH_TOKEN=your-secret-token",
"-e", "MCPROXY_DEFAULT_ENDPOINT=wss://your-salad-endpoint.salad.cloud",
"ghcr.io/saladtechnologies/mcproxy/mcp-server:latest"
]
}
}
}
完整的本地 Docker 设置
若要使用 Docker 在本地测试所有功能(无需构建):
docker run -d \
--name mcproxy-browser-server \
-p 3000:3000 \
-e AUTH_TOKEN=test-token \
ghcr.io/saladtechnologies/mcproxy/browser-server:latest
docker stop mcproxy-browser-server && docker rm mcproxy-browser-server
💻 使用示例
基本会话创建
Create a browser session at wss://my-salad-endpoint.salad.cloud
Claude 将在响应中看到浏览器类型和位置信息:
{
"sessionId": "abc-123",
"endpoint": "wss://my-salad-endpoint.salad.cloud",
"browserType": "chromium",
"location": {
"ip": "203.0.113.42",
"city": "Salt Lake City",
"region": "Utah",
"regionCode": "UT",
"country": "United States",
"countryCode": "US",
"timezone": "America/Denver",
"isp": "Example ISP"
}
}
移动设备模拟
Create an iPhone 15 browser session and navigate to example.com.
Take a screenshot to see the mobile layout.
List available devices that include "iPad" in the name.
Create a session emulating an iPad Pro and check how the site renders.
人性化浏览
Create a session and navigate to the login page. Use humanized typing to
enter the username and password, then humanized click to submit the form.
This helps avoid bot detection.
Cloudflare 保护的网站
Navigate to this Cloudflare-protected site with wait_for_cloudflare enabled.
Wait up to 20 seconds for any challenges to complete automatically.
多浏览器测试
Create a Chromium session and a Firefox session at wss://my-salad-endpoint.salad.cloud.
Navigate both to example.com and take screenshots to compare rendering.
地理分布式价格比较
Create 3 browser sessions at wss://my-salad-endpoint.salad.cloud (it will
connect to different replicas). List the sessions and tell me which locations
they're in.
Then use the session in California to check the price of "iPhone 15" on
apple.com, and use the session in Texas to check the same product. Compare
the prices including any tax differences.
按位置引用会话
List all my browser sessions.
Navigate to netflix.com using the Utah session.
Take a screenshot of the one in New York.
基于 Cookie 的会话持久化
Log into the website, then save the cookies. I'll use them later to
restore the session without logging in again.
📚 详细文档
配置
浏览器服务器(环境变量)
| 变量 |
默认值 |
描述 |
PORT |
3000 |
WebSocket 服务器端口 |
AUTH_TOKEN |
(必需) |
用于身份验证的共享密钥 |
MAX_CONTEXTS |
10 |
每个容器的最大浏览器上下文数 |
CONTEXT_TTL_MS |
1800000 |
上下文超时时间(30 分钟) |
HEALTH_PORT |
8080 |
健康/就绪检查的 HTTP 端口 |
健康检查端点
浏览器服务器在 HEALTH_PORT(默认 8080)上暴露健康检查端点:
| 端点 |
描述 |
GET /health |
返回包含上下文数量的健康状态。响应:{"status": "healthy", "contexts": 0, "maxContexts": 10} |
GET /ready |
就绪探测器。当服务器准备好接受连接时返回 {"ready": true} |
SaladCloud 配置:
- 启动探测器:在端口
8080 上执行 GET /ready - 确认服务器已初始化
- 存活探测器:在端口
8080 上执行 GET /health - 确认服务器健康
MCP 服务器(环境变量)
| 变量 |
默认值 |
描述 |
MCPROXY_AUTH_TOKEN 或 AUTH_TOKEN |
(必需) |
用于身份验证的共享密钥 |
MCPROXY_HEARTBEAT_INTERVAL_MS |
30000 |
心跳间隔(30 秒) |
MCPROXY_COMMAND_TIMEOUT_MS |
30000 |
命令超时时间(30 秒) |
MCP 工具
会话管理
| 工具 |
描述 |
browser_create_session |
创建一个新的浏览器会话,可选择浏览器类型和设备模拟 |
browser_list_sessions |
列出所有活动会话,包括浏览器类型和位置 |
browser_close_session |
关闭会话并释放资源 |
browser_list_devices |
列出所有可用于移动设备模拟的设备名称 |
browser_get_capabilities |
获取服务器功能并检查版本不匹配情况 |
browser_create_session 参数:
endpoint(可选):WebSocket 端点 URL(如果未提供,则使用 MCPROXY_DEFAULT_ENDPOINT)
browser_type(可选):chromium(默认)、firefox 或 webkit(Safari)
device(可选):要模拟的设备(例如,"iPhone 15"、"Pixel 7"、"iPad Pro 11")
viewport(可选):{ width, height }(像素)(如果设置了设备,则忽略此参数)
userAgent(可选):自定义用户代理字符串(覆盖设备和随机设置)
randomUserAgent(可选):使用随机逼真的用户代理
isMobile(可选):模拟移动浏览器
hasTouch(可选):启用触摸事件
导航
| 工具 |
描述 |
browser_navigate |
导航到指定 URL,可选择自动等待 Cloudflare 挑战完成 |
browser_go_back |
后退到历史记录中的上一页 |
browser_go_forward |
前进到历史记录中的下一页 |
browser_reload |
重新加载当前页面 |
browser_navigate 参数:
session_id(必需):会话 ID
url(必需):要导航到的 URL
wait_until(可选):load、domcontentloaded 或 networkidle
wait_for_cloudflare(可选):自动等待 Cloudflare 挑战完成
cloudflare_timeout(可选):最大等待时间(毫秒)(默认:15000)
交互(基于选择器)
| 工具 |
描述 |
browser_click |
通过 CSS 选择器点击元素 |
browser_type |
通过选择器在输入框中输入文本 |
browser_select |
选择下拉选项 |
browser_hover |
悬停在元素上 |
browser_scroll |
滚动页面或元素 |
交互(基于坐标)
这些工具使用 相对坐标(0 - 1 范围),因此视觉代理可以根据截图进行点击,而无需担心分辨率:
x = 0 表示左边缘,x = 1 表示右边缘
y = 0 表示上边缘,y = 1 表示下边缘
| 工具 |
描述 |
browser_click_at |
在相对坐标(0 - 1 范围)处点击 |
browser_double_click_at |
在指定坐标处双击 |
browser_move_mouse |
将鼠标移动到指定坐标 |
browser_drag |
从一个位置拖动到另一个位置 |
视觉代理的示例工作流程:
1. browser_screenshot() # 获取截图
2. browser_click_at(0.5, 0.3) # 点击中心顶部区域
3. browser_keyboard_type("hello") # 在焦点处输入文本
4. browser_keyboard_press("Enter") # 提交
键盘(类人文本输入)
这些工具在 当前聚焦元素 处输入文本(无需选择器),更具人类输入的特点:
| 工具 |
描述 |
browser_keyboard_type |
在当前焦点处输入文本 |
browser_keyboard_press |
按下按键(Enter、Tab、Escape、箭头键或组合键,如 Control + a) |
browser_keyboard_down |
按住按键(用于修饰键) |
browser_keyboard_up |
释放按住的按键 |
人性化选项:
大多数交互工具支持 humanize: true 选项,以实现自然、类人的行为:
- Click/Click_at:自然的曲线鼠标移动到目标位置
- Type/Keyboard_type:按键之间随机延迟(50 - 150 毫秒)
- Scroll:以自然的时间间隔进行小增量的平滑滚动
- Move_mouse/Drag:具有加速/减速的贝塞尔曲线路径
内容提取
| 工具 |
描述 |
browser_screenshot |
截取屏幕截图(返回 base64 编码的 PNG 格式,可保存到文件) |
browser_get_content |
获取 HTML 内容 |
browser_get_text |
获取可见文本 |
browser_evaluate |
执行 JavaScript 代码 |
等待
| 工具 |
描述 |
browser_wait_for_selector |
等待元素出现 |
browser_wait_for_navigation |
等待导航完成 |
Cookie 管理
| 工具 |
描述 |
browser_get_cookies |
从会话中获取 Cookie(可根据 URL 进行过滤) |
browser_set_cookies |
在会话中设置 Cookie(用于恢复身份验证状态) |
browser_clear_cookies |
清除会话中的所有 Cookie |
Cookie 持久化示例:
# 登录后保存 Cookie
cookies = browser_get_cookies(session_id)
# 将 Cookie 存储到某个位置...
# 稍后,恢复会话
browser_set_cookies(session_id, cookies)
browser_navigate(session_id, "https://example.com/dashboard")
CAPTCHA 处理
| 工具 |
描述 |
browser_check_captcha |
检查页面上是否存在 CAPTCHA,返回截图供代理分析 |
browser_solve_captcha |
分析图像后提交 CAPTCHA 解决方案 |
CAPTCHA 流程:
browser_navigate 自动检测 CAPTCHA 并返回截图
- 代理使用视觉功能分析 CAPTCHA 图像
- 代理调用
browser_solve_captcha 提交解决方案
- 如果需要,
browser_check_captcha 可以重新检查页面
支持的 CAPTCHA 类型:reCAPTCHA、hCaptcha、Cloudflare Turnstile、FunCaptcha 和通用图像/文本 CAPTCHA。
MCP 客户端配置
git clone https://github.com/SaladTechnologies/mcproxy.git
cd mcproxy
npm install
npm run build
Claude Desktop
将以下配置添加到 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)或 %APPDATA%\Claude\claude_desktop_config.json(Windows):
{
"mcpServers": {
"mcproxy": {
"command": "node",
"args": ["/path/to/mcproxy/mcp-server/dist/index.js"],
"env": {
"MCPROXY_AUTH_TOKEN": "your-secret-token",
"MCPROXY_DEFAULT_ENDPOINT": "wss://your-salad-endpoint.salad.cloud"
}
}
}
}
Claude Code(VS Code 扩展)
将以下配置添加到您的工作区 .mcp.json 或全局设置中:
{
"mcpServers": {
"mcproxy": {
"command": "node",
"args": ["./mcp-server/dist/index.js"],
"env": {
"MCPROXY_AUTH_TOKEN": "your-secret-token",
"MCPROXY_DEFAULT_ENDPOINT": "wss://your-salad-endpoint.salad.cloud"
}
}
}
}
Cursor
将以下配置添加到 Cursor 的 MCP 设置(~/.cursor/mcp.json)中:
{
"mcpServers": {
"mcproxy": {
"command": "node",
"args": ["/path/to/mcproxy/mcp-server/dist/index.js"],
"env": {
"MCPROXY_AUTH_TOKEN": "your-secret-token",
"MCPROXY_DEFAULT_ENDPOINT": "wss://your-salad-endpoint.salad.cloud"
}
}
}
}
Windsurf
将以下配置添加到 Windsurf 的 MCP 配置中:
{
"mcpServers": {
"mcproxy": {
"command": "node",
"args": ["/path/to/mcproxy/mcp-server/dist/index.js"],
"env": {
"MCPROXY_AUTH_TOKEN": "your-secret-token",
"MCPROXY_DEFAULT_ENDPOINT": "wss://your-salad-endpoint.salad.cloud"
}
}
}
}
其他 MCP 客户端
任何与 MCP 兼容的客户端都可以使用 mcproxy。服务器通过标准输入输出使用标准 MCP 协议进行通信。所需的环境变量:
MCPROXY_AUTH_TOKEN:身份验证令牌(必须与浏览器服务器的 AUTH_TOKEN 匹配)
MCPROXY_DEFAULT_ENDPOINT(可选):默认 WebSocket 端点,这样您就无需在每个 browser_create_session 调用中指定它
部署到 SaladCloud
1. 构建并推送 Docker 镜像
docker build -t your-registry/mcproxy-browser:latest -f browser-server/Dockerfile .
docker push your-registry/mcproxy-browser:latest
2. 在 SaladCloud 上创建容器组
- 访问 SaladCloud 门户
- 创建一个新的容器组
- 配置:
- 镜像:
your-registry/mcproxy-browser:latest
- 端口:
3000
- 环境变量:
AUTH_TOKEN:您的密钥令牌
MAX_CONTEXTS:10(根据容器资源进行调整)
- 资源:建议浏览器自动化至少使用 2GB 内存
- 网络:启用容器网关
- 启动探测器:在端口
8080 上执行 HTTP GET /ready
- 存活探测器:在端口
8080 上执行 HTTP GET /health
- 部署到您想要的区域
3. 记录您的端点
每个容器组将有一个类似以下的端点:
wss://your-org-abc123.salad.cloud
在创建浏览器会话时使用这些端点。
🔧 技术细节
项目结构
mcproxy/
├── shared/ # 共享的 TypeScript 类型
│ └── src/
│ └── protocol.ts # WebSocket 消息类型 + 位置信息
├── browser-server/ # 远程浏览器服务器
│ └── src/
│ ├── browser-manager.ts # Playwright + 隐身功能
│ ├── location-service.ts# IP 地理定位检测
│ ├── ws-server.ts # WebSocket 服务器
│ ├── command-handler.ts # 命令执行
│ └── index.ts # 入口点
├── mcp-server/ # 本地 MCP 服务器
│ └── src/
│ ├── browser-client.ts # WebSocket 客户端
│ ├── session-manager.ts # 会话管理 + 位置跟踪
│ ├── tools/ # MCP 工具定义
│ └── index.ts # 入口点
├── docker-compose.yml # 本地开发
└── package.json # 单仓库配置
构建
npm run build
npm run build:shared
npm run build:browser-server
npm run build:mcp-server
开发环境运行
npm run dev:browser-server
npm run dev:mcp-server
🔧 故障排除
连接超时
如果会话意外断开连接:
- 检查心跳间隔(默认 30 秒)是否小于 Salad 的空闲超时时间(100 秒)
- 验证与 SaladCloud 端点的网络连接
- 检查容器日志中的错误信息
机器人检测
如果网站检测到自动化操作:
- 隐身插件通常可以自动处理大多数情况
- 在点击、输入和滚动操作中使用
humanize: true 以实现类人行为
- 创建会话时尝试使用
randomUserAgent: true 来轮换指纹
- 使用移动设备模拟(
device: "iPhone 15") - 移动浏览器通常更受信任
- 对于 Cloudflare 保护的网站,在导航时使用
wait_for_cloudflare: true
Cloudflare 挑战
如果 Cloudflare 挑战未完成:
- 增加
cloudflare_timeout(默认 15 秒)
- 某些挑战需要交互 - 检查是否存在交互式 CAPTCHA
- 尝试使用不同的浏览器类型(Firefox 或 WebKit)
- 使用
browser_check_captcha 查看存在哪种类型的挑战
版本不匹配
如果出现意外行为或缺少功能:
- 使用
browser_get_capabilities 检查服务器版本和支持的功能
- 该工具会在浏览器服务器和 MCP 服务器版本不匹配时发出警告
- 更新版本落后的组件(响应中会提供建议)
使用 networkidle 时的导航错误
如果在使用 wait_until: networkidle 时导航失败并出现 net::ERR_ABORTED 错误:
- 具有动态内容或持续网络活动的网站可能永远不会达到“网络空闲”状态
- 改用
load 或 domcontentloaded(默认是 domcontentloaded)
networkidle 最适合静态页面或需要所有资源完全加载的情况
- 对于大多数用例,默认的
domcontentloaded 是最快且最可靠的选择
截图和文件处理
browser_screenshot 返回的截图以 base64 编码形式呈现,并在 MCP 响应中内联显示:
- 内联图像显示会自动工作 - 无需使用
present_files 或类似工具
- 可选的
file_path 参数可方便地将截图保存到磁盘,但 base64 响应是主要输出
- 如果使用
file_path,文件将保存在运行 MCP 服务器的机器(您的本地机器)上,而不是远程浏览器服务器上
内存问题
如果浏览器服务器内存不足:
- 在 SaladCloud 上增加容器内存分配(对于繁重的自动化任务,建议使用 4GB 以上)
- 减少
MAX_CONTEXTS 以限制并发浏览器上下文数量
- 完成会话后使用
browser_close_session 关闭会话
- 在同一会话中访问不同网站之间使用
browser_clear_cookies
📄 许可证
本项目采用 MIT 许可证。