-
Notifications
You must be signed in to change notification settings - Fork 2
MCP Ecosystem
📑 本页目录
本页汇总 Android Guru Agent 与 MCP(Model Context Protocol) 的全部交界面: 把手机当客户端(连接外部 MCP 服务器获得新工具)、把手机当服务器(逆向 Host,让 PC 上的 AI 客户端调用手机工具)、以及围绕两者的官方仓库分发生态。 分模块实现细节见 工具系统 与 模块地图。
手机同时是 MCP 客户端与 MCP 服务器,npm 上的整个 MCP 生态都能装进口袋。
┌──────────────────────────────────────────┐
│ Android 手机 │
│ │
外部 MCP 服务器 │ Agent 引擎 ←→ ToolRegistry (~109 工具) │ PC AI 客户端
(HTTP/SSE/BUILTIN)│ ↑ 市场安装/斜杠门控 │ (Cline/Claude)
──────────────────→ │ [客户端方向] McpManager 四传输 │ ←──────────────────
│ ↓ 沙箱 STDIO 走 PRoot Ubuntu │ POST /mcp + Bearer
│ [服务器方向] McpHostServer :8765 │ (逆向 Host, LAN)
│ 白名单 + v3 执行管线同一门控 │
└──────────────────────────────────────────┘
↑ 官方目录分发
apex-mcp-hub / apex-skill-hub (GitHub 仓库)
设计原则一句话:安装 ≠ 启动(落盘 enabled=false,显式启动才计入"运行中"),
门控不旁路(外部调用与 Agent 内部调用走同一条 v3 执行管线:环境门 → 权限门 →
风险门 → schema 校验 → 限流 → 熔断)。
| 形态 | 方向 | 运行位置 | 依赖 | 一句话 |
|---|---|---|---|---|
| BUILTIN | 客户端 | App 进程内(进程内 transport) | 无(随 App 分发) | App 能力的 MCP 协议化:github / search / fs / memory / thinking 五台 |
| 远端 HTTP / SSE | 客户端 | 外部服务器 | 网络 | 连接社区或自建远端(如 deepwiki) |
| 沙箱 STDIO | 客户端 | PRoot Ubuntu rootfs 内真实子进程 | rootfs + nodejs |
npm MCP 生态的接入通道:npx -y @modelcontextprotocol/server-*
|
| 逆向 Host | 服务器 | 手机 0.0.0.0:8765
|
局域网 | PC 客户端把手机当 MCP Server 调用(§5) |
| Hub 目录 | 分发 | GitHub 官方仓库 | 无 | 市场页直连 apex-mcp-hub / apex-skill-hub 按需安装 |
Note
BUILTIN 与沙箱 STDIO 的关键差异:前者是进程内代码直接应答 JSON-RPC(零依赖、
启动即连接),后者是 rootfs 内的真实 node 子进程(任意 npm server、有冷启动成本)。
官方预置语义也不同:BUILTIN ensureBuiltinServer(启动即自动连接),沙箱
ensureSandboxServer(只预置,手动启用)。
MCP 官方生态绝大多数 server 是本地命令(command + args,如
npx -y @modelcontextprotocol/server-filesystem /tmp),靠 stdin/stdout 的
换行分隔 JSON-RPC 通信 —— 并不需要真正"一台服务器"。问题在于 Android 的
app 进程里没有 node/npx/python。
沙箱 MCP 把这条命令放进 App 内嵌的 PRoot Ubuntu rootfs 里执行(完整 rootfs
已预装 nodejs/npm),宿主与沙箱进程之间仍然走同样的 stdio 管道 —— 上层协议零
变化。对应配置字段 McpServerConfig.runInSandbox(默认 false = 宿主直接
fork,桌面 JVM 行为不变;@Serializable 默认值保证旧配置向后兼容)。
| 入口 | 用法 |
|---|---|
| 市场页添加对话框 | 「市场 · MCP · 添加工具源」选本地命令形态,出现「在 PRoot 沙箱中运行」开关(rootfs 就绪时默认开启;未就绪禁用并提示先装 Ubuntu) |
Agent 工具 mcp_connect
|
参数加 "run_in_sandbox": true(可选,默认 false;Android 上 STDIO 建议开启) |
| 批量导入配置 | 社区通用 {"mcpServers": {...}} JSON 的条目里写 "runInSandbox": true(严格 Boolean,缺失落 false) |
- 终端页安装 Ubuntu(或设置里初始化),见 Ubuntu rootfs 供给;
- 完整 rootfs(
scripts/build_full_rootfs.sh构建)已预装 nodejs/npm 并全局 预装三台官方 server,开箱即用;最小 rootfs 需apt install -y nodejs npm。
npx -y <pkg> 首次运行要在线下载包,移动网络下可能远超 1 分钟,因此沙箱
连接握手/请求超时单独放宽:宿主 STDIO/HTTP/SSE 60s 不变,沙箱 STDIO 180s
(McpManager.SANDBOX_REQUEST_TIMEOUT_MS)。未就绪就启用/连接不会崩 ——
ProotMcpProcessLauncher 给出引导性报错(提示先装 Ubuntu + nodejs)。
Tip
完整 rootfs 已预装三台官方服务器(fs-sandbox / memory-sandbox /
everything-sandbox),冷启动基本消掉;自建条目首次连接仍可能慢,属正常现象,
二次连接走 npx 缓存。
v1.4.4 起(PR #246),技能与 MCP 从「全量内置」演进为「少量必要内置 + 官方仓库 按需安装」:内置技能 75 → 13 瘦身(8 coding + 3 agent + 2 all),其余全部 迁入两个 GitHub 仓库,市场页直连安装。
| 仓库 | 内容 | 结构 |
|---|---|---|
AceGuru-mjh/apex-skill-hub |
62 个技能 manifest |
index.json 只放元数据(id/name/version/scope/tags…),正文按需单文件下载 |
AceGuru-mjh/apex-mcp-hub |
8 台 MCP 服务器配置 | 单文件设计:配置内联在 index.json 的 servers[](几百字节/条,一次拉全目录) |
apex-mcp-hub 收录的 8 台:
| 名称 | 形态 | 作用域 | 说明 |
|---|---|---|---|
fs-sandbox |
npx 沙箱 | coding | 官方 filesystem 服务器(/workspace) |
memory-sandbox |
npx 沙箱 | agent | 官方知识图谱记忆 |
everything-sandbox |
npx 沙箱 | coding | 官方测试服务器(全能力面) |
context7 |
npx 沙箱 | coding | 库文档实时检索(Upstash) |
sequential-thinking |
npx 沙箱 | all | 官方顺序思考链 |
fetch |
npx 沙箱 | agent | 官方网页抓取 |
time |
npx 沙箱 | all | 官方时间服务 |
deepwiki |
HTTP 远端 | all | DeepWiki 仓库问答(免沙箱) |
Note
市场页还支持 mcp.so 社区目录直装(PR #249:解析详情页 mcpServers
配置 → 一键落盘为本地条目),与官方仓库互补。
为什么「安装 ≠ 启动」(学习 opencode 的 enabled:false 预置语义):沙箱 MCP
启动有真实成本(npx 冷启动 + rootfs 门禁);显式启动让「正在运行」状态对用户
可预期,斜杠门控才站得住。为什么保留 5 台 BUILTIN:能力在二进制里(github
REST / 搜索 / 工作区文件 / 记忆图谱 / 思考链),属于「必要内置」。
手机作为 MCP Server(Issue #173,v1.4.0 落地,模块
platform/mcp-host 纯 Kotlin JVM 零第三方依赖):PC 上的 AI 客户端
(Cline / Claude Desktop / 其它支持 streamable HTTP 的 MCP 客户端)通过
局域网 HTTP 调用手机上的工具 —— 与既有客户端方向互为逆向。
┌─────────────────┐ LAN HTTP (streamable 子集) ┌──────────────────┐
│ PC AI 客户端 │ ──────────────────────────────────▶ │ Android 手机 │
│ Cline / Claude │ POST /mcp + Bearer Token │ McpHostServer │
│ │ ◀────────────────────────────────── │ (0.0.0.0:8765) │
└─────────────────┘ JSON-RPC 2.0 响应 └────────┬─────────┘
白名单过滤
│
v3 执行管线
(环境门→权限门→风险门
→schema→限流→熔断)
│
ToolRegistry
(~109 工具)
| 客户端动作 | Host 行为 |
|---|---|
POST /mcp(initialize) |
200 + result{protocolVersion:"2024-11-05", capabilities{tools{listChanged:false}}, serverInfo{…}},响应头带 Mcp-Session-Id
|
POST /mcp(notifications/initialized 等通知) |
202 Accepted 空体 |
POST /mcp(tools/list,须带会话头) |
200 + result{tools:[{name,description,inputSchema}]}
|
POST /mcp(tools/call {name,arguments}) |
成功 result{content:[{type:"text",text}],isError:false};业务失败 isError:true;未知/未暴露工具 → -32602
|
POST /mcp(ping) |
200 + 空 result{}
|
GET /mcp |
405(无服务器推送流 —— spec 允许) |
DELETE /mcp(带会话头) |
会话已知 → 200 并移除;未知 → 404 |
每请求一连接(Connection: close);畸形请求 400,JSON 解析失败 -32700,
信封不合规 -32600,未知方法 -32601。
-
Token 鉴权:
Authorization: Bearer <token>,32 位 SecureRandom(~190 bit 熵);MessageDigest.isEqual常时比较防时序攻击;未配置 token = 拒绝所有 请求(fail-closed)。Token 可在 UI 重新生成(已连客户端下次请求即失效)。 - 限速 + 边界:每远程地址每分钟请求上限(固定窗口,默认 60,超限 429); 请求体 ≤1 MiB;头行 ≤16 KiB;并发连接 ≤64(超限 503);读超时 30s。
-
白名单 + 权限门:
- 分类白名单(默认
UTILITY/FILE/WEB/SYSTEM/SENSOR/MEMORY/CONTEXT只读友好集; SHELL/TERMINAL/APP/UI/GITHUB/SECURITY 默认关); - 工具黑名单(
vault_*、share_content等); -
vault_*硬拦截写死在 Bridge —— 安全红线:金库密钥绝不经外部 AI 通道出入; -
tools/list与tools/call用同一判定,无「列表不含但可直调」漏洞; - 外部调用经 v3 执行管线(含 SecretRedactingExecutor 脱敏)—— 与 Agent 内部 调用同一门控链,MCP Host 不旁路任何工具门控。
- 分类白名单(默认
手机与 PC 同一局域网;应用内「市场 → MCP → MCP Host」开启开关,复制 token。
Cline(cline_mcp_settings.json):
{
"mcpServers": {
"android-guru": {
"url": "http://<手机IP>:8765/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}Claude Desktop 经 mcp-remote 连接器接入同一 URL。UI 的「如何连接」折叠区会
自动填入本机局域网 IP 与当前端口/Token。
Warning
v1 如实声明局限:App 存活期可用(无前台服务,进程被杀即终止);无 SSE
推送流;每请求一连接(无 keep-alive);HTTP 明文(局域网可信前提下可接受,
公网/不可信网络请勿开启)。测试覆盖 79 个用例(platform/mcp-host/src/test/,
含真实端口集成测试:401/404/405/429/DELETE 终结/审计断言)。
| 入口 | 可见条件 | 拦截行为 |
|---|---|---|
| 斜杠 Skills 分组 | installed && enabled |
未装/未启的不出现(引导去市场) |
| 斜杠 MCP 分组 |
connected(= installed + enabled + running) |
空类目显示「暂无运行中的 MCP」hint |
/mcp:<id>(手输) |
— | 未运行 → systemMessage 引导 + 空 prompt 不执行 |
/mcp:github(手输) |
Token 或已连接 | 未连接 → GithubTokenDialog 信号 |
| Hub MCP 安装 | 目录可见 | 落盘 enabled=false;已有同名不覆盖 |
| MCP 启动 | enabled |
真实连接管线(进度弹窗 + tools/list 发现);沙箱未装 rootfs → 引导性报错 |
安装幂等语义:同名条目已被你自建为宿主条目(runInSandbox=false)→ 绝不
覆盖;已是沙箱条目 → 升级后按新定义刷新 command/args,但保留你的 enabled
偏好。
| 工具 / 命令 | 作用 |
|---|---|
mcp_connect |
连接一台 MCP 服务器(run_in_sandbox 可选参数) |
mcp_list |
列出已连接服务器的工具清单 |
mcp_call |
调用指定服务器的指定工具 |
/mcp:<id> 斜杠 |
把某台运行中的 MCP 服务器设为当前会话主力(未连接自动引导连接流程,GitHub 有 Token 对话框特殊路径) |
传输四选一:HTTP / SSE / STDIO / BUILTIN(core/tool-registry 的
McpManager + McpClient)。配置导入支持社区通用 {"mcpServers": {...}}
JSON 格式(McpConfigImport)。
| 症状 | 原因与解法 |
|---|---|
fs-sandbox 连接报错说目录不存在 |
server-filesystem 要求作用域目录存在。完整 rootfs 已带 /workspace;旧 rootfs 可把 args 的 /workspace 改成 /root(沙箱 home,必然存在) |
| 想给沙箱 server 配 API Key | 条目的 env 字段(对话框「环境变量」每行 KEY=VALUE)经 proot -E 传入沙箱 |
| 沙箱连接超时 | npx 冷启动在线下载,首次最长 180s;确认 rootfs 内有 nodejs/npm(完整 rootfs 开箱即用) |
| PC 连不上逆向 Host | 同一局域网?Token 复制完整?端口默认 8765;Authorization: Bearer 头格式正确 |
| 斜杠里看不到某台 MCP | 门控只列 connected(installed + enabled + running)—— 去市场页完成 安装 → 配置 → 启动 全流程 |
| BUILTIN 行没有配置按钮? | v1.4.4 起所有 MCP 行(含 BUILTIN)都有「配置」:作用域 / 启停 / 连接 / GitHub Token |
- 工具系统 —— MCP 四传输在工具注册表中的位置与 v3 执行管线
- 技能与斜杠命令 —— 斜杠门控与技能生态
- 终端运行时 / Ubuntu rootfs 供给 —— 沙箱的底层
- 安全与隐私 —— vault 硬拦截与密钥存储
-
模块地图 ——
platform/mcp-host与core/tool-registry的分工
-
MCP 生态总览
新 - (沙箱 MCP · 官方 Hub · 逆向 Host · 门控语义)
- 终端运行时
- 终端 API 契约
- SDK 边界
- Termux 能力矩阵
- Ubuntu rootfs 供给
- Ubuntu 生命周期
- PRoot 二进制溯源
- VT100/ANSI 模拟器
- 终端性能
- 终端迁移
- 原生层 C++/JNI