最近一直在折腾 MCP(Model Context Protocol,模型上下文协议),准确说是折腾 mobile-mcp——把 MCP 这一整套“AI 调用外部工具”的协议搬到手机端。电脑上接 MCP 已经不算新鲜,Claude Desktop、Cursor、各种 IDE 都能通过 MCP 读文件、调浏览器、跑命令;但到了手机端,我发现大多数人还在用最原始的方式:要么让 AI 干聊,要么每个功能单独写一套接口。mobile-mcp 要解决的,就是让手机里的 AI 也拥有同等的“工具调用”能力,让手机上的备忘录、日历、剪贴板、浏览器、乃至各种 App 能力,都能变成 AI 可以按标准协议调用的资源。
这篇文章是我把 mobile-mcp 从零到一完整跑通之后的实操记录。我会先讲清楚 MCP 在移动端到底解决了什么,再给出手机获取 MCP 服务的三种路径,然后是一步步的真实连接步骤和代码,最后是高频问题排查和避坑经验。适合正在做手机 AI 应用、端侧智能体、自动化脚本的开发者参考,也适合那些在电脑上已经用了 MCP、想把手头服务扩展到手机端的朋友。
1. 手机上的 AI 为什么连不上 MCP
1.1 手机 AI 的“工具调用”困境
在电脑上装了 MCP 之后,AI 能读文件、能操作浏览器、能连数据库,体验几乎是“满血”的。可到了手机端,AI 助手立刻变回了那个只会聊天的“嘴强王者”。你让它查一下本地备忘录里的待办、让它把当前屏幕上的文字提取出来、让它帮忙在某个 App 里完成一个操作,它基本无能为力。
这不是模型能力的问题,而是手机这个环境天然不友好。手机 App 之间数据隔离严格,iOS 和 Android 都有沙箱机制,一个 App 不能随意读取另一个 App 的数据;系统对后台进程和长连接的限制又非常多,想维持一个常驻的“驱动进程”非常困难;再加上权限管控(相册、剪贴板、定位、通知),每一项都要求用户单独授权。这些现实约束导致手机上的 AI 很难像电脑一样直接操作本地工具。
所以在很长一段时间里,手机 AI 只能走“厂商内置插件”路线:官方做了哪个功能,AI 才能调用哪个功能。今天接一个天气接口,明天接一个翻译接口,后天再接一个备忘录用例,每个接口都要单独写适配代码,累不累?累。而且这套方案没有标准化,换一个 AI 助手或者换一个平台,全部推倒重来。
1.2 MCP 到底在解决什么
MCP(模型上下文协议)不是一门新的编程语言,也不是一个具体的软件库,它是一个关于“AI 如何调用工具”的通信协议。它把工具、数据能力和 AI 模型解耦:工具提供方只要实现 MCP 服务端,AI 客户端只要实现 MCP 客户端,两边就能通过标准消息格式对接,而不再需要为每一个工具单独开发集成。
打个比方:以前每换一台打印机,电脑都要装对应的驱动,而且不同品牌驱动还不兼容。MCP 做的就是“统一打印机驱动规范”,只要设备支持这个规范,插上就能打印。电脑上的 MCP Host 发展很快,Claude Desktop、Cursor、VS Code 里的各种 AI 插件都在支持 MCP,生态已经相当热闹:Playwright MCP、Chrome DevTools MCP、Figma MCP、甚至 Blender 和 Unity 的 MCP 都有人在做。但 mobile-mcp 关注的是另一个问题:手机端怎么接入这套生态。
1.3 mobile-mcp 的核心思路
mobile-mcp 的典型架构并不复杂:手机端作为 MCP Host 发起连接,MCP Server 放在云端或者局域网的一台电脑上,两边通过 WebSocket 通信。手机端不需要去跑重的服务进程,只需要一个支持 WebSocket 的客户端环境(手机浏览器、App 内嵌 WebView,或者 SSH 客户端)就够了。
这样做的好处很明显:手机端轻量化,几乎任何手机都能运行;服务端集中管理,工具升级、权限控制都在一处完成;同时打通了电脑和手机两端——电脑上能调的 MCP 工具,手机通过同一个协议也能调。这也正是我推荐所有想做手机 AI 自动化的人,先以“远端 MCP Server + 手机 WebSocket 客户端”起步的原因。
2. 动手前先搞清楚 MCP 这一层:协议角色与传输选型
2.1 三个角色:Host、Server、Client
MCP 架构里的术语不多,但很容易混,尤其是 Host 和 Client 的区别。我用自己的理解来说:
- MCP Host:即“发起 AI 交互的主程序”,比如电脑上的 Claude、手机上的 AI 助手 App、某个聊天界面。Host 是用户直接打交道的对象。
- MCP Client:Host 内部负责和 MCP Server 建立连接、发请求的组件,和 Server 是一对一连接。
- MCP Server:对外暴露工具能力,比如一个提供天气查询的服务、一个控制浏览器的服务、一个操作数据库的服务。
手机上跑 mobile-mcp,并不需要单独安装一个“MCP Host App”去连接各种服务,而是你的手机客户端里内置了 MCP Client 的逻辑。手机端负责收集用户指令、把指令连同工具描述一起发给大模型,大模型决定调用哪个工具后,手机端再通过 MCP 协议向服务端发起tools/call请求。整个过程里,手机是“大脑”和“遥控器”,服务端是“手和脚”。
2.2 传输方式怎么选:stdio、HTTP/SSE、还是 WebSocket
MCP 协议本身并不限定传输层,目前主流有三种:stdio、HTTP+SSE、WebSocket。给不熟悉的朋友做一个对比:
| 传输方式 | 特点 | 适合场景 | 移动端评价 |
|---|---|---|---|
| stdio | 通过标准输入输出在本地进程间通信 | 电脑本地的 CLi 工具、本机服务 | 不适用,手机上很难也有没有意义 |
| HTTP + SSE | 单向请求-响应,服务端可推流 | 简单查询类工具、一次性任务 | 能用,但双向性弱,交互类场景别扭 |
| WebSocket / WSS | 双向实时通信,长连接 | 需要频繁交互、AI 实时调用多个工具 | 首选,双向连接对 MCP 的 JSON-RPC 消息最自然 |
我在实际测试中基本只用 WebSocket(加密版是 wss)。原因很简单:MCP 的请求-响应模型是 JSON-RPC 2.0,一条initialize请求对应一条响应,一次tools/call调用也可能有持续的数据返回,用 WebSocket 的话,连接建立后两边随时可以发消息,状态保持也方便,和手机网络环境也比较匹配。
2.3 为什么公网服务一定要上 wss
如果你只是本地调试,ws://127.0.0.1:8080没问题。但要让手机从外部网络连接你的 MCP 服务,就必须用wss://,也就是 WebSocket over TLS。原因有两个:第一,明文 WebSocket 在公网上等于裸奔,中间任何节点都可以截获你在 MCP 传输的 token 和工具调用内容;第二,很多公共 WiFi、运营商网络会直接拦截非 443 端口的 WebSocket 流量,用 wss 走 443 端口,被拦的概率小得多。
实际搭建时,可以用 Nginx 或 Caddy 做 TLS 终止,把外部 443 端口转发到本地的 MCP Server 端口。Caddy 配置尤其简单,它自动申请和续期证书,十几行配置就能搞定一个带 TLS 的 WebSocket 代理。
3. 手机获取 MCP 服务的三种路径与真实连接步骤
3.1 路径一:直接申请一个现成的 MCP 平台
对于大多数想快速体验、不想自己维护后端的人来说,这是最省事的一条路。我拿“小智 MCP 平台”举例,这类平台本质上是一个托管的 MCP Server 网关,你注册后在控制台创建一个应用,平台会分配一个 WebSocket 连接地址,格式类似:
wss://api.xiaozhi.me/mcp/?token=YOUR_TOKEN注意,token 是你在平台控制台申请到的密钥,属于敏感信息。我见过不少人直接把真实 token 贴进前端代码、测试帖子和公开仓库里,这是非常糟糕的习惯。下面所有示例中我都用YOUR_TOKEN占位,你实际操作时把它换成自己申请到的 token 即可。
拿到连接地址后,先在电脑浏览器里验证一下服务是否可用,用任何支持 WebSocket 的在线工具或者直接在浏览器控制台测试。建连之后第一件事是发initialize请求完成握手,然后发tools/list查看可用的工具列表。
3.2 路径二:用 Node.js 自建一个 MCP Server
如果手头有自己的 API、数据或者设备资源,自建 MCP Server 是更可控的选择。官方提供了 TypeScript SDK,可以快速起步:
npm create @modelcontextprotocol/server cd my-mcp-server npm install npm run start生成的骨架里包含一个示例工具。假设我们要暴露一个“查询明日天气”的工具,在server.ts里大致是这样:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; const server = new McpServer({ name: 'mobile-weather-server', version: '1.0.0', }); server.registerTool( 'get_weather', '根据城市名查询明日天气', { type: 'object', properties: { city: { type: 'string', description: '城市名,如 北京' } }, required: ['city'] }, async ({ city }) => { // 这里替换成真实的天气 API 调用 return { content: [{ type: 'text', text: `${city} 明日多云,20-28°C` }] }; } );这个骨架默认走 stdio 传输,适合电脑本地用。要让手机能连上,实际部署时还需要在服务外再包一层 WebSocket 传输适配器,或者直接使用支持 WebSocket 的 MCP SDK 方案。比较省事的方式还是用 npx 工具或者手写一个 WebSocket 服务,把 MCP 的 JSON-RPC 消息转发到上面的 Server 逻辑。
3.3 路径三:把已有 HTTP API 转成 MCP 服务
这个思路在团队内部特别实用。你现在手里可能有一堆 Swagger/OpenAPI 文档,这些文档本身已经描述了所有接口路径和参数。社区里已经有不少“OpenAPI to MCP”的转换工具,输入一份 Swagger JSON,直接生成一个 MCP Server。这样手机 AI 就可以直接用自然语言去调这些接口。
操作上大概是:先把 Swagger JSON 下载下来,然后跑一个转换工具,生成 MCP Server 代码,部署到服务器上,用 wss 暴露,手机端连接。整个过程半天内能完成,改造成本比逐个手写工具调用低一个数量级。这也是为什么“swagger 转 mcp”能成为热词——因为大量团队都有存量 API,这个路径几乎零成本接入。
4. 实操记录:从零把 mobile-mcp 跑起来
4.1 在浏览器控制台手动完成 MCP 握手
我的建议是:在写正式的 App 代码之前,先用浏览器控制台手动测试一遍协议流程,这能帮你直观看懂 MCP 的消息交换过程。下面是我真机操作时的完整步骤。
打开任意 HTTPS 网页,按 F12 打开控制台,执行:
const ws = new WebSocket('wss://api.xiaozhi.me/mcp/?token=YOUR_TOKEN'); ws.onopen = () => { console.log('连接已建立'); ws.send(JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2025-03-26', capabilities: {}, clientInfo: { name: 'mobile-mcp', version: '0.1.0' } } })); }; ws.onmessage = (event) => { console.log('收到:', event.data); };如果一切正常,你会收到一条initialize响应,返回结果大概长这样:
{ "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2025-03-26", "capabilities": { "tools": {} }, "serverInfo": { "name": "xiaozhi-mcp-server", "version": "1.0.0" } } }initialize是 MCP 协议的第一步,目的是协商协议版本和确认双方能力。收到响应后,按协议要求还要发一个notifications/initialized通知,表示客户端已经初始化完成:
ws.send(JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized', params: {} }));4.2 查看可用工具并调用
握手成功后,发tools/list请求查看服务端有哪些工具:
ws.send(JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} }));服务端会返回一个工具数组,每个工具的定义包含name、description和inputSchema。我当时看到平台提供的工具里有search_notes、send_message、get_weather、open_webpage这一类的能力。工具描述里的大模型友好字段非常重要,因为 AI 就是靠这份描述来决定什么时候调用这个工具的。
假设我们要调用search_notes,请求是:
ws.send(JSON.stringify({ jsonrpc: '2.0', id: 3, method: 'tools/call', params: { name: 'search_notes', arguments: { keyword: '会议' } } }));返回结果大致是:
{ "jsonrpc": "2.0", "id": 3, "result": { "content": [ { "type": "text", "text": "找到 3 条和「会议」相关的备忘录" } ], "isError": false } }就这么三步,一个完整的 MCP 工具调用就完成了。你可能会疑惑:这不就是一个 WebSocket 接口吗?和普通 REST API 有什么本质区别?区别在于,这个接口的“工具描述”和“入参结构”是协议标准化的,AI 可以直接理解并自动组装调用,而不是在代码里写死某个函数。换一个服务端、换一套工具,客户端逻辑可以基本不变,这就是标准化的价值。
4.3 从浏览器控制台升级成一个极简手机 Agent
手动测试通过之后,我把它封装成了一个手机网页版小助手。整个页面逻辑只有三层:
第一层是用户输入框,用户用自然语言提交需求,比如“帮我查北京明天的天气,如果下雨就提醒我带伞”。
第二层是工具注册表:页面加载时先连 WebSocket,发tools/list拿到所有可用工具,把工具的 name、description、inputSchema 原样保存下来。
第三层是大模型调度:把工具注册表连同用户输入一起提交给大模型。模型返回的可能是一个普通回复,也可能是一个“需要调用工具”的请求——即返回一个结构化的 JSON,里面包含工具名和参数。页面拿到这个 JSON 后,再通过 WebSocket 发tools/call,拿到结果后把结果回填给模型,让模型生成最终回复。
用这种方式,原本需要写一大堆业务逻辑的“查天气-做判断-提醒带伞”流程,变成了完全由 AI 动态决定调用哪一步。手机上跑起来后,基本就是一个轻量 Agent 雏形。
4.4 直接让手机原生 App 能力变成 MCP 工具
如果你的手机端是原生 App(不是网页),那还可以更进一步:把手机本地的剪贴板、日历、相册、传感器等能力,通过 bridge 暴露给页面里的 MCP Client。具体做法是在 App 的 WebView 里注入一个 JavaScript 桥接对象,MCP Client 在执行tools/call时,发现目标是本地能力,就调用桥接函数,从原生层拿到数据后返回。
我试过一个场景:让手机 AI 把当前剪贴板里的快递单号提取出来,调用快递查询工具,再把结果整理成一段话回复。整个过程里,剪贴板读取是原生能力,快递查询是远端 MCP Server 工具,最后由大模型组织语言。这种“本地能力 + 远端工具”混用的模式,是 mobile-mcp 区别于纯网页版的最大价值。你完全可以把手机定位、通讯录(注意权限合规)、相册 OCR 都封装成本地工具注册进 MCP 工具表,让 AI 统一调度。
5. 进阶玩法:让 MCP 连接浏览器、设计稿和已有 API
5.1 Playwright MCP 和 Chrome DevTools MCP,手机上怎么用
这两个热词是浏览器自动化领域里最常被对比的。简单说:
- Playwright MCP:启动一个由 MCP Server 控制的浏览器实例,AI 可以打开网页、点击、输入、截图,适合自动化测试和数据采集。
- Chrome DevTools MCP:直接连接开发者在用的 Chrome 浏览器,通过 CDP(Chrome DevTools Protocol)控制真实页面,适合调试、查看网络请求、实时修改页面。
手机上怎么用呢?我采用的方案是在一台常开的电脑或云主机上分别跑这两个 MCP Server,开放对应端口,然后在手机上用 mobile-mcp 客户端去远程连接。手机下发指令,电脑端浏览器执行。这相当于手机拿到了一个“远程浏览器遥控器”。夜间躺在床上调试网页,连电脑都不用开,手机就能指挥云主机跑完整个自动化流程,实测体验相当流畅。
5.2 VSCode 里配置 Figma MCP,手机远程引用设计稿
“vscode 配置figma mcp 不是在claude 中运行的吗”是另一个高频问题。答案是:MCP Server 和 MCP Host 是解耦的,Figma MCP Server 既可以被 Claude 桌面版连接,也可以被 VSCode 里的 AI 插件连接。VSCode 里一般通过配置文件声明 MCP Server 地址,类似:
{ "mcp": { "servers": { "figma": { "command": "npx", "args": ["-y", "figma-developer-mcp", "--stdio"], "env": { "FIGMA_API_KEY": "你的key" } } } } }手机端想“借用”这样的设计稿能力,思路还是远程化:把 Figma MCP Server 部署在一台机器上,以 wss 方式暴露,手机端挂载后,AI 就能读取图层名、尺寸、颜色,甚至让 AI 根据设计稿生成一段还原度还不差的代码。对经常在外面改稿的设计师和前端来说,这个场景相当实用。
5.3 各行业 MCP 生态速览
这一轮热词里出现了大量垂直工具的 MCP:Blender MCP、Unity MCP、QGIS MCP、同花顺 MCP、Cheat Engine 桥接 MCP、Burp Suite MCP 等等。逐一展开讲篇幅不够,我直接给结论:
- Blender MCP / Unity MCP 说明 MCP 已经进入了三维创作工具,AI 可以修改场景对象、材质参数、甚至驱动渲染流程。
- QGIS MCP 是地理信息系统方向,可以让 AI 查询图层、导出地图,做空间分析。
- 同花顺 MCP 这类金融行情服务,让 AI 获取行情数据、做基础分析变得标准。
- Cheat Engine 桥接 MCP、CTF skill 相关的 MCP 更多是游戏调试和网络安全竞赛圈子的探索。
- Burp Suite MCP 是把 Burp Suite 的代理流量、扫描能力暴露给 AI,适合有授权的安全测试自动化场景。
这些项目共同说明一件事:MCP 生态正在从“文本框工具”走向“通用设备操作”。今天 AI 能控制的还是软件工具,明天可能就是你家里那台打印机、那盏智能灯。mobile-mcp 的定位,就是让这些能力在手机端也能触手可及。
6. 高频问题排查:从连接失败到日志混乱
6.1 连接失败排查清单
手机端连不上 MCP 服务,是新手最常遇到的问题。我整理了一个排查清单:
| 症状 | 可能原因 | 处理方式 |
|---|---|---|
| WebSocket 一直 CONNECTING | 地址写错、token 失效、网络拦截 | 先在电脑端用 curl 或在线工具测试同一地址;检查 token 有效期 |
| 连接后收不到 initialize 响应 | 协议版本不匹配;服务端不接受该客户端 | 检查 protocolVersion 是否在服务端支持的范围内 |
| 握手成功但 tools/list 为空 | 服务端没有任何工具;权限不足 | 换一个平台账号或检查 token 是否被授权了工具权限 |
| 调用工具返回 permission denied | token 权限不够 | 到平台控制台申请对应工具的作用域 |
| 连接一建立就被断开 | 没有发 initialize 或 initialized 消息 | 严格按握手流程走,缺一步服务端都可能主动断开 |
需要特别提醒的是:很多平台的 token 有时效性,有的只有几小时。如果今天能连、明天不能连,先查 token 是不是过期了,不要盲目怀疑代码。
6.2 心跳、重连与移动网络切换
MCP 协议本身没有规定心跳机制,但移动端 WebSocket 长连接如果没有心跳,非常容易被运营商或系统杀掉。实测下来,30 秒发一个文本 ping 比较稳定,连续三次没有 pong 就主动关闭重连。重连之后必须重新发initialize和notifications/initialized,不能直接发tools/call,否则服务端会返回 session 相关错误。
另外一个容易踩的坑是网络切换。手机从 WiFi 切到 4G/5G 时,网络出口 IP 和链路都会变化,原有 WebSocket 连接通常会断。这不是你的代码问题,是 TCP 链路断了。处理方式是监听页面的 online/offline 事件,在 autoReconnect 逻辑里重置重试次数,并且增加退避策略:前几次 1 秒、3 秒、5 秒重连,后续每次翻倍,最大不超过 60 秒。避免在网络不稳定的情况下疯狂重连打爆服务端。
6.3 服务端日志:别让 console.log 毁了协议消息
这是我特别想强调的一个实战经验。MCP Server 在 stdio 模式下,协议消息走的是标准输入输出,如果你在服务端代码里用了console.log打印调试信息,这些内容会被 MCP 的传输层当成协议数据发给客户端,直接把 JSON-RPC 消息流搞乱。我见过不止一次,服务端跑得好好的,加了两行日志后客户端直接开始报解析错误。
正确做法是把日志写进专门的文件,或者用支持独立输出的日志库。写 Node.js 服务时,我习惯用 pino 或 winston,并且把 stdout 完全保留给 MCP 协议消息。如果需要查看实时日志,记录日志到文件后tail -f即可。这也是热词里“mcp server端的日志如何使用自定义日志管理”这个问题的核心答案:第一原则是协议通道和日志通道分离,第二原则是日志文件按天滚动,避免单文件过大。
6.4 安全注意事项:token 与最小权限
把 MCP 服务暴露到公网,安全边界一定要想清楚。首先是 token 管理:不要把 token 直接写死在手机 App 的本地代码里,因为逆向一个 APK 太容易了。更合理的做法是让手机 App 先请求你自己的后端,由后端动态下发短期 token。其次是工具权限:如果在平台或自建服务端支持按工具授权,就只开放必须用到的那几个工具,不要一股脑把全部工具都暴露给手机端。最后是会话结束后回收连接:一些平台支持按会话频率限制或过期时间,及时断开能减少被刷的风险。
我在实操中见过一个案例,有人把平台 token 写进了一个公开的演示网页,结果当天 token 就被机器人拿去刷了一整晚的工具请求。所以,演示页面、公开仓库、技术文章里,任何 token 都必须打码或使用占位符,这个习惯要刻进肌肉记忆。
最后再分享一个我踩了几次坑才想通的细节:手机端 MCP 最难的其实不是协议本身,而是让用户愿意在手机上把工具调用权交给 AI。电脑上你信任本地程序,所以愿意让 AI 读文件;手机上涉及剪贴板、备忘录、短信这些隐私敏感的数据,一旦 AI 出错调用,用户会立刻产生不信任。所以做 mobile-mcp 相关的产品,一定要在首次连接时明确告知用户“AI 能调用哪些工具、调用数据会发到哪个服务端”,最好还要提供细粒度的开关。技术协议再标准,最终还得回到“用户敢不敢用”这个问题上。先把最小闭环从查天气开始打通,再一步一步扩展工具面,这条路我实测下来是走得通的。