Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ English | [简体中文](./CHANGELOG_CN.md)

## 3.16.0 (2026-??-??)

- `Feat(Core)` Add a built-in MCP panel and WebSocket bridge for remotely reading debug data and optionally executing JavaScript after on-device authorization.
- `Feat(Log)` Add support for `console.timeLog()`. (issue #681, PR #684)
- `Feat(Network)` Capture static resource requests (images, scripts, stylesheets, fonts, etc.) via `PerformanceObserver` and display them in the Network panel. (issue #708)
- `Feat(Network)` Add WebSocket support: display connections in the Network panel with sent/received messages. (issue #688)
Expand Down Expand Up @@ -562,4 +563,4 @@ Plugins:

## v1.0.2 (2016-04-27)

- Initial release.
- Initial release.
3 changes: 2 additions & 1 deletion CHANGELOG_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 3.16.0 (2026-??-??)

- `Feat(Core)` 新增内置 MCP 面板和 WebSocket 桥接,支持远程读取调试数据,并可在手机端授权后执行 JavaScript。
- `Feat(Log)` 新增对 `console.timeLog()` 的支持。(issue #681, PR #684)
- `Feat(Network)` 通过 `PerformanceObserver` 捕获静态资源请求(图片、脚本、样式表、字体等)并在 Network 面板中展示。(issue #708)
- `Feat(Network)` 新增 WebSocket 支持:在 Network 面板中展示 WebSocket 连接及收发消息。(issue #688)
Expand Down Expand Up @@ -560,4 +561,4 @@ Network 插件:

## v1.0.2 (2016-04-27)

- 初始发布。
- 初始发布。
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Now vConsole is the official debugging tool for WeChat Miniprograms.
- Network: `XMLHttpRequest`, `Fetch`, `sendBeacon`
- Element: HTML elements tree
- Storage: `Cookies`, `LocalStorage`, `SessionStorage`
- MCP: Let desktop AI debugging tools read page logs and network requests, with optional JavaScript execution after explicit on-device authorization
- Execute JS command manually
- Custom plugins

Expand Down Expand Up @@ -75,6 +76,20 @@ Available CDN:

---

## Remote Debugging with MCP

The built-in MCP panel connects the page to a vConsole MCP server running on your computer. Once connected, MCP clients such as Codex and Claude Code can read Console logs and Network requests from the current mobile page.

![vConsole MCP panel](./doc/screenshot/mcp_panel.png)

To connect, start the MCP server on the computer, open the `MCP` panel, enter the computer's reachable LAN IP in `Host`, then enter its port and optional pairing token. Tap `Connect`; the page is available to the MCP client when `Status` becomes `open`. Do not use `localhost` as the host when connecting from a phone.

`Allow JavaScript Execution` is denied by default. Enable it only when the AI must operate the page. Authorization granted in the panel lasts only for the current page lifetime and resets after a reload, unless it is explicitly enabled in the initialization options. Executed scripts have the full privileges of the current page context, so use a pairing token and enable this option only on trusted development pages and networks.

HTTPS pages require a secure WebSocket (`wss://`) endpoint. See [Public Properties & Methods](./doc/public_properties_methods.md#vconsolemcp) for programmatic configuration.

---

## Preview

[http://wechatfe.github.io/vconsole/demo.html](http://wechatfe.github.io/vconsole/demo.html)
Expand Down
25 changes: 25 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ vConsole 是框架无关的,可以在 Vue、React 或其他任何框架中使
- 网络(Network): `XMLHttpRequest`, `Fetch`, `sendBeacon`
- 节点(Element): HTML 节点树
- 存储(Storage): `Cookies`, `LocalStorage`, `SessionStorage`
- MCP:允许电脑端 AI 调试工具远程读取页面日志和网络请求,并可在手机端明确授权后执行 JavaScript
- 手动执行 JS 命令行
- 自定义插件

Expand Down Expand Up @@ -77,6 +78,30 @@ vConsole.destroy();

---

## 使用 MCP 远程调试

MCP 面板用于连接运行在电脑上的 vConsole MCP 服务。连接后,Codex、Claude Code 等支持 MCP 的 AI 调试工具可以读取当前手机页面的 Console 日志和 Network 请求记录。

![vConsole MCP 面板](./doc/screenshot/mcp_panel.png)

使用步骤:

1. 在电脑上启动 vConsole MCP 服务,并确认监听的 IP、端口及配对 Token。
2. 确保手机可以访问该电脑。局域网调试时,手机和电脑通常需要连接到同一网络。
3. 打开 vConsole,进入 `MCP` 面板。
4. 在 `Host` 中填写电脑的局域网 IP(不能填写 `localhost`),在 `Port` 中填写服务端口;如果服务端配置了配对 Token,还需填写 `Pairing Token`。
5. 点击底部的 `Connect`。当 `Status` 显示为 `open` 时,AI 调试工具即可发现并读取该页面;点击 `Disconnect` 可主动断开。

面板会记住连接地址和配对 Token。主动连接后,页面会在连接意外断开时自动重连;主动点击 `Disconnect` 后则不会自动重连。

`Allow JavaScript Execution` 默认处于 `Denied`,此时 MCP 只能读取调试信息。只有在确实需要 AI 操作页面时才应勾选该选项;通过面板授予的权限仅对当前页面生命周期有效,刷新或重新打开页面后会恢复为拒绝(初始化配置显式开启时除外)。执行的脚本拥有当前页面上下文中的完整权限,请配置配对 Token,并仅在可信的开发页面和网络环境中开启。

如果当前页面使用 HTTPS,MCP 服务也应提供安全的 WebSocket(`wss://`),否则浏览器可能因混合内容策略拒绝连接。

也可以通过初始化参数配置连接,完整选项和方法请参阅[公共属性及方法](./doc/public_properties_methods_CN.md#vconsolemcp)。

---

## 手机预览

[http://wechatfe.github.io/vconsole/demo.html](http://wechatfe.github.io/vconsole/demo.html)
Expand Down
3 changes: 2 additions & 1 deletion dev/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ <h1 class="page_title">vConsole Demo</h1>
<a href="./element.html" class="weui_btn weui_btn_default">Element</a>
<a href="./storage.html" class="weui_btn weui_btn_default">Storage</a>
<a href="./plugin.html" class="weui_btn weui_btn_default">Custom Plugin</a>
<a href="./mcp.html" class="weui_btn weui_btn_default">MCP Bridge</a>
<a href="./async.html" class="weui_btn weui_btn_default">Async Loading</a>
<a href="./vue.html" class="weui_btn weui_btn_default">Vue</a>
</div>
Expand All @@ -41,4 +42,4 @@ <h1 class="page_title">vConsole Demo</h1>
console.log('on clearLog');
}
});
</script>
</script>
34 changes: 34 additions & 0 deletions dev/mcp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>vConsole: MCP Bridge</title>
<link href="../dev/lib/weui.min.css" rel="stylesheet"/>
<link href="../dev/lib/demo.css" rel="stylesheet"/>
<script src="../dist/vconsole.min.js"></script>
</head>
<body ontouchstart>
<div class="page">
<h1 class="page_title">MCP Bridge</h1>
<div class="weui_cells_title">Configure the connection and JavaScript permission in vConsole's MCP panel.</div>
<a id="open" class="weui_btn weui_btn_primary">Open MCP Panel</a>
<a id="log" class="weui_btn weui_btn_default">Create Console Log</a>
<a id="request" class="weui_btn weui_btn_default">Create Network Request</a>
</div>
</body>
</html>

<script>
var vConsole = new window.VConsole();
document.getElementById('open').onclick = function() {
vConsole.show();
vConsole.showPlugin('mcp');
};
document.getElementById('log').onclick = function() {
console.error('vConsole MCP test log', { time: Date.now() });
};
document.getElementById('request').onclick = function() {
fetch('./log.html?s=500&t=300');
};
</script>
38 changes: 35 additions & 3 deletions doc/public_properties_methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ TypeScript users can import the type directly:
import type { VConsoleOptions } from 'vconsole';
```

Available sub-types: `VConsoleLogOptions`, `VConsoleNetworkOptions`, `VConsoleStorageOptions`, `VConsoleAvailableStorage`.
Available sub-types: `VConsoleLogOptions`, `VConsoleNetworkOptions`, `VConsoleStorageOptions`, `VConsoleAvailableStorage`, `VConsoleMCPOptions`.

Key | Type | Optional | Default value | Description
--------------------- | -------- | -------- | ------------------------------------------- | -------------------
defaultPlugins | Array(String) | true | ['system', 'network', 'element', 'storage'] | Listed built-in plugins will be inited and loaded into vConsole.
defaultPlugins | Array(String) | true | ['system', 'network', 'element', 'storage', 'mcp'] | Listed built-in plugins will be inited and loaded into vConsole.
pluginOrder | Array(String) | true | [] | Plugin panels will be sorted as this list. Plugin not listed will be put last.
onReady | Function | true | | Trigger after vConsole is inited and default plugins is loaded.
disableLogScrolling | Boolean | true | | If `false`, panel will not scroll to bottom while printing new logs.
Expand All @@ -67,6 +67,11 @@ log.showTimestamps | Boolean | true | false
network.maxNetworkNumber | Number | true | 1000 | Overflow requests will be removed from Netowrk panel.
network.ignoreUrlRegExp | RegExp | true | | Skip the requests which url match the RegExp.
storage.defaultStorages | Array | true | ['cookies', 'localStorage', 'sessionStorage'] | Listed storage(s) will be available in Storage panel.
mcp.endpoint | String | true | | WebSocket endpoint of a vConsole MCP server.
mcp.token | String | true | | Optional pairing token configured by the MCP server.
mcp.autoConnect | Boolean | true | true | Connect automatically after vConsole is ready when an endpoint is set.
mcp.reconnectInterval | Number | true | 2000 | Delay in milliseconds before reconnecting.
mcp.allowJavaScriptExecution | Boolean | true | false | Allow an MCP client to execute JavaScript in the page.

Example:

Expand Down Expand Up @@ -125,6 +130,33 @@ vConsole.setSwitchPosition(20, 20);

---

### vConsole.mcp

The built-in MCP panel lets users enter the computer host, port, and optional pairing token, then connect or disconnect from its toolbar. It remembers the settings and automatically reconnects after a connection is enabled.

The connection can also be configured programmatically:

```javascript
var vConsole = new VConsole({
mcp: {
endpoint: 'ws://192.168.1.100:8765',
token: 'your-development-token',
autoConnect: true,
allowJavaScriptExecution: false,
},
});

vConsole.mcp.connect('ws://192.168.1.100:8765');
vConsole.mcp.disconnect();
vConsole.mcp.state; // 'closed' | 'connecting' | 'open'
```

Console logs and Network records are always available as read-only requests. JavaScript execution is denied by default and can be enabled for the current page from the MCP panel or with `mcp.allowJavaScriptExecution: true`. Enabled scripts run with the page's full origin privileges, so use a pairing token and only enable execution on trusted development pages.

The connection uses the browser's original WebSocket implementation and is not included in the Network panel.

---

### vConsole.destroy()

Destroy an vConsole instance object and remove vConsole panel from document.
Expand Down Expand Up @@ -276,4 +308,4 @@ vConsole.hideSwitch();

---

[Back to Index](./a_doc_index.md)
[Back to Index](./a_doc_index.md)
38 changes: 35 additions & 3 deletions doc/public_properties_methods_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ TypeScript 用户可直接导入类型:
import type { VConsoleOptions } from 'vconsole';
```

相关子类型:`VConsoleLogOptions`、`VConsoleNetworkOptions`、`VConsoleStorageOptions`、`VConsoleAvailableStorage`。
相关子类型:`VConsoleLogOptions`、`VConsoleNetworkOptions`、`VConsoleStorageOptions`、`VConsoleAvailableStorage`、`VConsoleMCPOptions`

键名 | 类型 | 可选 | 默认值 | 描述
--------------------- | -------- | -------- | ------------------------------------------- | -------------------
defaultPlugins | Array(String) | true | ['system', 'network', 'element', 'storage'] | 需要自动初始化并加载的内置插件。
defaultPlugins | Array(String) | true | ['system', 'network', 'element', 'storage', 'mcp'] | 需要自动初始化并加载的内置插件。
pluginOrder | Array(String) | true | [] | 插件面板会按此列表进行排序,未列出的插件将排在最后。
onReady | Function | true | | 回调方法,当 vConsole 完成初始化并加载完内置插件后触发。
disableLogScrolling | Boolean | true | | 若为 `false`,有新日志时面板将不会自动滚动到底部。
Expand All @@ -66,6 +66,11 @@ log.showTimestamps | Boolean | true | false
log.maxNetworkNumber | Number | true | 1000 | 超出数量上限的请求记录会被自动清除。
network.ignoreUrlRegExp | RegExp | true | | 不展示 URL 匹配正则表达式的请求。
storage.defaultStorages | Array | true | ['cookies', 'localStorage', 'sessionStorage'] | 在 Storage 面板中要加载的 storage 类型。
mcp.endpoint | String | true | | vConsole MCP 服务的 WebSocket 地址。
mcp.token | String | true | | MCP 服务配置的可选配对 Token。
mcp.autoConnect | Boolean | true | true | 配置 endpoint 后,在 vConsole 就绪时自动连接。
mcp.reconnectInterval | Number | true | 2000 | 断线重连的等待时间,单位为毫秒。
mcp.allowJavaScriptExecution | Boolean | true | false | 是否允许 MCP 客户端在页面中执行 JavaScript。

例子:

Expand Down Expand Up @@ -125,6 +130,33 @@ vConsole.setSwitchPosition(20, 20);

---

### vConsole.mcp

内置的 MCP 面板支持用户填写电脑 Host、端口和可选配对 Token,并通过工具栏连接或断开。面板会记住设置,在启用连接后自动重连。

也可以通过代码配置连接:

```javascript
var vConsole = new VConsole({
mcp: {
endpoint: 'ws://192.168.1.100:8765',
token: 'your-development-token',
autoConnect: true,
allowJavaScriptExecution: false,
},
});

vConsole.mcp.connect('ws://192.168.1.100:8765');
vConsole.mcp.disconnect();
vConsole.mcp.state; // 'closed' | 'connecting' | 'open'
```

Console 日志和 Network 记录始终以只读请求提供。JavaScript 执行默认拒绝,可在当前页面的 MCP 面板中开启,或配置 `mcp.allowJavaScriptExecution: true`。启用后的脚本具有当前页面同源环境的完整权限,因此请配置配对 Token,并只在可信开发页面中开启。

MCP 连接使用浏览器原始的 WebSocket 实现,因此不会出现在 Network 面板中。

---

### vConsole.destroy()

析构一个 vConsole 对象实例,并将 vConsole 面板从页面中移除。
Expand Down Expand Up @@ -276,4 +308,4 @@ vConsole.hideSwitch();

---

[返回索引](./a_doc_index_CN.md)
[返回索引](./a_doc_index_CN.md)
Binary file added doc/screenshot/mcp_panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"svelte": "^5.53.10",
"svelte-loader": "^3.2.4",
"svelte-preprocess": "^6.0.3",
"terser-webpack-plugin": "^5.4.0",
"typescript": "^5.9.3",
"webpack": "^5.72.0",
"webpack-cli": "^6.0.1",
Expand Down
17 changes: 16 additions & 1 deletion src/core/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import { VConsoleSystemPlugin } from '../log/system';
import { VConsoleNetworkPlugin } from '../network/network';
import { VConsoleElementPlugin } from '../element/element';
import { VConsoleStoragePlugin } from '../storage/storage';
import { VConsoleMCPClient } from '../mcp/mcp';
import { VConsoleMCPPlugin } from '../mcp/mcp.plugin';

// built-in plugin exporters
import { VConsoleLogExporter } from '../log/log.exporter';
Expand All @@ -53,6 +55,7 @@ export class VConsole {
public log: VConsoleLogExporter;
public system: VConsoleLogExporter;
public network: VConsoleNetworkExporter;
public mcp: VConsoleMCPClient;

// Export static classes
public static VConsolePlugin: typeof VConsolePlugin;
Expand All @@ -62,6 +65,7 @@ export class VConsole {
public static VConsoleNetworkPlugin: typeof VConsoleNetworkPlugin;
public static VConsoleElementPlugin: typeof VConsoleElementPlugin;
public static VConsoleStoragePlugin: typeof VConsoleStoragePlugin;
public static VConsoleMCPPlugin: typeof VConsoleMCPPlugin;

constructor(opt?: VConsoleOptions) {
if (!!VConsole.instance && VConsole.instance instanceof VConsole) {
Expand All @@ -72,10 +76,11 @@ export class VConsole {

this.isInited = false;
this.option = {
defaultPlugins: ['system', 'network', 'element', 'storage'],
defaultPlugins: ['system', 'network', 'element', 'storage', 'mcp'],
log: {},
network: {},
storage: {},
mcp: {},
};

// merge options
Expand All @@ -98,6 +103,8 @@ export class VConsole {
console.debug('[vConsole] Deprecated option: `maxNetworkNumber`, use `network.maxNetworkNumber` instead.');
}

this.mcp = new VConsoleMCPClient(this.option.mcp);

// add built-in plugins
this._addBuiltInPlugins();

Expand Down Expand Up @@ -165,6 +172,7 @@ export class VConsole {
plugins['network'] = { proto: VConsoleNetworkPlugin, name: 'Network' };
plugins['element'] = { proto: VConsoleElementPlugin, name: 'Element' };
plugins['storage'] = { proto: VConsoleStoragePlugin, name: 'Storage' };
plugins['mcp'] = { proto: VConsoleMCPPlugin, name: 'MCP' };
}
if (!!list && tool.isArray(list)) {
for (let i = 0; i < list.length; i++) {
Expand Down Expand Up @@ -263,6 +271,9 @@ export class VConsole {
this._showFirstPluginWhenEmpty();

this.triggerEvent('ready');
if (this.option.mcp?.endpoint && this.option.mcp.autoConnect !== false) {
this.mcp.connect();
}
}

private _showFirstPluginWhenEmpty() {
Expand Down Expand Up @@ -529,6 +540,7 @@ export class VConsole {
}
this._triggerPluginsEvent('updateOption');
this._updateComponentByOptions();
this.mcp.setOption(this.option.mcp);
} else if (tool.isObject(keyOrObj)) {
for (let k in keyOrObj) {
if (k === '__proto__' || k === 'constructor' || k === 'prototype') {
Expand All @@ -539,6 +551,7 @@ export class VConsole {
}
this._triggerPluginsEvent('updateOption');
this._updateComponentByOptions();
this.mcp.setOption(this.option.mcp);
} else {
console.debug('[vConsole] The first parameter of `vConsole.setOption()` must be a string or an object.');
}
Expand All @@ -553,6 +566,7 @@ export class VConsole {
window.removeEventListener('DOMContentLoaded', this._onloadCallback);
this._onloadCallback = undefined;
}
this.mcp.disconnect();
if (!this.isInited) {
VConsole.instance = undefined;
return;
Expand Down Expand Up @@ -584,4 +598,5 @@ if (__TARGET__ === 'web') {
VConsole.VConsoleNetworkPlugin = VConsoleNetworkPlugin;
VConsole.VConsoleElementPlugin = VConsoleElementPlugin;
VConsole.VConsoleStoragePlugin = VConsoleStoragePlugin;
VConsole.VConsoleMCPPlugin = VConsoleMCPPlugin;
}
Loading