@mcp-b/chrome-devtools-mcp 1.5.4 → 1.5.6
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/build/src/McpContext.js +20 -4
- package/build/src/main.js +1 -1
- package/build/src/tools/pages.js +2 -1
- package/build/src/tools/webmcp.js +63 -20
- package/package.json +1 -1
package/build/src/McpContext.js
CHANGED
|
@@ -75,6 +75,12 @@ export class McpContext {
|
|
|
75
75
|
#pageToDevToolsPage = new Map();
|
|
76
76
|
/** Currently selected page for tool operations. */
|
|
77
77
|
#selectedPage;
|
|
78
|
+
/**
|
|
79
|
+
* Whether the selected page has been explicitly set for this session.
|
|
80
|
+
* When true, createPagesSnapshot() won't auto-switch to pages[0].
|
|
81
|
+
* This prevents MCP sessions from interfering with each other in shared browsers.
|
|
82
|
+
*/
|
|
83
|
+
#pageExplicitlySelected = false;
|
|
78
84
|
/** Most recent accessibility snapshot of the selected page. */
|
|
79
85
|
#textSnapshot = null;
|
|
80
86
|
#networkCollector;
|
|
@@ -357,7 +363,8 @@ export class McpContext {
|
|
|
357
363
|
async newPage() {
|
|
358
364
|
const page = await this.browser.newPage();
|
|
359
365
|
await this.createPagesSnapshot();
|
|
360
|
-
this
|
|
366
|
+
// Mark as explicitly selected so this session sticks to this page
|
|
367
|
+
this.selectPage(page, true);
|
|
361
368
|
this.#networkCollector.addPage(page);
|
|
362
369
|
this.#consoleCollector.addPage(page);
|
|
363
370
|
// Set up WebMCP auto-detection for the new page
|
|
@@ -384,7 +391,8 @@ export class McpContext {
|
|
|
384
391
|
throw new Error('Failed to get page from new window target');
|
|
385
392
|
}
|
|
386
393
|
await this.createPagesSnapshot();
|
|
387
|
-
this
|
|
394
|
+
// Mark as explicitly selected so this session sticks to this window
|
|
395
|
+
this.selectPage(page, true);
|
|
388
396
|
this.#networkCollector.addPage(page);
|
|
389
397
|
this.#consoleCollector.addPage(page);
|
|
390
398
|
// Set up WebMCP auto-detection for the new page
|
|
@@ -473,12 +481,16 @@ export class McpContext {
|
|
|
473
481
|
isPageSelected(page) {
|
|
474
482
|
return this.#selectedPage === page;
|
|
475
483
|
}
|
|
476
|
-
selectPage(newPage) {
|
|
484
|
+
selectPage(newPage, explicit = false) {
|
|
477
485
|
const oldPage = this.#selectedPage;
|
|
478
486
|
if (oldPage) {
|
|
479
487
|
oldPage.off('dialog', this.#dialogHandler);
|
|
480
488
|
}
|
|
481
489
|
this.#selectedPage = newPage;
|
|
490
|
+
if (explicit) {
|
|
491
|
+
// Mark page as explicitly selected to prevent auto-switching
|
|
492
|
+
this.#pageExplicitlySelected = true;
|
|
493
|
+
}
|
|
482
494
|
newPage.on('dialog', this.#dialogHandler);
|
|
483
495
|
this.#updateSelectedPageTimeouts();
|
|
484
496
|
}
|
|
@@ -532,7 +544,11 @@ export class McpContext {
|
|
|
532
544
|
return (this.#options.experimentalDevToolsDebugging ||
|
|
533
545
|
!page.url().startsWith('devtools://'));
|
|
534
546
|
});
|
|
535
|
-
|
|
547
|
+
// Only auto-select pages[0] if:
|
|
548
|
+
// 1. No page has been explicitly selected for this session AND
|
|
549
|
+
// 2. Either there's no selected page OR the selected page is no longer valid
|
|
550
|
+
if (!this.#pageExplicitlySelected &&
|
|
551
|
+
(!this.#selectedPage || this.#pages.indexOf(this.#selectedPage) === -1) &&
|
|
536
552
|
this.#pages[0]) {
|
|
537
553
|
this.selectPage(this.#pages[0]);
|
|
538
554
|
}
|
package/build/src/main.js
CHANGED
|
@@ -22,7 +22,7 @@ import { WebMCPToolHub } from './tools/WebMCPToolHub.js';
|
|
|
22
22
|
* @remarks If moved, update release-please config.
|
|
23
23
|
*/
|
|
24
24
|
// x-release-please-start-version
|
|
25
|
-
const VERSION = '1.5.
|
|
25
|
+
const VERSION = '1.5.6';
|
|
26
26
|
// x-release-please-end
|
|
27
27
|
process.on('unhandledRejection', (reason, promise) => {
|
|
28
28
|
logger('Unhandled promise rejection', promise, reason);
|
package/build/src/tools/pages.js
CHANGED
|
@@ -37,7 +37,8 @@ export const selectPage = defineTool({
|
|
|
37
37
|
},
|
|
38
38
|
handler: async (request, response, context) => {
|
|
39
39
|
const page = context.getPageByIdx(request.params.pageIdx);
|
|
40
|
-
|
|
40
|
+
// Mark as explicitly selected so this session stays on this page
|
|
41
|
+
context.selectPage(page, true);
|
|
41
42
|
if (request.params.bringToFront) {
|
|
42
43
|
await page.bringToFront();
|
|
43
44
|
}
|
|
@@ -117,22 +117,34 @@ export const listWebMCPTools = defineTool({
|
|
|
117
117
|
response.appendResponseLine('Navigate to a page with @mcp-b/global loaded to discover tools.');
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
120
|
-
response.appendResponseLine(
|
|
120
|
+
response.appendResponseLine(`Found ${tools.length} WebMCP tool(s):`);
|
|
121
121
|
response.appendResponseLine('');
|
|
122
|
+
// Group tools by page
|
|
123
|
+
const toolsByPage = new Map();
|
|
122
124
|
for (const tool of tools) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
if (!toolsByPage.has(tool.pageIdx)) {
|
|
126
|
+
toolsByPage.set(tool.pageIdx, []);
|
|
127
|
+
}
|
|
128
|
+
toolsByPage.get(tool.pageIdx).push(tool);
|
|
129
|
+
}
|
|
130
|
+
// Sort pages by index
|
|
131
|
+
const sortedPages = Array.from(toolsByPage.keys()).sort((a, b) => a - b);
|
|
132
|
+
for (const pageIdx of sortedPages) {
|
|
133
|
+
const pageTools = toolsByPage.get(pageIdx);
|
|
134
|
+
const domain = pageTools[0].domain;
|
|
135
|
+
response.appendResponseLine(`Page ${pageIdx}: ${domain}`);
|
|
136
|
+
for (const tool of pageTools) {
|
|
137
|
+
response.appendResponseLine(` • ${tool.originalName}`);
|
|
138
|
+
if (tool.description) {
|
|
139
|
+
response.appendResponseLine(` ${tool.description}`);
|
|
140
|
+
}
|
|
126
141
|
}
|
|
127
|
-
response.appendResponseLine(` Domain: ${tool.domain} (page ${tool.pageIdx})`);
|
|
128
|
-
response.appendResponseLine(` Full ID: ${tool.toolId}`);
|
|
129
142
|
response.appendResponseLine('');
|
|
130
143
|
}
|
|
131
|
-
response.appendResponseLine('
|
|
144
|
+
response.appendResponseLine('To call a tool: call_webmcp_tool({ name: "tool_name", arguments: {...} })');
|
|
132
145
|
if (tools.length > 0) {
|
|
133
146
|
response.appendResponseLine(`Example: call_webmcp_tool({ name: "${tools[0].originalName}" })`);
|
|
134
147
|
}
|
|
135
|
-
response.appendResponseLine('NOT: call_webmcp_tool({ name: "webmcp_localhost_..." })');
|
|
136
148
|
return;
|
|
137
149
|
}
|
|
138
150
|
// Subsequent calls: return diff
|
|
@@ -141,30 +153,61 @@ export const listWebMCPTools = defineTool({
|
|
|
141
153
|
toolHub.setLastSeenToolIds(currentToolIds);
|
|
142
154
|
if (added.length === 0 && removed.length === 0) {
|
|
143
155
|
response.appendResponseLine('No changes since last poll.');
|
|
156
|
+
response.appendResponseLine('');
|
|
144
157
|
if (tools.length > 0) {
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
// Group tools by page
|
|
159
|
+
const toolsByPage = new Map();
|
|
160
|
+
for (const tool of tools) {
|
|
161
|
+
if (!toolsByPage.has(tool.pageIdx)) {
|
|
162
|
+
toolsByPage.set(tool.pageIdx, []);
|
|
163
|
+
}
|
|
164
|
+
toolsByPage.get(tool.pageIdx).push(tool);
|
|
165
|
+
}
|
|
166
|
+
response.appendResponseLine(`${tools.length} tool(s) available:`);
|
|
167
|
+
const sortedPages = Array.from(toolsByPage.keys()).sort((a, b) => a - b);
|
|
168
|
+
for (const pageIdx of sortedPages) {
|
|
169
|
+
const pageTools = toolsByPage.get(pageIdx);
|
|
170
|
+
const toolNames = pageTools.map(t => t.originalName).join(', ');
|
|
171
|
+
response.appendResponseLine(` Page ${pageIdx}: ${toolNames}`);
|
|
172
|
+
}
|
|
147
173
|
}
|
|
148
174
|
return;
|
|
149
175
|
}
|
|
150
176
|
if (added.length > 0) {
|
|
151
|
-
response.appendResponseLine(`Added
|
|
177
|
+
response.appendResponseLine(`Added ${added.length} new tool(s):`);
|
|
178
|
+
response.appendResponseLine('');
|
|
179
|
+
// Group by page
|
|
180
|
+
const addedByPage = new Map();
|
|
152
181
|
for (const tool of added) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
response.appendResponseLine(` ${tool.description}`);
|
|
182
|
+
if (!addedByPage.has(tool.pageIdx)) {
|
|
183
|
+
addedByPage.set(tool.pageIdx, []);
|
|
156
184
|
}
|
|
157
|
-
|
|
185
|
+
addedByPage.get(tool.pageIdx).push(tool);
|
|
158
186
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
187
|
+
const sortedPages = Array.from(addedByPage.keys()).sort((a, b) => a - b);
|
|
188
|
+
for (const pageIdx of sortedPages) {
|
|
189
|
+
const pageTools = addedByPage.get(pageIdx);
|
|
190
|
+
const domain = pageTools[0].domain;
|
|
191
|
+
response.appendResponseLine(`Page ${pageIdx}: ${domain}`);
|
|
192
|
+
for (const tool of pageTools) {
|
|
193
|
+
response.appendResponseLine(` + ${tool.originalName}`);
|
|
194
|
+
if (tool.description) {
|
|
195
|
+
response.appendResponseLine(` ${tool.description}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
response.appendResponseLine('');
|
|
199
|
+
}
|
|
200
|
+
response.appendResponseLine(`Call with: call_webmcp_tool({ name: "${added[0].originalName}" })`);
|
|
162
201
|
response.appendResponseLine('');
|
|
163
202
|
}
|
|
164
203
|
if (removed.length > 0) {
|
|
165
|
-
response.appendResponseLine(`Removed
|
|
204
|
+
response.appendResponseLine(`Removed ${removed.length} tool(s)`);
|
|
205
|
+
response.appendResponseLine('');
|
|
166
206
|
for (const id of removed) {
|
|
167
|
-
|
|
207
|
+
// Extract original name from toolId format: webmcp_{domain}_page{idx}_{name}
|
|
208
|
+
const parts = id.split('_');
|
|
209
|
+
const name = parts.slice(3).join('_'); // Everything after page index
|
|
210
|
+
response.appendResponseLine(` - ${name || id}`);
|
|
168
211
|
}
|
|
169
212
|
}
|
|
170
213
|
},
|