Sign inSign up

mahufong/agent-browser-adapter

By mahufong

•Updated 24 days ago

Image
0

2.0K

mahufong/agent-browser-adapter repository overview

⁠个人 MCP 网关(FastMCP + WorkOS + Cloudflare Tunnel)

这是一个面向 ChatGPT 网页版 的 Ubuntu / Docker Compose 部署包。它采用统一身份验证,但不会把多个 MCP 的工具集合并成一个大列表。

flowchart TD
    C[ChatGPT 网页版] --> T[Cloudflare Tunnel]
    T --> G1[网关:agent-browser :8101]
    T --> G2[网关:未来 MCP :8102]
    G1 --> A[私有 HTTP 适配器]
    A --> S[agent-browser stdio]
    S --> B[远程 CDP 浏览器]
    G2 --> H[未来原生 HTTP MCP]

每个外部域名对应一个独立 FastMCP 进程、端口、OAuth Resource Indicator 和 ChatGPT 连接。统一的是代码、WorkOS 租户和部署单元,不是工具命名空间。

⁠镜像、架构与标签

本项目使用 Docker Hub 上的两个应用镜像:

  • mahufong/mcp-gateway
  • mahufong/agent-browser-adapter

两个镜像都发布 linux/amd64 与 linux/arm64。发布时必须协调使用同一个标签:

  • latest 是同一工作流为两个镜像依次更新的移动标签;Docker Hub 无法跨两个镜像仓库原子移动标签。
  • sha-<12-character root commit> 是当前仓库根提交 SHA 的前 12 位,例如 sha-0123456789ab,用于精确标识一次双镜像发布。

发布工作流把 SHA 标签当作写一次的不可变发布:两个 SHA 标签都不存在时才构建;两个都已存在时只重新校验并复用;如果只存在其中一个则视为半发布并直接失败,不会覆盖现存 SHA 标签。开发或临时环境可以使用 latest。生产 Compose 或 Kubernetes 应固定同一个 SHA 标签,不能让两个服务使用不同提交,也不能用 latest 作为生产回滚依据。

镜像由 .github/workflows/mcp-gateway.yml 构建和发布。CI 会运行网关/适配器 smoke 检查,并检查每个发布标签是否包含 Linux amd64 和 arm64 manifest。工作流只发布镜像,不执行生产部署;smoke 使用临时测试配置,不需要 WorkOS、Cloudflare Tunnel、CDP 或其他生产 Secret。

⁠0. 先确认 ChatGPT Plus 入口

截至 2026-09-01,OpenAI 当前帮助页把完整 MCP / 自定义 App 的正式可用范围写为 Business、Enterprise/Edu;但 OpenAI 支持人员也曾说明部分 Plus/Pro 个人账户可在 Developer Mode 创建或安装自定义 MCP。Plus 的实际入口存在账户与灰度差异。

部署前请在 ChatGPT 网页版确认同时能看到:

  1. Settings → Apps → Advanced settings → Developer mode;
  2. Settings → Apps → Create(或等价的“创建自定义 App/MCP”入口)。

两项都有即可继续。若没有 Create,服务端部署仍然有效,但无法靠修改 FastMCP、WorkOS 或 Cloudflare 绕过 ChatGPT 账户侧限制;需要等待账户开放、改用支持远程 MCP 的其他客户端,或升级到有正式支持的套餐。

参考:OpenAI 当前说明⁠;Plus/Pro Developer Mode 支持回复⁠。

⁠已确定的首版参数

项目选择
公网地址https://mcp-agent-browser.mahufong.top/mcp
入口Cloudflare Tunnel,不开放主机端口
OAuthWorkOS AuthKit,由外层网关统一验证
用户限制JWT sub 精确白名单,默认只允许一个 WorkOS 用户
FastMCP固定为已验证的 4.0.5;Gateway 直接使用的 mcp==2.2.0、mcp-types==2.2.0、httpx2==2.13.0 同样显式锁定;升级时先跑完整 CI/smoke
agent-browser发布镜像固定为 0.34.0;升级需修改构建版本并由 CI 重新发布
cloudflared固定为 2026.8.2,稳定后再固定镜像 digest
stdio 转换与 agent-browser 同一容器内转换为私有 Streamable HTTP
CDP URL由 .env 的 AGENT_BROWSER_CDP 传给 agent-browser;优先填 http(s) DevTools 端点
浏览器状态由远程浏览器服务维护;适配器不安装 Chrome、不保存 profile
浏览器并发单并发,避免多个调用同时操作同一浏览器

⁠1. Ubuntu 主机准备

建议 Ubuntu 22.04 或 24.04,并安装 Docker Engine 与较新的 Compose plugin(需要支持 gw_priority,建议 Compose 2.33.1+)。确认:

docker version
docker compose version

将本目录复制到主机,例如 /opt/personal-mcp-gateway,然后:

cd /opt/personal-mcp-gateway
cp .env.example .env
chmod 600 .env
nano .env

填写 WorkOS、Cloudflare 和完整 CDP URL。不要把 .env 提交到 Git。

⁠2. agent-browser 的 CDP 配置

AGENT_BROWSER_CDP 接受两种形式,优先选择前者:

# 自建浏览器:DevTools HTTP 端点,浏览器重启后依然有效
AGENT_BROWSER_CDP='http://browser-host.example:9222'

# 托管浏览器服务:服务商签发的完整 WebSocket 地址
AGENT_BROWSER_CDP='wss://provider.example/devtools/browser/your-current-id?token=...'

ws://host:9222/devtools/browser/<uuid> 里的 UUID 由 Chrome 在每次启动时重新生成,所以浏览器一重启该地址就失效。http(s) 端点只含主机和端口,agent-browser 会在连接时请求 /json/version 取得当前的 WebSocket 地址,因此浏览器重启后不需要改配置、也不需要重建容器。Kubernetes 的一次性 startupProbe 会执行 /app/warmup.py,经 127.0.0.1:8000/mcp 调用只读的 agent_browser_get_url,从而预热 adapter 的 FastMCP provider、常驻 stdio MCP 链路、agent-browser daemon 和浏览器/CDP。warmup 的本地 HTTP session 会在调用后关闭,但模块级 StdioTransport(keep_alive=True) 会保留其 agent-browser 子进程。之后的周期性 healthcheck 只检查本地监听和 http(s) CDP 端点,不会创建 MCP/SSE 会话。MCP tools/list 协议检查只在 CI smoke 和部署验收时执行,见 adapters/agent-browser/healthcheck.py。

托管服务通常只提供带 token 的 wss 地址,那就照原样填写。完整 CDP URL 往往包含凭据,建议使用单引号,避免其中的 $、# 或 query string 被 Compose 误解析。

修改这个值之后,使用 registry-first 流程重新创建适配器;单纯 docker compose restart 不会重新读取环境变量:

docker compose pull
docker compose up -d --no-build --force-recreate agent-browser-adapter
docker compose up -d --no-build mcp-gateway

工具范围也由 .env 控制:AGENT_BROWSER_TOOLS=core 是较小的默认列表;你可以自行改为 all,或使用逗号分隔的组合,例如 core,network,state,tabs。修改后同样重新创建适配器。

⁠3. WorkOS AuthKit

在 WorkOS Dashboard 中完成:

  1. 启用 AuthKit,并记下形如 https://xxx.authkit.app 的 AuthKit Domain。
  2. 关闭公开注册,只保留你自己的用户;如有条件,同时启用 MFA。
  3. 启用 Client ID Metadata Document(CIMD);同时保留 Dynamic Client Registration(DCR)兼容旧客户端。
  4. 注册 Resource Indicator:https://mcp-agent-browser.mahufong.top/mcp。首个 MCP 可设为默认 Resource。
  5. 从 Users 页面取得你自己的 user_... ID,填入 ALLOWED_WORKOS_SUBS。网关按 JWT 的 sub 精确比较,不以邮箱判断。
  6. 确认 AuthKit discovery metadata 的 scopes_supported 包含 offline_access,且授权会签发 refresh token;否则 ChatGPT 的登录会在 access token 到期后失效。

以后每增加一个域名,都要增加对应的完整 Resource Indicator,例如 https://mcp-notes.mahufong.top/mcp。WorkOS 只能有一个默认 Resource;多个 MCP 时必须确认 ChatGPT 对每个连接正确发送 resource 参数。

详见 WorkOS 与 Cloudflare 配置⁠。

⁠4. Cloudflare Tunnel

创建一个 remotely-managed Tunnel,把 token 写入 .env。在 Tunnel 的 Public Hostnames 中添加:

Public hostnameService
mcp-agent-browser.mahufong.tophttp://mcp-gateway:8101

这里使用 mcp-agent-browser.mahufong.top,它只比 mahufong.top 多一级,通常可由 Cloudflare Universal SSL 覆盖。agent-browser.mcp.mahufong.top 多两级,默认通配证书通常不覆盖。

不要在该 hostname 前再启用 Cloudflare Access 登录,否则会与 WorkOS OAuth 形成 ChatGPT 无法自动完成的双重认证。应关闭缓存、JS Challenge 和交互式 Bot Challenge;WAF 可保留不需要浏览器挑战的规则。

⁠5. 启动(registry-first)

生产或普通运行主机直接拉取已发布镜像,禁止通过启动命令触发本地构建。生产环境先将两个服务设为同一个固定 SHA 标签:

export MCP_GATEWAY_IMAGE=mahufong/mcp-gateway:sha-0123456789ab
export AGENT_BROWSER_ADAPTER_IMAGE=mahufong/agent-browser-adapter:sha-0123456789ab

不需要固定版本时可省略这两个变量,Compose 默认使用 latest。无论使用哪种标签,都必须先拉取再启动:

docker compose config
docker compose pull
docker compose up -d --no-build
docker compose ps
docker compose logs --tail=100 mcp-gateway agent-browser-adapter cloudflared

pull 必须先执行,up --no-build 用来确保启动失败时不会回退到本地构建。生产环境不要使用 latest 作为回滚依据。

Compose 没有发布任何 ports:。公网流量只能由 cloudflared 经私有 edge 网络进入。

Kubernetes 部署额外提供一个直连内网入口:mcp-gateway-internal NodePort(固定端口 30101)。在节点的 192.168.192.x 地址上访问 http://<节点内网IP>:30101/mcp 时,若配置了 MCP_INTERNAL_CIDRS=192.168.192.0/24,请求不会经过 Cloudflare,也不需要 OAuth。NodePort 必须由节点防火墙限制为该网段,不能发布到公网;公网域名仍始终要求 OAuth。

⁠6. 连接前检查

未带 token 访问 MCP 端点应得到 401,而不是 404 或 502:

curl -i -H 'Accept: application/json, text/event-stream' \
  https://mcp-agent-browser.mahufong.top/mcp

OAuth Protected Resource Metadata 应能访问:

curl -fsS \
  https://mcp-agent-browser.mahufong.top/.well-known/oauth-protected-resource/mcp

如果 WorkOS 登录成功、但 ChatGPT 看不到工具,先检查:

docker compose logs --tail=200 mcp-gateway agent-browser-adapter

常见原因是 Resource Indicator 与 /mcp 完整 URL 不一致、ALLOWED_WORKOS_SUBS 不是 access token 的 sub、AGENT_BROWSER_CDP 已过期、上游 CDP 握手失败、后端 stdio 启动失败,或 Cloudflare 对流式响应做了挑战/缓存。

⁠分段性能日志

Gateway 和 adapter 使用同一个服务端生成的 request_id 输出 payload-free JSON 事件:

  • mcp_http_request:auth_phase_ms、first_byte_ms、total_ms;
  • mcp_tool_call:queue_ms、upstream_ms(包含通过工具级 subject 检查后的 Gateway→adapter 往返和下游执行;FastMCP 偶发的工具元数据预取只计入 HTTP total_ms);
  • mcp_adapter_request:adapter_total_ms;
  • agent_browser_tool_call:agent_browser_ms(stdio、agent-browser 和 CDP 阶段);
  • agent_browser_queue_timeout:adapter 的单浏览器锁等待超过 MCP_QUEUE_TIMEOUT_SECONDS 时记录 queue_ms,防止 public/internal 两个 Gateway listener 的请求在 adapter 层无限排队。

日志不会记录 bearer token、JWT、query、工具参数/结果、响应正文或客户端 IP 明文。origin_connection_id 是进程内加盐后的 origin peer 标识,只能用来判断 cloudflared 到 Gateway 的连接是否复用;Cloudflare 在边缘终止公网 TLS,因此该字段不能证明 ChatGPT 到 Cloudflare 的 TCP/TLS 复用。GET/SSE 长连接应看 first_byte_ms,不要把连接存续时间对应的 total_ms 当作工具执行时间。

⁠7. 在 ChatGPT 网页版添加

在 ChatGPT 的 Developer Mode 中创建一个自定义 MCP 连接:

  • 名称:Agent Browser
  • MCP Server URL:https://mcp-agent-browser.mahufong.top/mcp
  • Authentication:OAuth

完成 WorkOS 登录和授权后刷新工具列表。每个后续 MCP 也单独创建连接,因此它们在 ChatGPT 中保持分开。

⁠运维命令

# 状态与日志
docker compose ps
docker compose logs -f --tail=100

# 修改 config/services.json 后重新创建网关容器
docker compose up -d --no-build --force-recreate mcp-gateway

# 修改 CDP URL 或 AGENT_BROWSER_TOOLS 后拉取并重建适配器容器
docker compose pull
docker compose up -d --no-build --force-recreate agent-browser-adapter
docker compose up -d --no-build mcp-gateway

# 发布了新的 latest 镜像后更新两个服务
docker compose pull
docker compose up -d --no-build --force-recreate mcp-gateway agent-browser-adapter

# 停止网关;远程浏览器状态不在本项目中
docker compose down

⁠Kubernetes 生产部署

Kubernetes 不应使用本目录 Deployment 中的本地占位镜像或 latest。请按照 k8s/README.md⁠ 为网关和适配器设置同一个 sha-<12-character root commit> 标签,并通过集群 Secret 注入 WorkOS、CDP 等运行时凭据。CI 不会访问生产集群,也不会需要这些凭据。

⁠增加更多 MCP

  • 原生 HTTP MCP:参照 增加原生 HTTP MCP⁠。
  • stdio MCP:复制 adapters/agent-browser 的结构,让转换器与 stdio 进程待在同一个隔离容器,再把私有 HTTP 地址交给网关。
  • 安全边界与公网浏览器风险:务必阅读 安全与网络边界⁠。

⁠当前仍需你在部署时确定

  1. agent-browser 版本:发布镜像固定为 0.34.0,避免直接采用刚发布的版本;升级时修改 Dockerfile/工作流中的构建版本并通过 CI 发布新的双镜像标签。.env 中的 AGENT_BROWSER_VERSION 只影响贡献者本地构建。
  2. CDP URL:自建浏览器填 http://host:9222 这类 DevTools 端点,浏览器重启后无需改动;托管服务填其签发的 wss 地址,该地址变更后需要重新创建 agent-browser-adapter 容器。
  3. 工具范围:默认 core;你可在 .env 改为 all 或按组组合。
  4. 能力策略:按你的要求默认使用 full.json,即不额外禁用 eval/upload/download;如以后想收紧,可改用 files.json 或 safe.json。
  5. 网页网络范围:既有 CDP 会话不支持 agent-browser 的 allowed-domains;浏览器实际能访问哪里,由远程浏览器所在网络决定。

⁠本地验证(贡献者)

贡献者可在本目录运行静态检查和基于 uv 隔离环境的单元测试:

./validate.sh

Docker 镜像构建、容器启动和 MCP smoke test 统一由 .github/workflows/mcp-gateway.yml 在 GitHub Actions 中完成;生产主机必须使用上面的 Docker Hub 拉取流程。

⁠上游资料

Tag summary

Content type

Image

Digest

sha256:895ce6cc6…

Size

168.7 MB

Last updated

24 days ago

docker pull mahufong/agent-browser-adapter