@mallocfeng/chromedev 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,7 @@ http://127.0.0.1:8787/mcp
13
13
  整个流程只有两步:
14
14
 
15
15
  1. 在 Chrome 中开启远程调试
16
- 2. 安装并启动 `chromedev` 服务
16
+ 2. 用 npm 安装并启动 `chromedev`
17
17
 
18
18
  ### 1. 在 Chrome 中开启远程调试
19
19
 
@@ -32,25 +32,19 @@ http://127.0.0.1:8787/mcp
32
32
 
33
33
  ### 2. 安装并启动服务
34
34
 
35
- 推荐直接用 npm 全局安装:
35
+ 安装:
36
36
 
37
37
  ```bash
38
38
  npm install -g @mallocfeng/chromedev
39
39
  ```
40
40
 
41
- 安装完成后,后台启动:
41
+ 启动:
42
42
 
43
43
  ```bash
44
44
  chromedev run
45
45
  ```
46
46
 
47
- 如果你是在项目源码目录里本地运行,也可以用:
48
-
49
- ```bash
50
- node ./bin/chromedev.mjs run
51
- ```
52
-
53
- 成功后会看到:
47
+ 成功后会看到类似输出:
54
48
 
55
49
  ```text
56
50
  chromedev started in background (pid 12345)
@@ -59,47 +53,9 @@ endpoint: http://127.0.0.1:8787/mcp
59
53
 
60
54
  这表示服务已经在后台运行,其他 AI 或程序现在可以访问 `http://127.0.0.1:8787/mcp`。
61
55
 
62
- ## npm 安装
63
-
64
- 推荐安装方式:
65
-
66
- ```bash
67
- npm install -g @mallocfeng/chromedev
68
- ```
69
-
70
- 安装完成后可直接使用:
71
-
72
- ```bash
73
- chromedev run
74
- chromedev status
75
- chromedev stop
76
- ```
77
-
78
- 如果你不想全局安装,也可以临时执行:
79
-
80
- ```bash
81
- npx @mallocfeng/chromedev run
82
- ```
83
-
84
- 如果用户把这个 GitHub 仓库地址直接发给 AI,AI 应该按下面的步骤理解和执行:
85
-
86
- 1. 先安装命令行工具:
87
-
88
- ```bash
89
- npm install -g @mallocfeng/chromedev
90
- ```
91
-
92
- 2. 然后启动服务:
93
-
94
- ```bash
95
- chromedev run
96
- ```
97
-
98
- 3. 如果还需要安装 OpenClaw skill,再从 GitHub 下载项目源码,并把 `skills/chromedev` 拷贝到 OpenClaw 的 `skills` 目录。
99
-
100
56
  ## 常用命令
101
57
 
102
- 后台启动:
58
+ 启动:
103
59
 
104
60
  ```bash
105
61
  chromedev run
@@ -111,16 +67,16 @@ chromedev run
111
67
  chromedev run --foreground
112
68
  ```
113
69
 
114
- 查看状态:
70
+ 停止:
115
71
 
116
72
  ```bash
117
- chromedev status
73
+ chromedev stop
118
74
  ```
119
75
 
120
- 停止服务:
76
+ 查看状态:
121
77
 
122
78
  ```bash
123
- chromedev stop
79
+ chromedev status
124
80
  ```
125
81
 
126
82
  查看日志路径:
@@ -129,21 +85,15 @@ chromedev stop
129
85
  chromedev logs
130
86
  ```
131
87
 
132
- 如果你是在源码目录里本地运行,把 `chromedev` 换成:
133
-
134
- ```bash
135
- node ./bin/chromedev.mjs
136
- ```
137
-
138
88
  ## 如何验证服务正常
139
89
 
140
- 看状态:
90
+ 查看状态:
141
91
 
142
92
  ```bash
143
93
  chromedev status
144
94
  ```
145
95
 
146
- 看端点是否存在:
96
+ 检查端点:
147
97
 
148
98
  ```bash
149
99
  curl -i http://127.0.0.1:8787/mcp
@@ -151,81 +101,30 @@ curl -i http://127.0.0.1:8787/mcp
151
101
 
152
102
  如果返回 `400 Bad Request` 且内容类似 `No sessionId`,这是正常的,说明 MCP 端点已经存在。
153
103
 
154
- ## 命令行访问网页示例
155
-
156
- 列出当前页面:
157
-
158
- ```bash
159
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs list_pages
160
- ```
161
-
162
- 打开 `163.com`:
163
-
164
- ```bash
165
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs new_page '{"url":"https://www.163.com/","timeout":30000}'
166
- ```
167
-
168
- 读取当前页面快照:
169
-
170
- ```bash
171
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs take_snapshot
172
- ```
173
-
174
104
  ## 在 OpenClaw 中安装 skill
175
105
 
176
- 这个项目里已经包含了一份 skill:
106
+ 这个仓库包含一份 skill:
177
107
 
178
108
  ```text
179
109
  skills/chromedev
180
110
  ```
181
111
 
182
- 如果你是通过 GitHub 下载项目源码:
112
+ 安装方法:
183
113
 
184
- 1. 打开仓库:`https://github.com/mallocfeng/chromeDev`
185
- 2. 下载项目源码,或者直接 clone:
114
+ 1. 从 GitHub 下载项目源码:
186
115
 
187
116
  ```bash
188
117
  git clone https://github.com/mallocfeng/chromeDev.git
189
118
  ```
190
119
 
191
- 3. 你需要用到的 skill 目录就是:
192
-
193
- ```text
194
- chromeDev/skills/chromedev
195
- ```
196
-
197
- 如果用户把 GitHub 地址直接发给 AI,AI 可以按这套指令执行:
198
-
199
- ```bash
200
- git clone https://github.com/mallocfeng/chromeDev.git
201
- ```
202
-
203
- 然后取出:
204
-
205
- ```text
206
- chromeDev/skills/chromedev
207
- ```
208
-
209
- 再把它复制到 OpenClaw 的 `skills` 目录下。
210
-
211
- 安装到 OpenClaw 的方法很简单:
212
-
213
- 1. 把项目目录中的 `skills/chromedev` 目录拷贝到你 OpenClaw 工作目录的 `skills` 文件夹下。
214
- 2. 如果你不清楚这个文件夹在哪里,可以先直接问 OpenClaw,它会告诉你当前 agent 工作目录在哪里。
215
- 3. 拷贝进去以后,运行:
120
+ 2. 把其中的 `skills/chromedev` 目录拷贝到 OpenClaw 当前 agent 工作目录下的 `skills` 文件夹。
121
+ 3. 如果你不知道 OpenClaw 的工作目录在哪里,直接先问 OpenClaw。
122
+ 4. 拷贝完成后执行:
216
123
 
217
124
  ```bash
218
125
  openclaw gateway restart
219
126
  ```
220
127
 
221
- 完成后就可以在 OpenClaw 里调用这个 skill。
222
-
223
- 给 AI 的可执行描述可以直接写成这样:
224
-
225
- ```text
226
- 从 https://github.com/mallocfeng/chromeDev 下载项目,把其中的 skills/chromedev 目录拷贝到当前 OpenClaw agent 工作目录下的 skills 文件夹,然后执行 openclaw gateway restart。
227
- ```
228
-
229
128
  目录结构应该像这样:
230
129
 
231
130
  ```text
@@ -239,7 +138,7 @@ openclaw gateway restart
239
138
 
240
139
  ## 在 OpenClaw 中使用
241
140
 
242
- 在聊天框中可以直接这样输入:
141
+ 可以直接这样输入:
243
142
 
244
143
  ```text
245
144
  /chromedev 调用这个 skills 访问当前打开的纽约时报标签文章,并摘要
@@ -251,28 +150,11 @@ openclaw gateway restart
251
150
  调用 chromedev 这个 skills,访问纽约时报,并且摘要新闻
252
151
  ```
253
152
 
254
- 这个 skill 会通过本地 `ChromeDev` MCP 服务访问你当前打开的 Chrome,并读取网页内容。
255
-
256
153
  注意:
257
154
 
258
- - OpenClaw 里的 skill 只负责“告诉 AI 怎么调用本地 ChromeDev 服务”
259
- - 真正提供浏览器访问能力的,还是你本机运行中的 `chromedev run`
260
- - 所以使用 skill 前,先确认本地 `chromedev` 服务已经启动
261
-
262
- ## 日志与运行文件
263
-
264
- 默认文件位置:
265
-
266
- - `~/.chromedev/run/chromedev.pid`
267
- - `~/.chromedev/run/chromedev.out.log`
268
- - `~/.chromedev/run/chromedev.err.log`
269
-
270
- 直接查看日志:
271
-
272
- ```bash
273
- tail -f ~/.chromedev/run/chromedev.out.log
274
- tail -f ~/.chromedev/run/chromedev.err.log
275
- ```
155
+ - skill 只负责告诉 AI 怎么调用本地 ChromeDev 服务
156
+ - 真正提供浏览器访问能力的,是你本机运行中的 `chromedev run`
157
+ - 使用 skill 前,先确认本地服务已经启动
276
158
 
277
159
  ## 默认配置
278
160
 
@@ -293,6 +175,21 @@ MCP_REQUEST_TIMEOUT=30000
293
175
  MCP_PORT=8788 chromedev run
294
176
  ```
295
177
 
178
+ ## 日志位置
179
+
180
+ 默认文件位置:
181
+
182
+ - `~/.chromedev/run/chromedev.pid`
183
+ - `~/.chromedev/run/chromedev.out.log`
184
+ - `~/.chromedev/run/chromedev.err.log`
185
+
186
+ 查看日志:
187
+
188
+ ```bash
189
+ tail -f ~/.chromedev/run/chromedev.out.log
190
+ tail -f ~/.chromedev/run/chromedev.err.log
191
+ ```
192
+
296
193
  ## 常见问题
297
194
 
298
195
  ### 1. `EADDRINUSE: address already in use 127.0.0.1:8787`
@@ -321,14 +218,6 @@ MCP_PORT=8788 chromedev run
321
218
  3. 远程调试是否已经启用
322
219
  4. Chrome 是否弹出了授权确认框但还没有点
323
220
 
324
- ### 3. 第一次连接会卡几秒
325
-
326
- 通常是正常的,可能是:
327
-
328
- - Chrome 正在等待授权确认
329
- - `autoConnect` 正在连接浏览器
330
- - 页面本身还在加载
331
-
332
221
  ## 安全说明
333
222
 
334
223
  - 服务只应监听本地地址 `127.0.0.1`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mallocfeng/chromedev",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "CLI that exposes chrome-devtools-mcp as a local background service connected to your live Chrome browser.",
6
6
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "LICENSE"
34
34
  ],
35
35
  "bin": {
36
- "chromedev": "./bin/chromedev.mjs"
36
+ "chromedev": "bin/chromedev.mjs"
37
37
  },
38
38
  "scripts": {
39
39
  "start": "node ./server/chrome-mcp-daemon.mjs",
@@ -8,6 +8,7 @@ description: Use this skill when you need to access or control a live Chrome bro
8
8
  Use this skill when the user wants browser-backed data from real web pages through the local `chrome-devtools-mcp` middleware running at `http://127.0.0.1:8787/mcp`.
9
9
 
10
10
  This skill is for cases where rendered browser state matters: JavaScript-heavy sites, login state in the user's Chrome, interaction flows, screenshots, DOM snapshots, or page data that should come from the live browser instead of plain HTTP fetches.
11
+ The primary behavior is simple: if the user gives a URL, open it and return the page content. If the page is a list page, return the list content in order.
11
12
 
12
13
  ## Preconditions
13
14
 
@@ -29,9 +30,28 @@ A response like `400 Bad Request` with `No sessionId` means the endpoint exists
29
30
  2. Connect to `http://127.0.0.1:8787/mcp`.
30
31
  3. Use MCP browser tools to open or select a page.
31
32
  4. Prefer `take_snapshot` or `evaluate_script` for structured extraction.
32
- 5. Use `wait_for` when content depends on async rendering.
33
+ 5. Use `wait_for` only when the page is still loading and you know a stable piece of text or UI state to wait for.
33
34
  6. Return the extracted data, not raw protocol noise.
34
35
 
36
+ ## How To Interpret Requests
37
+
38
+ When the user gives a URL, treat it as a request to read the page and return its content:
39
+
40
+ 1. Open the target URL with `new_page`.
41
+ 2. Immediately call `list_pages` and select the page whose URL matches the target URL, or whose title clearly matches the target site.
42
+ 3. If multiple tabs match, choose the most recently opened matching tab.
43
+ 4. Only use `wait_for` if the page is still visibly loading and you know a stable text or selector to wait on.
44
+ 5. Use `take_snapshot` or `evaluate_script` to read the selected page.
45
+ 6. Return the page content faithfully and concisely. Do not add a summary unless the user explicitly asks for one.
46
+
47
+ Examples:
48
+
49
+ - "访问 163.com" means open `https://www.163.com/` and return the visible page content.
50
+ - "给我这个网页内容" means read the current page and return the content as-is.
51
+ - "访问纽约时报并读取文章" means open the NYTimes page or the specified article and return the article/page content.
52
+ - "读取这个 list 页面" means return the visible list items in order, including titles, text, and links when available.
53
+ - "读取 list" means extract the list structure, not a summary of the topic.
54
+
35
55
  ## Preferred tool order
36
56
 
37
57
  - `list_pages`: inspect current browser pages before changing state.
@@ -46,9 +66,11 @@ A response like `400 Bad Request` with `No sessionId` means the endpoint exists
46
66
 
47
67
  This skill includes a reusable script:
48
68
 
49
- - [`scripts/http_mcp_call.mjs`](/Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs)
69
+ - [`scripts/http_mcp_call.mjs`](scripts/http_mcp_call.mjs)
50
70
 
51
71
  It connects to the local HTTP MCP endpoint and calls one tool.
72
+ Use the copy that lives inside `skills/chromedev` so the skill always runs the version bundled with the current workspace.
73
+ If `list_pages` reports that the selected page has been closed, the script creates a blank page and retries once so the tab list can be returned.
52
74
 
53
75
  If `@modelcontextprotocol/sdk` is missing in the current workspace, install it in that workspace first:
54
76
 
@@ -61,52 +83,70 @@ npm install @modelcontextprotocol/sdk
61
83
  List current pages:
62
84
 
63
85
  ```bash
64
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs list_pages
86
+ node skills/chromedev/scripts/http_mcp_call.mjs list_pages
65
87
  ```
66
88
 
67
89
  Open `163.com`:
68
90
 
69
91
  ```bash
70
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs new_page '{"url":"https://www.163.com/","timeout":30000}'
92
+ node skills/chromedev/scripts/http_mcp_call.mjs new_page '{"url":"https://www.163.com/","timeout":30000}'
93
+ ```
94
+
95
+ Select the matching page before reading:
96
+
97
+ ```bash
98
+ node skills/chromedev/scripts/http_mcp_call.mjs list_pages
99
+ ```
100
+
101
+ Then choose the tab whose URL matches `https://www.163.com/` before calling `take_snapshot` or `evaluate_script`.
102
+
103
+ Read the current 163.com page:
104
+
105
+ ```bash
106
+ node skills/chromedev/scripts/http_mcp_call.mjs take_snapshot
71
107
  ```
72
108
 
73
109
  Get the current page snapshot:
74
110
 
75
111
  ```bash
76
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs take_snapshot
112
+ node skills/chromedev/scripts/http_mcp_call.mjs take_snapshot
77
113
  ```
78
114
 
79
115
  Extract page title and URL:
80
116
 
81
117
  ```bash
82
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs evaluate_script '{"function":"() => ({ title: document.title, url: location.href })"}'
118
+ node skills/chromedev/scripts/http_mcp_call.mjs evaluate_script '{"function":"() => ({ title: document.title, url: location.href })"}'
83
119
  ```
84
120
 
85
121
  Wait for specific text:
86
122
 
87
123
  ```bash
88
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs wait_for '{"text":["网易","163"],"timeout":30000}'
124
+ node skills/chromedev/scripts/http_mcp_call.mjs wait_for '{"text":["网易","163"],"timeout":30000}'
89
125
  ```
90
126
 
127
+ If `list_pages` returns `The selected page has been closed`, just run it again. The bundled script will open `about:blank` and retry automatically.
128
+
91
129
  ## Extraction guidance
92
130
 
93
- - Use `take_snapshot` for readable page summaries, navigation labels, and visible content.
131
+ - Use `take_snapshot` for readable page content and page structure.
94
132
  - Use `evaluate_script` for precise fields, arrays, links, prices, tables, or JSON-shaped output.
95
- - Use `wait_for` before reading if the site is client-rendered or slow.
133
+ - Use `wait_for` only if the page is still loading and you know a reliable text or selector to wait on.
96
134
  - Use `list_network_requests` and `get_network_request` only when DOM extraction is insufficient.
135
+ - For list pages, preserve order and return the item text or link target for each visible entry.
136
+ - For article pages, return the article text and visible metadata, not a recap unless asked.
97
137
 
98
138
  ## Example patterns
99
139
 
100
140
  For article text:
101
141
 
102
142
  ```bash
103
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs evaluate_script '{"function":"() => ({ title: document.title, text: document.body.innerText.slice(0, 4000) })"}'
143
+ node skills/chromedev/scripts/http_mcp_call.mjs evaluate_script '{"function":"() => ({ title: document.title, text: document.body.innerText.slice(0, 4000) })"}'
104
144
  ```
105
145
 
106
146
  For links on the page:
107
147
 
108
148
  ```bash
109
- node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_call.mjs evaluate_script '{"function":"() => Array.from(document.querySelectorAll(\"a\")).slice(0,50).map(a => ({ text: (a.innerText || a.textContent || \"\").trim(), href: a.href })).filter(x => x.href)"}'
149
+ node skills/chromedev/scripts/http_mcp_call.mjs evaluate_script '{"function":"() => Array.from(document.querySelectorAll(\"a\")).slice(0,50).map(a => ({ text: (a.innerText || a.textContent || \"\").trim(), href: a.href })).filter(x => x.href)"}'
110
150
  ```
111
151
 
112
152
  ## Operational notes
@@ -115,3 +155,9 @@ node /Volumes/MacMiniDisk/project/chromeDev/skills/chromedev/scripts/http_mcp_ca
115
155
  - If a tool call hangs near connection start, assume Chrome may be waiting for the authorization dialog.
116
156
  - Prefer returning concise extracted data over full raw snapshots unless the user asked for raw output.
117
157
  - Do not expose the local MCP endpoint outside `127.0.0.1`.
158
+ - Prefer the bundled `skills/chromedev/scripts/http_mcp_call.mjs` over ad hoc absolute paths so the current workspace copy is always used.
159
+ - For URL-reading tasks, return the page content faithfully and concisely. Do not summarize unless explicitly requested.
160
+ - For list pages, return the list items faithfully and in order.
161
+ - Never assume the currently selected tab is the one you just opened. Always re-check `list_pages` and target the matching URL or title before reading.
162
+ - Prefer `take_snapshot` for the first pass and `evaluate_script` only when the user wants exact fields or raw text.
163
+ - Treat `wait_for` as optional. Use it only if a page is visibly still loading and you know a reliable text or selector to wait on.
@@ -47,13 +47,32 @@ async function main() {
47
47
 
48
48
  try {
49
49
  await client.connect(transport)
50
- const result = await client.callTool({ name: toolName, arguments: args })
50
+ const result = await callWithRecovery(client, toolName, args)
51
51
  console.log(JSON.stringify(result, null, 2))
52
52
  } finally {
53
53
  await transport.close().catch(() => {})
54
54
  }
55
55
  }
56
56
 
57
+ async function callWithRecovery(client, toolName, args) {
58
+ const result = await client.callTool({ name: toolName, arguments: args })
59
+
60
+ if (toolName === 'list_pages' && isClosedPageError(result)) {
61
+ await client.callTool({
62
+ name: 'new_page',
63
+ arguments: { url: 'about:blank', timeout: 30000 },
64
+ })
65
+ return client.callTool({ name: toolName, arguments: args })
66
+ }
67
+
68
+ return result
69
+ }
70
+
71
+ function isClosedPageError(result) {
72
+ const text = result?.content?.find?.((item) => item?.type === 'text')?.text || ''
73
+ return Boolean(result?.isError && text.includes('selected page has been closed'))
74
+ }
75
+
57
76
  function printUsage() {
58
77
  console.error('Usage: http_mcp_call.mjs <tool_name> [json_args]')
59
78
  console.error("Example: http_mcp_call.mjs new_page '{\"url\":\"https://www.163.com/\",\"timeout\":30000}'")