ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

vConsole MCP:让AI直接读取移动端日志,告别H5调试痛点

vConsole MCP:让AI直接读取移动端日志,告别H5调试痛点

1. 移动端调试的痛点与 vConsole MCP 的破局思路

做过 H5 的同学都懂,移动端调试这件事,说多了都是泪。你在电脑浏览器里跑得好好的页面,一上真机就各种玄学问题:接口偶尔 500、某个按钮点了没反应、页面白屏但控制台干干净净。最要命的是,你根本看不到手机上到底发生了什么——没有控制台、没有 Network 面板、连报错都被吞掉了。

传统的做法无非这么几种。第一种是alert 大法,在关键位置弹窗打印变量,调试完再一个个删掉,代码被搞得千疮百孔。第二种是引入 vConsole,在页面里挂一个移动端的调试面板,能看到日志和网络请求,但问题是——你得用眼睛盯着那块小屏幕,手动翻找、手动复制,信息量大一点就完全看不过来。第三种是远程调试,用数据线连电脑,通过浏览器开发者工具映射,但这对环境要求高,iOS 和 Android 各有各的坑,而且很多场景(比如内嵌在 App 里的 WebView)根本连不上。

我自己就踩过无数次这种坑。有一次做一个活动页,在 App 的 WebView 里跑,用户反馈说点击抽奖没反应,我在电脑上怎么测都是好的。最后没办法,只能把关键日志用 vConsole 打出来,然后让测试同学截图发给我,来回折腾了一下午才定位到是一个第三方 SDK 在特定机型上初始化失败。那种效率,真的是让人抓狂。

vConsole MCP这个项目,就是冲着这个痛点来的。它的核心思路非常直接:既然 vConsole 已经把日志和请求都收集到了页面上,那我能不能让 AI 直接去“读”这些数据?答案是能。通过MCP(Model Context Protocol)协议,把 vConsole 的数据通道打开,让 AI 助手(比如 Claude、Cursor 里的 AI)直接接入,实时获取 H5 页面上的 console 日志、网络请求、错误堆栈,然后帮你分析问题、定位 bug。

说白了,以前是你盯着 vConsole 面板看,现在是你让 AI 帮你盯着,你只需要问它“刚才那个请求为什么失败了”,它就能直接告诉你答案。这个转变的意义在于,调试的交互方式从“人找信息”变成了“人问问题”,效率提升不是一点半点。

这个内容适合谁看?如果你是前端开发、H5 开发、移动端测试,或者经常需要排查线上问题的同学,这套方案能直接用到你的日常工作里。如果你对 MCP 协议感兴趣,想了解怎么把现有工具接入 AI 工作流,这里也有完整的实现思路。哪怕你只是好奇“AI 怎么看见浏览器日志”这件事,往下看也能搞明白背后的原理。

2. 核心组件拆解:vConsole、MCP 与 WebSocket 是怎么串起来的

2.1 vConsole 的角色:数据采集层

vConsole 本身是一个轻量级的移动端调试面板,它的核心能力是劫持原生的 console 方法和 XMLHttpRequest/fetch 请求,把原本输出到浏览器控制台的信息,重定向到页面上一个可交互的面板里。它支持日志(log、info、warn、error)、网络请求(请求头、响应体、耗时)、系统信息、存储查看等功能。

但 vConsole 默认是“只读”的——数据展示在面板上,你只能看,没法程序化地取出来。所以我们要做的第一件事,就是在 vConsole 的基础上加一层数据导出机制。具体来说,就是监听 vConsole 的事件,或者直接 hook 它的日志添加方法,把每一条日志和请求都序列化成 JSON,然后通过一个通道发出去。

这里有个关键点:vConsole 的插件机制允许我们注册自定义插件,但更轻量的做法是直接监听它的内部事件。vConsole 在添加日志时会触发addLog事件,我们可以通过vConsole.on('addLog', callback)来捕获。对于网络请求,vConsole 会触发addRequest事件。这两个事件就是我们数据采集的入口。

注意:vConsole 的事件名在不同版本间可能有差异,建议锁定一个稳定版本(比如 3.15.1),并在初始化时确认事件是否正常触发。

2.2 MCP 的角色:AI 与工具之间的桥梁

MCP 全称 Model Context Protocol,是一个让 AI 模型能够调用外部工具、访问外部资源的协议。你可以把它理解成 AI 的“USB 接口”——以前 AI 只能基于训练数据回答问题,现在通过 MCP,它可以实时读取你本地的文件、查询数据库、调用 API,甚至控制浏览器。

在这个项目里,MCP 的作用是把 vConsole 采集到的数据暴露给 AI。具体实现上,我们需要写一个 MCP Server,它对外提供几个“工具”(Tool),比如:

  • get_console_logs:获取最近的 console 日志
  • get_network_requests:获取网络请求列表
  • get_errors:获取错误日志
  • clear_logs:清空日志

AI 助手通过 MCP 协议连接到这个 Server,当你在对话里问“刚才那个接口为什么返回 500”时,AI 会自动调用get_network_requests工具,拿到数据后分析并回答。

MCP 的通信方式支持 stdio 和 SSE 两种,对于本地调试场景,stdio 更简单直接。你只需要在 AI 客户端的配置里加上这个 MCP Server 的启动命令,它就能自动拉起并连接。

2.3 WebSocket 的角色:实时数据传输通道

vConsole 跑在手机浏览器里,MCP Server 跑在电脑上,两者之间需要一个通信通道。WebSocket 是最合适的选择——全双工、低延迟、支持服务端主动推送。

整个数据流是这样的:

  1. H5 页面加载 vConsole 和我们的采集脚本
  2. 采集脚本通过 WebSocket 连接到本地电脑上的 MCP Server
  3. 每当有新的日志或请求产生,采集脚本立即通过 WebSocket 发送给 Server
  4. Server 把数据缓存起来,等待 AI 查询
  5. AI 通过 MCP 协议调用工具,Server 返回缓存的数据

这里有个细节需要注意:WebSocket 连接地址不能写死。因为手机和电脑要在同一个局域网内,IP 地址会变。常见的做法是在页面上提供一个输入框,让开发者手动填入电脑的局域网 IP 和端口,或者通过 URL 参数传递。更优雅的方案是使用 mDNS 或者扫描二维码自动配置,但实现复杂度会高一些。

提示:如果 H5 页面是 HTTPS 的,WebSocket 必须用 wss://,否则浏览器会阻止混合内容。本地调试时可以用自签名证书,或者让页面跑在 HTTP 下。

2.4 三者的协作关系

把这三个组件串起来看:vConsole 负责“看见”页面里发生的一切,WebSocket 负责“搬运”这些数据,MCP Server 负责“翻译”给 AI 听。AI 拿到数据后,结合它的分析能力,就能帮你快速定位问题。

这个架构的好处是解耦。vConsole 的采集逻辑、WebSocket 的传输逻辑、MCP 的工具定义,三者可以独立开发和替换。比如你不想用 vConsole,换成自己写的日志采集库也行;不想用 WebSocket,换成 SSE 或者轮询也能跑。这种灵活性对于实际项目落地非常重要。

3. 从零搭建:vConsole MCP 的完整实操流程

3.1 环境准备与依赖安装

先明确一下我们要装什么。电脑端需要 Node.js 环境(建议 18 以上),因为 MCP Server 和 WebSocket 服务都用 Node 写。手机端不需要额外环境,只要能跑浏览器就行。

创建一个项目目录,初始化 npm:

mkdir vconsole-mcp cd vconsole-mcp npm init -y

安装核心依赖:

npm install ws vconsole

ws是 WebSocket 的服务端实现,vconsole是移动端调试面板。如果你打算把采集脚本打包成一个独立的 JS 文件,还需要一个打包工具,这里用 esbuild 就够了:

npm install esbuild --save-dev

MCP Server 的实现可以基于官方的@modelcontextprotocol/sdk:

npm install @modelcontextprotocol/sdk

目录结构建议这样组织:

vconsole-mcp/ ├── server/ │ ├── ws-server.js # WebSocket 服务 │ └── mcp-server.js # MCP Server ├── client/ │ └── collector.js # 注入到 H5 的采集脚本 ├── dist/ │ └── collector.min.js # 打包后的采集脚本 └── package.json

3.2 WebSocket 服务端实现

WebSocket 服务端的职责很简单:接收手机端发来的数据,缓存起来,并提供查询接口给 MCP Server。

// server/ws-server.js const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); // 数据缓存,限制最大条数防止内存溢出 const MAX_LOGS = 1000; const MAX_REQUESTS = 500; const store = { logs: [], requests: [], errors: [], }; function pushWithLimit(arr, item, limit) { arr.push(item); if (arr.length > limit) { arr.shift(); } } wss.on('connection', (ws) => { console.log('客户端已连接'); ws.on('message', (data) => { try { const msg = JSON.parse(data); switch (msg.type) { case 'log': pushWithLimit(store.logs, msg.payload, MAX_LOGS); if (msg.payload.level === 'error') { pushWithLimit(store.errors, msg.payload, MAX_LOGS); } break; case 'request': pushWithLimit(store.requests, msg.payload, MAX_REQUESTS); break; case 'clear': store.logs = []; store.requests = []; store.errors = []; break; default: break; } } catch (e) { console.error('解析消息失败:', e); } }); ws.on('close', () => { console.log('客户端断开连接'); }); }); // 导出查询接口供 MCP Server 使用 module.exports = { getLogs: (limit = 50) => store.logs.slice(-limit), getRequests: (limit = 30) => store.requests.slice(-limit), getErrors: (limit = 50) => store.errors.slice(-limit), clear: () => { store.logs = []; store.requests = []; store.errors = []; }, }; console.log('WebSocket 服务已启动,端口 8080');

这段代码有几个设计考量。第一,限制缓存条数,因为手机端可能持续产生大量日志,不限制的话内存会爆。第二,错误日志单独存一份,方便 AI 快速定位问题。第三,导出查询接口而不是直接暴露 store,是为了让 MCP Server 和 WebSocket 服务解耦,后续换存储方案(比如存 SQLite)时不影响上层。

3.3 采集脚本的编写与注入

采集脚本要跑在 H5 页面里,它的任务是初始化 vConsole,监听日志和请求事件,然后通过 WebSocket 发出去。

// client/collector.js import VConsole from 'vconsole'; const WS_URL = window.__VCONSOLE_WS_URL__ || 'ws://192.168.1.100:8080'; let ws = null; let reconnectTimer = null; function connect() { ws = new WebSocket(WS_URL); ws.onopen = () => { console.log('[vConsole MCP] 已连接到调试服务'); }; ws.onclose = () => { console.log('[vConsole MCP] 连接断开,3秒后重连'); reconnectTimer = setTimeout(connect, 3000); }; ws.onerror = (err) => { console.error('[vConsole MCP] 连接错误', err); }; } function send(type, payload) { if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type, payload })); } } // 初始化 vConsole const vConsole = new VConsole({ theme: 'dark' }); // 监听日志事件 vConsole.on('addLog', (log) => { send('log', { level: log.level || 'log', content: log.content, time: Date.now(), }); }); // 监听网络请求事件 vConsole.on('addRequest', (req) => { send('request', { url: req.url, method: req.method, status: req.status, cost: req.cost, requestBody: req.requestBody, responseBody: req.responseBody, time: Date.now(), }); }); connect(); // 暴露手动清空的方法 window.__clearVConsoleMCP = () => { send('clear', {}); };

这里有几个实操中总结出来的经验。第一,WebSocket 地址要支持外部注入。我一开始写死了地址,结果换个网络环境就要改代码重新打包,非常麻烦。后来改成从window.__VCONSOLE_WS_URL__读取,在页面里通过一个 script 标签提前设置,灵活多了。

第二,重连机制必须有。手机浏览器切到后台再切回来,WebSocket 经常会断,没有重连的话数据就丢了。3 秒重连是个比较平衡的值,太短了频繁重试浪费资源,太长了数据丢失窗口太大。

第三,vConsole 的事件回调里不要做耗时操作。因为日志产生频率可能很高,如果回调里做复杂的序列化或者同步请求,会阻塞页面。这里的send只是把数据丢进 WebSocket 的发送缓冲区,是异步的,不会阻塞。

打包成单文件:

npx esbuild client/collector.js --bundle --minify --format=iife --outfile=dist/collector.min.js

然后在 H5 页面的<head>里引入:

<script> window.__VCONSOLE_WS_URL__ = 'ws://192.168.1.100:8080'; </script> <script src="https://your-cdn.com/collector.min.js"></script>

注意:如果页面是 HTTPS 的,WebSocket 地址必须用 wss://,并且证书要有效,否则连接会被浏览器阻止。本地调试时可以用mkcert生成自签名证书。

3.4 MCP Server 的实现与接入

MCP Server 是整个方案里和 AI 对接的部分。它需要定义几个工具,让 AI 能够查询数据。

// server/mcp-server.js const { Server } = require('@modelcontextprotocol/sdk/server/index.js'); const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js'); const { CallToolRequestSchema, ListToolsRequestSchema, } = require('@modelcontextprotocol/sdk/types.js'); const wsStore = require('./ws-server'); const server = new Server( { name: 'vconsole-mcp', version: '1.0.0' }, { capabilities: { tools: {} } } ); // 定义工具列表 server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'get_console_logs', description: '获取 H5 页面最近的 console 日志', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: '返回条数,默认 50' }, level: { type: 'string', description: '过滤日志级别:log/warn/error' }, }, }, }, { name: 'get_network_requests', description: '获取 H5 页面最近的网络请求', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: '返回条数,默认 30' }, status: { type: 'number', description: '按状态码过滤' }, }, }, }, { name: 'get_errors', description: '获取 H5 页面的错误日志', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: '返回条数,默认 50' }, }, }, }, { name: 'clear_logs', description: '清空所有缓存的日志和请求', inputSchema: { type: 'object', properties: {} }, }, ], })); // 处理工具调用 server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case 'get_console_logs': { let logs = wsStore.getLogs(args?.limit || 50); if (args?.level) { logs = logs.filter((l) => l.level === args.level); } return { content: [{ type: 'text', text: JSON.stringify(logs, null, 2) }], }; } case 'get_network_requests': { let reqs = wsStore.getRequests(args?.limit || 30); if (args?.status) { reqs = reqs.filter((r) => r.status === args.status); } return { content: [{ type: 'text', text: JSON.stringify(reqs, null, 2) }], }; } case 'get_errors': { const errors = wsStore.getErrors(args?.limit || 50); return { content: [{ type: 'text', text: JSON.stringify(errors, null, 2) }], }; } case 'clear_logs': { wsStore.clear(); return { content: [{ type: 'text', text: '已清空所有日志和请求' }], }; } default: throw new Error(`未知工具: ${name}`); } }); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('vConsole MCP Server 已启动'); } main().catch(console.error);

这段代码的核心是工具定义和请求处理。工具定义告诉 AI “我能做什么”,请求处理负责“怎么做”。注意get_console_logs支持按 level 过滤,get_network_requests支持按 status 过滤,这些过滤能力能帮 AI 更快地缩小排查范围。

接入 AI 客户端时,以 Claude Desktop 为例,在配置文件里加上:

{ "mcpServers": { "vconsole": { "command": "node", "args": ["/path/to/vconsole-mcp/server/mcp-server.js"] } } }

重启客户端后,AI 就能看到这四个工具了。你可以直接问它:“帮我看看最近有没有报错”,它会自动调用get_errors并分析结果。

3.5 完整调试流程演示

假设你在调试一个 H5 页面,用户反馈点击按钮后没反应。按照传统方式,你可能要加一堆 console.log,然后让用户截图。现在有了这套方案,流程变成这样:

  1. 手机打开 H5 页面,vConsole 自动初始化,采集脚本连接 WebSocket
  2. 你在页面上复现问题:点击按钮,发现没反应
  3. 打开 AI 对话,输入:“刚才点击按钮后,有没有报错?网络请求正常吗?”
  4. AI 自动调用get_errors,发现有一条TypeError: Cannot read property 'id' of undefined
  5. AI 继续调用get_network_requests,发现按钮点击后应该发的接口根本没发出去
  6. AI 综合判断:按钮的点击事件处理函数里,在发请求之前就抛错了,原因是某个对象为 undefined
  7. 你根据这个线索去检查代码,发现是用户数据还没加载完就点了按钮

整个过程不需要你手动翻日志、不需要截图、不需要来回沟通,AI 直接把结论摆在你面前。这就是这套方案的价值所在。

4. 实战避坑指南与常见问题排查

4.1 连接类问题:WebSocket 连不上怎么办

这是最常见的问题,表现是手机端一直显示“连接断开,3秒后重连”。排查思路按优先级来:

第一,确认手机和电脑在同一局域网。手机连的是 4G/5G,电脑连的是 WiFi,那肯定连不上。让手机连上同一个 WiFi,或者电脑开热点给手机连。

第二,确认 IP 地址正确。电脑的局域网 IP 可以通过ifconfig(Mac/Linux)或ipconfig(Windows)查看。注意不要用 127.0.0.1,那是本机回环地址,手机访问不到。

第三,检查防火墙。Windows 防火墙默认会阻止外部设备访问本地端口。要么在防火墙里放行 8080 端口,要么临时关闭防火墙测试。Mac 一般没这个问题,但如果你开了某些安全软件,也可能被拦。

第四,确认端口没被占用。如果 8080 已经被其他程序用了,WebSocket 服务启动会报错。换个端口,比如 8081,同时更新采集脚本里的地址。

第五,HTTPS 页面的混合内容限制。如果 H5 页面是 HTTPS 的,浏览器会阻止 ws:// 的连接。解决方案有两个:一是让页面跑在 HTTP 下(仅限本地调试),二是给 WebSocket 服务配 SSL 证书,用 wss:// 连接。

实操心得:我习惯在 WebSocket 服务启动时打印出所有可用的局域网 IP,这样就不用每次手动查了。用os.networkInterfaces()遍历一下就行。

4.2 数据类问题:日志丢失或不全

有时候发现 AI 查到的日志比实际少,或者某些请求没被捕获。原因可能有这几个:

vConsole 的事件没触发。不同版本的 vConsole 事件名可能不一样,建议在初始化后先手动打一条日志,确认addLog事件能正常触发。如果不行,查一下你用的版本的文档。

WebSocket 发送频率过高导致丢包。如果页面在短时间内产生大量日志(比如循环里打日志),WebSocket 的发送缓冲区可能溢出。解决方案是在采集脚本里加一个简单的节流,比如每 50ms 最多发一次,把这段时间内的日志合并成一个数组发送。

缓存条数限制。前面代码里设了 MAX_LOGS=1000,超过就会丢弃最早的。如果你需要更长的历史,可以调大这个值,或者把数据持久化到文件/SQLite。

页面刷新导致数据丢失。WebSocket 连接在页面刷新时会断开,缓存的数据如果只在内存里,刷新后就没了。如果需要跨刷新保留,可以在服务端把数据写入文件。

4.3 AI 类问题:MCP 工具调用失败

AI 客户端显示“无法找到 MCP Server”或者“工具调用超时”,排查方向:

路径问题。MCP 配置里的args必须是绝对路径,相对路径在不同工作目录下会解析失败。

Node 版本问题。@modelcontextprotocol/sdk需要 Node 18 以上,低版本会报语法错误。用node -v确认一下。

依赖没装全。MCP Server 依赖ws和@modelcontextprotocol/sdk,如果只装了其中一个,启动会报错。建议在项目根目录执行npm install确保所有依赖都装上。

stdio 通信被污染。MCP 的 stdio 传输要求 stdout 只能输出协议数据,任何console.log都会干扰通信。所以 MCP Server 里的日志必须用console.error输出到 stderr。

工具描述不够清晰。AI 是根据工具描述来决定调用哪个工具的。如果描述太模糊,AI 可能不知道该用哪个。建议描述里写清楚“什么时候用这个工具”,比如“当需要查看页面报错时使用”。

4.4 常见问题速查表

问题现象可能原因排查方法解决方案
手机端一直重连网络不通手机浏览器访问电脑 IP:端口确认同一局域网,检查防火墙
连接成功但无数据事件未触发手动打日志看是否发送检查 vConsole 版本和事件名
AI 找不到工具MCP 配置错误查看客户端日志检查路径、Node 版本、依赖
日志条数偏少缓存限制查看 MAX_LOGS 设置调大限制或持久化存储
HTTPS 页面连不上混合内容阻止浏览器控制台报错用 wss:// 或页面降级 HTTP
请求体为空vConsole 配置检查 vConsole 初始化参数开启 requestBody 记录

4.5 几个提升效率的独家技巧

技巧一:给日志加标签。在采集脚本里,可以根据日志内容自动打标签,比如包含“error”的标记为错误,包含“api”的标记为接口相关。这样 AI 查询时可以按标签过滤,更快定位。

技巧二:请求耗时排序。在 MCP Server 里加一个get_slow_requests工具,按耗时倒序返回请求。排查性能问题时特别有用,一眼就能看出哪个接口拖慢了页面。

技巧三:错误聚合。同样的错误可能重复出现很多次,在服务端做一下聚合,返回“错误类型 + 出现次数 + 首次出现时间”,比返回一堆重复日志清晰得多。

技巧四:结合 sourcemap。如果页面是打包压缩过的,错误堆栈里的行号列号没法直接对应源码。可以在 MCP Server 里集成 sourcemap 解析,把压缩后的位置映射回源码位置,AI 分析起来更准确。

技巧五:多页面支持。如果同时调试多个 H5 页面,可以在 WebSocket 连接时带上页面标识(比如 URL 的 hash),服务端按页面分开存储,AI 查询时指定页面标识即可。

5. 扩展思路:这套方案还能怎么用

5.1 接入更多数据源

vConsole 只是数据来源之一。同样的架构可以接入其他调试信息:

  • Performance API:采集页面性能指标(FP、FCP、LCP),让 AI 分析性能瓶颈
  • 错误监控 SDK:把 Sentry 等工具捕获的错误同步过来
  • 自定义埋点:业务代码里的关键节点打点,AI 可以还原用户操作路径
  • Storage 变化:监听 localStorage/sessionStorage 的读写,排查缓存相关问题

只要能把数据通过 WebSocket 发过来,MCP Server 就能把它暴露给 AI。

5.2 从“查询”到“主动分析”

现在的模式是“你问 AI 答”,下一步可以让 AI 主动分析。比如在 MCP Server 里加一个定时任务,每隔 30 秒检查一次错误日志,发现新错误就主动推送给 AI,AI 分析后给出可能的原因和修复建议。这样你甚至不需要主动问,问题出现时 AI 就已经在帮你排查了。

5.3 团队协作场景

把 WebSocket 服务部署到一台公共服务器上,团队成员都可以连接。每个人的调试数据按设备 ID 分开存储,AI 可以跨设备分析问题。比如测试同学在 A 手机上复现了问题,开发同学在 B 手机上调试,AI 可以对比两台设备的日志差异,快速定位环境相关问题。

5.4 与 CI/CD 结合

在自动化测试阶段,让测试用例跑在真实设备上,采集脚本把日志和请求发到服务端。测试结束后,AI 自动分析日志,判断是否有异常。如果有,直接生成 bug 报告,包含错误堆栈、复现步骤建议、相关请求信息。这样能把问题发现的时间点提前到测试阶段,减少线上事故。

我在实际使用这套方案的过程中,最大的感受是调试的思维模式变了。以前是“我要去找什么信息”,现在是“我描述现象,让 AI 去找信息”。这个转变节省的不仅是时间,更是精力——你不用再在繁杂的日志里大海捞针,而是把精力放在理解问题和设计解决方案上。当然,AI 的分析结果需要你验证,它可能会误判,但作为第一轮的筛选和定位工具,它已经足够强大了。

返回列表