Skip to main content
Glama
browser-persistent

browser-persistent

by Jinhuanxuvv
README.md
# browser-persistent

一个**带登录态**的浏览器 MCP 服务:让 AI agent 用真实 Chrome 打开需要登录、或重度依赖 JavaScript 的页面。

面向的场景很具体:容器里没有显示器、没有 Playwright 自带浏览器、但你又需要 agent 读到「登录后才看得见」的内容。

## 它解决什么

常见的 headless 浏览器封装通常是**一次性隔离档案**——每次启动都是全新身份,没有登录态,很多页面只能拿到登录墙。本项目反过来:

1. **固定 profile**,登录态跨进程留存,重启不重登;
2. **headful 跑在 Xvfb 虚拟显示上**(无显示器容器也能用),比纯 headless 更像真人环境;
3. **凭据只注入、不回显**:从受保护文件读 cookie 注入浏览器,任何工具都不返回 cookie 的值;
4. **不下载浏览器**:直接用系统 Chromium 配 `playwright-core`,省掉 Playwright 动辄 150MB 的浏览器下载(在国内网络环境里这步经常卡死)。

## 能力边界(实测,别信宣传)

诚实比功能重要,以下都是真机实测结论:

| 目标 | 结果 |
|---|---|
| X 文章页(`/i/article/...`) | ✅ 可读全文。注入 `auth_token` 后浏览器自行取得 `ct0`,无需人工登录 |
| X 个人主页 / 时间线 | ❌ 触发 Cloudflare 人机验证(403),等待不放行 |
| 京东首页 / 搜索页 | ⚠️ 页面能渲染、登录态可注入,但搜索会返回「访问频繁」限流 |
| 普通静态或 SSR 页面 | ✅ 正常 |

**本项目不做验证码绕过,也不保证能绕过任何风控。** 上面标 ❌ 和 ⚠️ 的,就是绕不过去,如实写明。

## 安装

```bash
# 系统依赖(Debian/Ubuntu)
apt-get install -y chromium xvfb

# 项目依赖
npm i playwright-core @modelcontextprotocol/sdk
```

## 配置

全部通过环境变量,都有默认值:

| 变量 | 默认 | 说明 |
|---|---|---|
| `DSH_BROWSER_PROFILE` | `/workspace/.browser-profile` | profile 目录,登录态存这里 |
| `DSH_BROWSER_CHROME` | `/usr/bin/chromium` | Chromium 可执行文件 |
| `DSH_BROWSER_DISPLAY` | `:99` | Xvfb 的虚拟显示号 |
| `DSH_BROWSER_X_SECRET` | `/data/.secrets/x-session.json` | 含 `auth_token` 字段的凭据文件 |
| `DSH_BROWSER_JD_COOKIES` | `/workspace/jd-cookies.json` | 浏览器导出的 cookie JSON 数组 |
| `DSH_BROWSER_ALLOW` | 空(允许全部) | 域白名单,逗号分隔,如 `x.com,github.com` |
| `DSH_BROWSER_MIN_INTERVAL_MS` | `0` | 两次导航的最小间隔,建议对风控站点设 `60000` |
| `DSH_BROWSER_COOLDOWN_MS` | `1800000` | 触发风控后的熔断时长(默认 30 分钟) |

凭据文件的权限建议 `600`,且**不要放进版本库**(`.gitignore` 已排除)。

## 礼貌访问(三个护栏)

对着带风控的站点跑自动化,最容易被忽略的不是技术,是节奏。本项目内置三道护栏:

1. **域白名单**:设了 `DSH_BROWSER_ALLOW` 之后,不在名单内的域名直接拒绝导航,连点击和填写也一并拒绝。
2. **最小间隔**:`DSH_BROWSER_MIN_INTERVAL_MS` 控制两次导航的间隔,过快会直接报错并告知还需等待多久;单次可用 `force: true` 越过,但白名单与熔断不受影响。
3. **风控熔断**:页面正文命中「访问频繁」「安全验证」「当前页面异常」「Just a moment」等特征后,**自动熔断 30 分钟**,期间所有导航被拒,`browser_policy` 可查剩余冷却时间。

三道护栏都不是绕过风控的技巧,而是**在被风控之前先自己停手**。实测中京东就是靠这一条把损失降到最低的。


## 接进 MCP 客户端

以支持 stdio MCP 的客户端为例:

```json
{
  "mcpServers": {
    "browser-persistent": {
      "command": "node",
      "args": ["/path/to/browser-persistent/server.js"],
      "env": {
        "DSH_BROWSER_PROFILE": "/path/to/.browser-profile"
      }
    }
  }
}
```

## 工具一览

| 工具 | 用途 |
|---|---|
| `browser_open` | 打开 URL,等渲染完成,返回标题、最终地址、正文 |
| `browser_text` | 读当前页正文 |
| `browser_html` | 读 HTML(可按选择器取片段) |
| `browser_shot` | 截图存文件 |
| `browser_click` / `browser_type` | 点击 / 填写 |
| `browser_eval` | 页面内执行 JS |
| `browser_cookies` | 列 cookie 的**名称与域**,不返回值 |
| `browser_import_cookies` | **通用** cookie 导入:接受浏览器导出的 JSON(数组或 `{cookies:[]}`) |
| `browser_login_x` | 注入 X 的 `auth_token` 并建立登录态 |
| `browser_login_jd` | 注入浏览器导出的京东 cookie |
| `browser_policy` | 查看白名单、最小间隔与剩余熔断时间 |
| `browser_close` | 关闭浏览器,profile 保留 |

## 安全提醒

- profile 目录里等同于**明文登录凭据**,权限建议 `700`,永不入库、不外传。
- 一个长期稳定的 profile 意味着**长期稳定的可识别身份**,这本身是风险;用完即弃的隔离档案在隐私上更安全。取舍要自己想清楚。
- 只在你有权访问的账号与站点上使用。

## 关于定位

它不是通用反自动化方案,也不是「隐形浏览器」。它只做三件事:留登录态、在没有屏幕的地方跑 headful、省掉浏览器下载;外加三道让你别把账号玩坏的护栏。

## License

MIT