Skip to main content
Glama
README.md
# MCP Agent Bridge

把本机变成一个可通过 **Cloudflare Tunnel** 公网访问的 MCP 服务器,让**网页端 Agent**(ChatGPT、Claude、Cursor、自建 Web Agent 等)直接:

- 📁 **读写你本机的文件**(`files.allowedRoots` 决定范围,默认 `["*"]` = 整机任意路径;也可只放行指定目录)
- ⚡ **控制你的 PowerShell**(默认 blocklist:任意命令可执行,删除/破坏性命令全链路拦截;可选 allowlist 白名单),并可通过 SSH 读取/操作远端主机
- 🧩 **使用你本机的 Skill**:`list_skills` / `read_skill` 让网页端模型直接读到本机 `SKILL.md` 并按其中的步骤干活
- 🔧 **调用你本机 Agent 的工具**(桥接任意本地 MCP server,stdio / HTTP / SSE)
- 🧠 **让本机的另一个 Agent(workbuddy / Claude Code / Cursor…)也连进来当"指挥方"**:它只用 `delegate_task` 下指令(几乎不耗自己的 token),网页端 Agent 领活、干活、回报 —— 两边共享同一块任务板
- 🌐 **联网搜索**:`web_search` / `fetch_page` 用你本机的网络位置去搜(默认 Bing,免 API Key)
- 🖥️ 同时在**本机监控台**里实时看到:谁连进来了、调用了什么工具、读写/执行了什么、参数和结果
- 💬 **本机 Agent 控制台(GUI)**:不含内置模型——一键生成"连接提示词"(给网页端)与"接入配置"(给本机 Agent),实时镜像活动流与任务板,并可手动调工具、审批

灵感来自 [expose-files-mcp](https://github.com/egyjs/expose-files-mcp),在其安全模型上扩展了 PowerShell 深度控制、Agent 工具桥接、本机 Skill 读取、多 Agent 协作任务板、联网搜索、实时监控与审批门。

```
 网页端 Agent (ChatGPT / Claude / 自建)        你(浏览器)
        │  https://<random>.trycloudflare.com/mcp     │  http://127.0.0.1:7822
        │  Authorization: Bearer <token>              │  http://127.0.0.1:7821
        ▼                                              ▼
 Cloudflare Tunnel (cloudflared)          Agent 控制台 (GUI) / 监控台
        │                                              │
        └──────────────┬───────────────────────────────┘
                       ▼
 ┌─────────────────────────────────────────────┐
 │  mcp-agent-bridge  (本机 Node 进程)          │
 │                                             │
 │  MCP Server (Streamable HTTP, 127.0.0.1)    │
 │   ├─ 文件工具   任意路径 list/read/write/...  │
 │   ├─ PowerShell run_powershell (blocklist)   │
 │   ├─ 本机 Skill list_skills / read_skill     │
 │   ├─ Agent 桥接  agent_call_tool ...         │
 │   ├─ 协作任务板  delegate_task / take_task    │
 │   └─ 联网搜索    web_search / fetch_page     │
 │          │                    │              │
 │          ▼                    ▼              │
 │  本机文件系统 / SSH 主机     本机其他 MCP server│
 │                          (stdio/HTTP/SSE)    │
 │                                             │
 │  GUI http://127.0.0.1:7822 (仅本机)          │
 │   接入本机Agent · 连接提示词 · 任务板 · 审批   │
 │  监控台 http://127.0.0.1:7821 (仅本机)       │
 │   实时活动流 · 会话 · 审计日志 · 配置         │
 └─────────────────────────────────────────────┘
```

## 快速开始

要求:Node.js ≥ 18.17;公网暴露需要 [cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)(`winget install Cloudflare.cloudflared`)。

```powershell
cd mcp-agent-bridge
npm install --registry=https://registry.npmmirror.com

node bin/mcp-agent-bridge.js --public

# 想收窄文件范围(只放行指定目录)时:
node bin/mcp-agent-bridge.js --allowed-roots "C:\Users\Administrator\.workbuddy,E:\projects"

# 想收回权限时(例如只读):
node bin/mcp-agent-bridge.js --files read-only

# 想收紧为白名单模式时:
node bin/mcp-agent-bridge.js `
  --root . `
  --powershell `
  --ps-mode allowlist `
  --allowed-commands "Get-ChildItem,Get-Content,Get-Date,node,git"
```

启动后控制台会打印:

```
── Server ────────────────────────────────────
  Root          C:\Users\Administrator\.workbuddy
  Files         read-write (sensitive patterns allowed) — whole machine (any path on this host + SSH targets)
  PowerShell    enabled — any command; deletion/destructive always blocked (blocklist mode)
  Skills        enabled (5 dirs: ...\.trae-cn\skills, ...\.claude\skills, ...)
  Search        enabled (engine: bing; web_search + fetch_page, no API key needed)
  Handoff       enabled — local agent (commander) ⇄ web agents (workers); 0 open / 0 task(s) in ...\logs\board.json
  Tools         24 (get_status, list_files, read_file, ...)

── Tunnel (cloudflared) ──────────────────────
  Public        https://xxxx-yyyy.trycloudflare.com/mcp
  Header        Authorization: Bearer <token>
  Token         9f2b1c...        (自动生成,也可用 --auth-token 指定)

── Agent Console (GUI) ───────────────────────
  URL           http://127.0.0.1:7822
  Mode          connect-prompt console — no built-in model; the web agent is the brain
  Local agent   console → 🔌 接入本机 Agent for a ready-to-paste MCP client config

── Dashboard (monitor) ───────────────────────
  URL           http://127.0.0.1:7821
```

把 **Public URL + Token** 填到你的网页端 Agent 即可;也可以打开 `http://127.0.0.1:7822` 点 **「🔗 连接网页 Agent」**,直接拿一段写好的连接提示词粘给网页端模型;想让**本机另一个 Agent**也连进来当指挥方,点 **「🔌 接入本机 Agent」**。`http://127.0.0.1:7821` 看监控。

## 网页端 Agent 如何接入

| 客户端 | 接入方式 |
|---|---|
| 通用 MCP 客户端 | Streamable HTTP 端点 `<tunnel-url>/mcp`,请求头 `Authorization: Bearer <token>` |
| ChatGPT | Settings → Apps & Connectors → Developer mode → 添加 MCP Server(填 URL);token 走自定义 Header 或使用 OAuth 网关 |
| Claude / Cursor 等 | 在 MCP 配置中填 URL,认证头 `Authorization: Bearer <token>` |
| 自建 Web Agent | `fetch(url + "/mcp", { headers: { Authorization: "Bearer " + token }, ... })` 按 MCP Streamable HTTP 协议调用 |

SDK 示例(Node):

```js
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const client = new Client({ name: "web-agent", version: "1.0.0" });
await client.connect(
  new StreamableHTTPClientTransport(new URL("https://xxxx.trycloudflare.com/mcp"), {
    requestInit: { headers: { Authorization: `Bearer ${TOKEN}` } },
  }),
);
const { tools } = await client.listTools();
const res = await client.callTool({ name: "run_powershell", arguments: { command: "Get-Date" } });
```

## 本机 Agent 接入(多一个"指挥方"客户端)

原来的模式不变:网页端 Agent 通过隧道连进来干活。**新增加的是——你本机的另一个 Agent(workbuddy、Claude Code、Cursor、TRAE…)也连到同一个桥上**,于是它和网页端 Agent 就能通过这个 MCP 沟通:

```text
本机 Agent(指挥方,省 token)──delegate_task──▶ 共享任务板 ◀──take_task── 网页端 Agent(干活的)
        ▲                                          │
        └──────── 通知/留言(update_task 自动触发)────┘
```

关键点:两个客户端连的是**同一个 bridge 进程**,所以任务板是共享的(`board.file`,默认 `./logs/board.json`,重启不丢)。注意本机 Agent 要用 **HTTP 回环地址** `http://127.0.0.1:8080/mcp` 接入,**不要**用 stdio 另起一个进程——那样就变成两块板子了。隧道开不开都不影响本机接入。

### 怎么接

控制台右上角点 **🔌 接入本机 Agent**,会给你三样东西:

1. **MCP 客户端配置**(直接粘进本机 Agent 的 MCP 配置):
   ```json
   {
     "mcpServers": {
       "mcp-agent-bridge": {
         "type": "http",
         "url": "http://127.0.0.1:8080/mcp",
         "headers": { "Authorization": "Bearer <你的token>" }
       }
     }
   }
   ```
   个别客户端要求 `"type": "streamable-http"`,按客户端写法改一下即可。
2. **命令行方式**(Claude Code 等):`claude mcp add --transport http mcp-agent-bridge http://127.0.0.1:8080/mcp --header "Authorization: Bearer <token>"`
3. **一段说明**(把这句发给本机 Agent,它会按"指挥方"的规矩干活)

### 指挥方的省 token 规矩

内置在 `🔌 接入本机 Agent` 的说明里,核心就四条:

- 只下指令、不干重活:`delegate_task({ instruction: "一句话说清目标", context: "可选、尽量短" })`,写完就停
- 不轮询:干活的 Agent 完成/失败/被阻塞时会**自动**发通知给指挥方,`read_messages({to:"local"})` 收即可;要等就 `wait_for_work({role:"local", timeoutSec:60})`
- 看进度用 `get_tasks({status:"open"})`——每行一个摘要,只有要细节才 `verbose:true`
- 大文件、长日志、整页网页都让干活的 Agent 去读,指挥方只收结论

干活的 Agent 侧的约定是:`take_task` 领活 → 用文件/PowerShell/搜索工具干活 → `update_task({status:"done", result:"一句话结论"})` 汇报;信息不够就 `send_message({to:"local"})` 提问、`update_task({status:"blocked"})` 说明阻塞。

### 从控制台直接派活

控制台 → **📋 任务板** → 写一句指令 → 派活:等价于指挥方调用 `delegate_task`。谁派的、谁在干、干到哪一步(含最新 note / result)都在这个面板里,监控台首页也有一张任务板卡片。任务板 API:`GET /api/board`、`POST /api/board/task`、`POST /api/board/message`。

## 暴露给网页端 Agent 的工具

**文件(范围由 `files.allowedRoots` 决定)**
`list_files` `read_file` `write_file` `delete_file` `move_path` `search_files` `file_info`

默认 `files.allowedRoots = ["*"]`:**整机任意路径都可读可写**,传绝对路径即可(`C:\Users\...`、`D:\...`);想收窄就把它改成具体目录列表,`rootDir` 始终在范围内。

**本机 Skill**
`list_skills` — 列出本机全部 skill(扫描 `skills.dirs` 下含 `SKILL.md` 的目录),可按关键词过滤
`read_skill` — 按名字读取某个 skill 的 `SKILL.md`(或用 `file` 读 `references/xxx.md` 等附属文件),让网页端模型照它执行

**协作任务板(本机指挥方 ⇄ 干活的 Agent)**
`delegate_task` — 指挥方下指令(一句话),返回任务号,输出极短
`take_task` — 干活的 Agent 领取下一个任务(可按优先级/指定 id),拿到完整指令
`update_task` — 汇报进展/阻塞/完成(`done`/`failed`/`blocked` 会自动给指挥方发通知)
`get_tasks` — 一行一个任务摘要(`verbose:true` 才展开细节),指挥方省 token 就靠它
`send_message` / `read_messages` — 两边互相留言提问/回答,默认只读未读并标记已读
`wait_for_work` — 长轮询(最多 600s),有活/有留言才返回,避免双方空转轮询

**联网搜索**
`web_search` — 搜索并返回标题/链接/摘要(默认 Bing,免 API Key;可切 duckduckgo / tavily / brave)
`fetch_page` — 抓取某个页面并转成可读正文(`mode: text|html|links`;静态抓取,不执行 JS)

**PowerShell**
`run_powershell` — 双模式安全校验 + 超时(taskkill 整树击杀)+ 输出上限:

- **blocklist(默认)**:任意命令可执行(管道 `|`、重定向 `>`、`&&`/`;` 链都放行),但删除/破坏性命令在**任何形式**下都会被拦截——本体的 cmdlet 与别名(`Remove-Item`/`ri`/`rm`/`del`/`rmdir`/`rd`/`Clear-Content`/`Format-Volume`…)、命令链后半段的删除(`A; Remove-Item …`、`A && rm …`、`$(rm …)`)、嵌套 shell 内的删除(`cmd /c del`、`powershell -Command rm`、`bash -c "rm"`、`wsl rm`、`python -c "os.remove"` 等)、`powershell -EncodedCommand` **解码后**的删除、以及 SSH 远端命令中的删除。主机关机/重启(`Stop-Computer`/`shutdown`)与 `Invoke-Expression`(绕过向)也一律拦截
- **allowlist**:只放行 `powershell.allowedCommands` 里的命令,元字符默认禁用——旧行为,适合最严格场景

删除文件请走 `delete_file`(有审批门;PowerShell 侧无论本机还是 SSH 远端都删不了东西)。

### 通过 PowerShell 使用 SSH

blocklist 模式下可以直接跑 `ssh`,远端命令同样只拦删除:

```powershell
ssh -o BatchMode=yes -o ConnectTimeout=10 deploy@10.0.0.5 "df -h && free -m"
```

- 远端命令里的删除(`rm`、`rmdir`、`unlink`、`find -delete`、`sudo rm`、远端 python `os.remove` 等)会在**连接之前**被本地拦截;其余远端命令(管道、链式)正常放行
- **读取不受限**:`ssh host "cat /etc/hosts"`、`ssh host "ls -la /var/log"` 等浏览远端内容的命令一律放行,本地任意路径也能直接读
- 建议始终带 `-o BatchMode=yes -o ConnectTimeout=10`:交互式密码/指纹确认会让调用挂到超时
- 仅支持已配置免密登录(公钥)的主机;`ssh` 后面必须跟一次性命令,裸 `ssh`(读 stdin)会被拒绝

**Agent 桥接**
`agent_list_servers` `agent_list_tools` `agent_call_tool` `agent_refresh` — 把你本机其他 MCP server 的工具代理给网页端。

**状态**
`get_status` — 让 Agent 自查当前权限、文件范围(allowedRoots/是否整机)、PowerShell 模式(blocklist/allowlist)与白名单、skill 目录与数量、搜索引擎、协作任务板状态、agent 列表、敏感文件策略。

## 文件范围(allowedRoots)

```json
"files": { "allowedRoots": ["*"] }                                                   // 默认:整机任意路径
"files": { "allowedRoots": ["C:\\Users\\Administrator\\.workbuddy", "E:\\projects"] }  // 只放行这两个目录
```

- `"*"`(或 `"any"` / `"all"`)表示**整机**:`list_files` / `read_file` / `write_file` / `move_path` / `file_info` / `search_files` 都接受任意绝对路径,不再有 `PathSecurityError`
- 配置里的路径支持 `~`(展开为用户目录),`rootDir` 永远在允许范围内
- 越界时报错会提示怎么放宽:`Path "..." is outside the allowed roots (...). Add it to files.allowedRoots, or set files.allowedRoots = ["*"] ...`
- 敏感文件(`.env`、`*.pem`、`*.key`、`id_rsa`…)由 `sensitivePatterns` + `allowSensitive` 控制,**默认 `allowSensitive = true`(可读)**;要恢复防护就设成 `false`
- 唯一的写保护是"删除":`delete_file` 是唯一删除通道(审批门 + 拒绝删除允许根本身),PowerShell 的删除命令在本机与 SSH 远端一律拦截

## 使用你本机的 Skill

开启后(默认开启),网页端模型可以先 `list_skills` 看清单,再 `read_skill` 把某个 skill 的 `SKILL.md` 读进上下文,然后照其中的步骤用现有工具完成工作——相当于把本机 skill 库变成了它的一部分能力。

```json
"skills": {
  "enabled": true,
  "dirs": ["~/.trae-cn/skills", "~/.claude/skills", "~/.codex/skills", "~/.workbuddy/skills", "~/.trae-cn/plugins"],
  "maxDepth": 6,
  "maxSkills": 500
}
```

- 扫描规则:目录树下任何**含 `SKILL.md` 的文件夹**算一个 skill(其子目录视为 `references/`、`scripts/` 之类的附属资源,不再递归当 skill)
- 元信息取自 `SKILL.md` 顶部的 frontmatter(`name` / `display_name` / `description` / `description_zh`)
- 单文件读取上限 400 KB;`read_skill` 的 `file` 参数只接受 skill 目录内的相对路径
- 目录清单有 30 秒缓存,新增 skill 最多半分钟后可见;`skills.enabled = false` 则不注册这两个工具

## 联网搜索(web_search / fetch_page)

让连进来的 Agent 用**你本机的网络位置**去搜索和抓页面:`web_search({query})` 拿标题+链接+摘要,`fetch_page({url})` 把某个页面转成可读正文(`mode: text|html|links`)。

默认引擎是 **Bing**,**不需要 API Key**——Bing 有稳定的 RSS 结果端点(`https://www.bing.com/search?q=…&format=rss`),比抓 JS 渲染的结果页可靠得多,抓不到时才回退解析 HTML 结果块。默认之所以不是 DuckDuckGo:**国内多数网络根本连不上 DDG**(实测 `html.duckduckgo.com`、`lite.duckduckgo.com`、`api.duckduckgo.com` 全部超时),而 Bing 可用且很快。

| 引擎 | 需要 Key | 适用 |
|---|---|---|
| `bing`(默认) | 否 | 国内可用;走 RSS 结果端点,失败回退 HTML |
| `duckduckgo` | 否 | 免 Key,但国内多数网络不可达(报错时会提示你换 bing) |
| `tavily` | 是(`search.apiKey`) | 需要正式搜索 API 时用 |
| `brave` | 是(`search.apiKey`) | 同上 |

```powershell
# 关掉搜索工具
node bin/mcp-agent-bridge.js --search false

# 换成 tavily(需要 Key)
node bin/mcp-agent-bridge.js --search-engine tavily --search-key tvly-xxxx

# 自定义端点(内网镜像 / 自建搜索服务;{q} 与 {count} 会被替换)
node bin/mcp-agent-bridge.js --search-endpoint "http://10.0.0.9/search?q={q}&count={count}"
```

注意:

- `fetch_page` 是**静态抓取**(不执行 JS),SPA 页面可能只拿到很少内容——这种页面用 `run_powershell` 起无头浏览器,或直接换一个静态源
- 单次响应有大小上限(`search.maxBytes`,默认 2MB)与超时(`search.timeoutMs`,默认 20s)
- Bing RSS / DDG HTML 属于"给人看的搜索结果",请仅作个人非商业用途;要商用/正式集成就切到 `tavily` / `brave` 这类 API
- 控制台监控台都能改引擎与端点(热生效);`search.apiKey` 在监控台里只写不读(接口返回时已脱敏)

## 桥接"我的 Agent 的工具"

在配置文件 `agents` 数组里登记任意本地 MCP server,启动时会自动连接并代理其全部工具:

```json
{
  "agents": [
    { "name": "filesystem", "transport": "stdio",
      "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] },
    { "name": "my-http-server", "transport": "http",
      "url": "http://127.0.0.1:9000/mcp", "headers": { "Authorization": "Bearer xxx" } },
    { "name": "my-sse-server", "transport": "sse",
      "url": "http://127.0.0.1:9001/sse" }
  ]
}
```

网页端 Agent 调用:`agent_call_tool { server: "filesystem", tool: "write_file", args: {...} }`。每个 agent 可加 `"enabled": false` 暂时停用,`"timeoutMs": 120000` 控制调用超时。改完配置重启进程,或在监控台点"重连 Agents"。

## 监控台功能(http://127.0.0.1:7821,仅回环,不经隧道)

- **实时活动流**:每次工具调用(参数/结果/耗时/成败)、会话建立断开、认证失败、隧道状态、Agent 状态,SSE 秒推,可按类型过滤
- **会话表**:来源 IP(取自 CF-Connecting-IP)、User-Agent、连接时长、调用数、流量
- **审批队列**:manual 模式下危险操作挂起等你批准/拒绝(见下)
- **配置热更新**:rootDir、文件允许根(allowedRoots)、文件权限、PowerShell 模式与白名单、skill 目录、敏感模式、审批模式,改完即生效,无需重启
- **急停**:一键"暂停服务"(所有工具调用立即被拒绝)、"断开隧道"
- **审计日志**:所有事件落盘 `logs/audit-YYYY-MM-DD.jsonl`

## 本机 Agent 控制台(GUI,http://127.0.0.1:7822,仅回环)

一个浏览器里的"操作台":GUI 自身作为 **MCP 客户端**连到 bridge,因此它调用工具与网页端 Agent 走的是**同一条 MCP 通道**——同样的文件范围、命令策略(blocklist/allowlist)、审批与监控打点(监控台里能看到 `gui` 会话)。

> 这个控制台**不含内置模型**,也不再需要任何 API Key —— 大脑就是网页端模型,控制台负责"给它钥匙 + 让你看它在干什么"。

- **连接网页 Agent(核心)**:顶栏点 **「🔗 连接网页 Agent」**,一键生成连接提示词——已自动嵌入 MCP URL、访问令牌、文件范围(整机/指定根)、文件权限、PowerShell 与 SSH 规则、skill 用法、删除规则、审批模式、全部工具清单。复制后发给支持 MCP 的网页端模型(ChatGPT Apps & Connectors、Claude、Kimi 等),它就能连上来待命
- **接入本机 Agent**:顶栏点 **「🔌 接入本机 Agent」**,给出可直接粘贴的 MCP 客户端配置(回环 URL + Bearer)、Claude Code 命令行写法,以及一段"指挥方"说明(含省 token 规矩)——详见上面的[本机 Agent 接入](#本机-agent-接入多一个指挥方客户端)
- **任务板**:顶栏点 **「📋 任务板」** 看本机指挥方与网页端 Agent 的协作全貌(任务状态、谁在干、最新进展与结论、双方留言),也可以在这里直接写一句指令派活;有未完成任务时顶栏按钮会高亮并显示数量
- **实时活动流**:网页端 Agent 的每一次工具调用都以卡片形式秒级推送到界面(参数、结果、耗时、成败,可展开),与监控台同源
- **工具面板**:左侧列出全部工具与 JSON Schema 表单,点开即填参调用,用于调试和单次操作
- **范围条**:顶部一行常显当前 rootDir、文件范围(是否整机)、权限、PowerShell 模式、skill 目录、敏感文件策略、审批模式
- **审批**:`approval.mode = manual` 时,挂起的操作直接在活动流里弹出审批卡片,批准/拒绝后继续;也可在监控台统一处理
- **暂停/隧道状态**:顶栏徽章显示 MCP 连接、隧道、待审批数量与暂停状态

配置只有三个键(启动期配置,运行时不可热改;`transport = stdio` 时 GUI 自动关闭):

```powershell
# 配置文件 bridge.config.json
"gui": { "enabled": true, "host": "127.0.0.1", "port": 7822 }

# CLI
node bin/mcp-agent-bridge.js --gui on --gui-port 7822
```

### 为什么没有 API Key?

网页端模型自带推理能力,本工具只提供工具与通道,因此**不需要你配置任何 LLM Key**(`gui.llm`、`gui.systemPrompt` 以及 `BRIDGE_LLM_*` / `--llm-*` 等配置项已全部移除)。

1. **让网页端模型当大脑(推荐)**:控制台点 **「🔗 连接网页 Agent」** 拿到提示词 → 发给网页端模型。注意:网页模型要走公网隧道,启动时需加 `--public`(弹窗里也会提示)。
2. **纯手动工具模式**:左侧「工具」面板按 JSON Schema 填参调用,适合调试和单次操作。

> ⚠️ 连接提示词里包含明文访问令牌,等于把本机工具的钥匙交给收到它的模型——只发给你信任的服务,并在控制台/监控台留意其行为。

## 审批模式(推荐给敏感场景)

```json
"approval": {
  "mode": "manual",
  "timeoutMs": 60000,
  "requireFor": { "fileWrite": true, "fileDelete": true, "command": true, "agentCall": true }
}
```

manual 模式下,网页端 Agent 的写文件 / 删除 / 执行命令 / 调用 agent 工具会**挂起**,监控台"审批"页弹出卡片显示完整参数,你点"批准"才真正执行(超时默认按拒绝处理)。`auto` 模式则全自动执行,仅记录审计。

## 安全模型

- 默认"除删除外全部放开":文件 `read-write`、PowerShell 开启、本机 Skill 开启、文件范围整机;公网默认关,allowlist 白名单为空 = 全拒绝
- 公网暴露强制 Bearer Token(未提供则自动生成 64 位十六进制)
- 文件路径按 `files.allowedRoots` 判定:默认 `["*"]` = 整机可读写(**有意为之**,读取不受限);改成具体目录列表即恢复边界,越界仍会拒绝 `..` 逃逸与 symlink 逃逸
- `allowSensitive` 默认 `true`,即 `.env` / `*.pem` / `*.key` 等也可读;要恢复防护就设 `false`(此时命中 `sensitivePatterns` 的路径会被拒绝)
- **唯一被限制的能力是"删除"**:`delete_file` 是唯一删除通道(manual 模式下必须审批,且拒绝删除允许根本身);PowerShell 侧的删除/破坏性命令在本机与 SSH 远端一律拦截
- PowerShell 双模式:
  - **blocklist(默认)**:任意命令可执行,但删除/破坏性命令做**全链路拦截**——命令分段解析(管道/`;`/`&&`/`$()` 后的删除都算)、嵌套 shell 递归检查(`cmd`/`powershell`/`pwsh`/`bash`/`sh`/`wsl`/`python` 等,含 `-EncodedCommand` Base64 解码)、SSH 命令行分区检查(远端命令里的删除在连接前拦截)、常见破坏性 payload 模式(`docker rm`、`kubectl delete`、`find -delete`、`os.remove` 等);主机关机/重启与 `Invoke-Expression` 一律拒绝;裸 shell(无参,stdin 执行通道)拒绝
  - **allowlist**:仅白名单命令 + 元字符默认禁用
  - 两种模式都有超时与输出上限
- 监控台与 Agent 控制台都只绑定 127.0.0.1,不经过隧道
- Token 在配置接口中始终脱敏,认证失败也会记录来源 IP
- GUI 发起的工具调用与外部 Agent 同权限——受文件范围、命令策略(blocklist/allowlist)、审批门约束,且全部计入监控与审计

> ⚠️ 公网暴露本质上是把本机能力交给持有 token 的一方。请使用长随机 token、保持 manual 审批、定期看审计日志,不用时用监控台断开隧道。

## 配置

优先级:内置默认 < `bridge.config.json`(或 `--config`)< 环境变量 < CLI 参数。完整示例见 `config.example.json`。

| 键 | 默认 | 说明 |
|---|---|---|
| `rootDir` | cwd | 相对路径的解析基准,永远在允许范围内 |
| `files.allowedRoots` | `["*"]` | 文件工具范围;`["*"]` = 整机任意路径,也可写成 `["C:\\Users\\Administrator\\.workbuddy", "E:\\projects"]`(支持 `~`) |
| `permissions.files` | `read-write` | `read-only` / `read-write` / `write-only` / `none` |
| `permissions.powershell` | `true` | 是否启用 run_powershell |
| `permissions.agents` | `true` | 是否启用 agent 桥接工具(需在 `agents[]` 里登记才有可调用的 server) |
| `skills.enabled` | `true` | 是否注册 list_skills / read_skill |
| `skills.dirs` | 5 个常见目录 | skill 搜索目录(含 `SKILL.md` 的文件夹即一个 skill) |
| `skills.maxDepth` / `maxSkills` | 6 / 500 | 扫描深度与数量上限 |
| `search.enabled` | `true` | 是否注册 `web_search` / `fetch_page` |
| `search.engine` | `bing` | `bing` / `duckduckgo` / `tavily` / `brave` |
| `search.apiKey` | `null` | 仅 tavily / brave 需要(接口返回时脱敏) |
| `search.endpoint` | `null` | 覆盖引擎地址(`{q}`、`{count}` 占位符) |
| `search.maxResults` / `timeoutMs` / `maxBytes` | 6 / 20000 / 2000000 | 结果条数(1–10)、超时、单次响应上限 |
| `search.fetchMaxChars` | 8000 | `fetch_page` 默认返回的正文长度 |
| `board.enabled` | `true` | 是否注册协作任务板工具(`delegate_task` 等 7 个) |
| `board.file` | `./logs/board.json` | 任务板持久化文件(运行时不可改,需重启) |
| `board.maxTasks` / `maxMessages` | 200 / 200 | 保留上限(先淘汰最旧的已完成任务) |
| `transport` | `http` | `http`(远程)或 `stdio`(本地客户端) |
| `http.host/port` | `127.0.0.1:8080` | MCP HTTP 监听地址 |
| `public.enabled` | `false` | 启动 Cloudflare quick tunnel |
| `public.authToken` | 自动生成 | Bearer Token |
| `public.noAuth` | `false` | 关闭认证(危险) |
| `powershell.mode` | `blocklist` | `blocklist`(任意命令,删除/破坏性全链路拦截)/ `allowlist`(仅白名单) |
| `powershell.allowedCommands` | `[]` | 命令白名单(**仅 allowlist 模式生效**;cmdlet 名或 exe 名) |
| `powershell.allowShellMetachars` | `false` | 允许 `; \| & $ >` 等元字符(仅 allowlist 模式有意义;blocklist 下管道/重定向本就放行) |
| `powershell.timeoutMs` / `maxOutputBytes` | 30000 / 200000 | 超时与输出上限 |
| `agents[]` | `[]` | 桥接的本机 MCP server 列表 |
| `approval.*` | `auto` | 审批模式与超时 |
| `sensitivePatterns` / `allowSensitive` | 内置 / `true` | 敏感文件防护;默认 `true` = 可读,设 `false` 恢复拦截 |
| `dashboard.*` | `true, 127.0.0.1:7821` | 监控台 |
| `gui.enabled` | `true` | 本机 Agent 控制台(stdio 传输时强制关闭) |
| `gui.host/port` | `127.0.0.1:7822` | GUI 监听地址(仅回环,不经隧道) |
| `logs.dir` / `logs.maxEvents` | `./logs` / 500 | 审计日志目录与内存事件上限 |

常用 CLI:`--root` `--files` `--allowed-roots` `--skills on|off` `--skills-dirs` `--powershell` `--ps-mode blocklist|allowlist` `--agents` `--allowed-commands` `--search on|off` `--search-engine` `--search-key` `--search-endpoint` `--board on|off` `--board-file` `--public` `--auth-token` `--port` `--host` `--approval manual|auto` `--gui on|off` `--gui-port <n>` `--config <file>`;环境变量对应 `BRIDGE_ALLOWED_ROOTS`、`BRIDGE_SKILLS_DIRS`、`BRIDGE_SKILLS`、`BRIDGE_PS_MODE`、`BRIDGE_ALLOWED_COMMANDS`、`BRIDGE_SEARCH`、`BRIDGE_SEARCH_ENGINE`、`BRIDGE_SEARCH_KEY`、`BRIDGE_BOARD`、`BRIDGE_BOARD_FILE` 等。(已移除:`--llm-base-url` `--llm-api-key` `--llm-model` / `BRIDGE_LLM_*`)

## 常见问题

- **trycloudflare URL 每次重启都会变**:quick tunnel 的特性。要固定域名请用 `cloudflared tunnel` 绑定自己的 Cloudflare 域名,再把 `public.provider` 保持不变(本工具只封装 quick tunnel;固定域名可直接用系统 cloudflared 指向 `http.port`)。
- **命令被拒:not in the allowlist**:只在 allowlist 模式出现。把该命令加进 `powershell.allowedCommands`(监控台配置页可热改),或切回默认的 blocklist 模式(`--ps-mode blocklist`)。
- **`read_file` / `list_files` 报 `PathSecurityError`(以前读不到 C 盘)**:旧版本把路径锁在 rootDir 内。现在 `files.allowedRoots` 默认 `["*"]`,直接传绝对路径即可;若你手动改成过目录列表,把目标目录加进去,或改回 `["*"]`。报错信息里会直接告诉你该怎么改。
- **敏感文件读不了**:说明 `allowSensitive = false`。设成 `true`(默认值)即可读 `.env` / `*.pem` / `*.key` 等。
- **需要真正删除文件时**:`delete_file` 是唯一通道(manual 模式下会挂起等你批准);`rm` / `Remove-Item` / `del` 等命令在任何模式、任何位置(含 SSH 远端)都会被拦截。
- **`list_skills` 看不到某个 skill**:确认它所在目录在 `skills.dirs` 里、目录内直接放着 `SKILL.md`,且清单缓存 30 秒后过期;也可显式加 `--skills-dirs` 指向它。
- **为什么没有 API Key / LLM 配置了?** 控制台已内置模型能力移除,改为由网页端模型当大脑:点「🔗 连接网页 Agent」拿提示词即可。旧的 `--llm-*` 与 `BRIDGE_LLM_*` 参数已删除,配置里的 `gui.llm` / `gui.systemPrompt` 会被自动忽略。
- **Remove-Item / rm / del 一直被拒**:设计如此,两种模式下都拦截。删除请用 `delete_file`(审批门保护)。
- **为什么 ssh 远程执行 `rm` 会被拒绝?** SSH 命令行会被分成"本地参数"和"引号内的远端命令"两段分别检查,远端命令中的删除模式(`rm`、`rmdir`、`unlink`、`find -delete`、`sudo rm` 等)在建立连接之前就被本地策略拦截——这是有意为之,本工具不希望网页端 Agent 通过 SSH 删掉你远端机器上的东西。远端的非删除命令不受影响。
- **ssh 卡住直到超时**:大概率是交互式密码或主机指纹确认在等输入。请给主机配置公钥免密登录,并带上 `-o BatchMode=yes -o ConnectTimeout=10`。
- **Agent 连接失败**:看监控台 Agent 表的错误信息;stdio 方式确认 command/args 可在终端手动跑通。
- **本机 Agent 连上了,但任务板是空的 / 两边看不到对方**:确认本机 Agent 用的是 **HTTP 回环 URL**(`http://127.0.0.1:8080/mcp` + Bearer),而不是 stdio 另起的进程——只有连到同一个 bridge 进程才会共享同一块 `board.file`。用 `get_status` 看 `handoff` 里的 `total/open` 是不是同一个板子。
- **指挥方收不到完成通知**:`update_task` 的 `status` 要写 `done`/`failed`/`blocked` 才会自动发通知(只写 `note` 不会);通知发给 `delegate_task` 时的 `from`(默认 `local`),所以读取要用 `read_messages({to:"local"})`。
- **`web_search` 报错或没有结果**:默认走 Bing,国内可用;`engine=duckduckgo` 在国内多数网络会 `fetch failed`(报错信息里会提示换 bing)。公司网络需要代理时可换 `tavily`/`brave`(带 Key)或 `--search-endpoint` 指到内网搜索服务。
- **`fetch_page` 抓回来几乎是空的**:目标页是 JS 渲染的,静态抓取拿不到内容。换静态源,或用 `run_powershell` 起无头浏览器抓。
- **任务板文件在哪、会不会丢**:默认 `logs/board.json`(`board.file` 可改,但需重启),写入是"临时文件 + rename"的原子写,重启后自动恢复;`board.maxTasks` 满了会先淘汰最旧的已完成任务,未完成的保留。

## 目录结构

```
mcp-agent-bridge/
├── bin/mcp-agent-bridge.js     入口
├── src/
│   ├── index.js                启动编排
│   ├── config.js               配置(默认值/文件/env/CLI 合并校验)
│   ├── server.js               MCP server 组装 + 调用打点
│   ├── monitor.js              监控核心:事件/会话/审计/审批/统计
│   ├── security/               路径范围(allowedRoots)/ PowerShell 命令校验
│   ├── tools/                  files / powershell / skills / agent-bridge / handoff(任务板)/ search(搜索+抓页)
│   ├── transports/             Streamable HTTP (+stdio)
│   ├── tunnel/                 cloudflared 封装
│   ├── gui/                    Agent 控制台(MCP 客户端 + 活动流 + 连接提示词)
│   └── dashboard/              监控台(API + SSE + 前端)
├── config.example.json
└── test/                       e2e / gui / gui-approval / agents / ps-blocklist / tunnel
```

MIT License. 参考 [expose-files-mcp](https://github.com/egyjs/expose-files-mcp)(MIT)。