@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.
@@ -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.selectPage(page);
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.selectPage(page);
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
- if ((!this.#selectedPage || this.#pages.indexOf(this.#selectedPage) === -1) &&
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.4';
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);
@@ -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
- context.selectPage(page);
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(`${tools.length} WebMCP tool(s) registered:`);
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
- response.appendResponseLine(`- ${tool.originalName}`);
124
- if (tool.description) {
125
- response.appendResponseLine(` Description: ${tool.description}`);
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('IMPORTANT: Use call_webmcp_tool with the ORIGINAL name (without webmcp_ prefix).');
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
- const toolNames = tools.map(t => t.originalName).join(', ');
146
- response.appendResponseLine(`${tools.length} tools available: ${toolNames}`);
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 (${added.length}):`);
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
- response.appendResponseLine(`+ ${tool.originalName}`);
154
- if (tool.description) {
155
- response.appendResponseLine(` ${tool.description}`);
182
+ if (!addedByPage.has(tool.pageIdx)) {
183
+ addedByPage.set(tool.pageIdx, []);
156
184
  }
157
- response.appendResponseLine(` Full ID: ${tool.toolId}`);
185
+ addedByPage.get(tool.pageIdx).push(tool);
158
186
  }
159
- response.appendResponseLine('');
160
- response.appendResponseLine('NEW TOOLS AVAILABLE: Use call_webmcp_tool with the original name.');
161
- response.appendResponseLine(`Example: call_webmcp_tool({ name: "${added[0].originalName}" })`);
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 (${removed.length}):`);
204
+ response.appendResponseLine(`Removed ${removed.length} tool(s)`);
205
+ response.appendResponseLine('');
166
206
  for (const id of removed) {
167
- response.appendResponseLine(`- ${id}`);
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
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-b/chrome-devtools-mcp",
3
- "version": "1.5.4",
3
+ "version": "1.5.6",
4
4
  "description": "MCP server for Chrome DevTools with WebMCP integration for connecting to website MCP tools",
5
5
  "keywords": [
6
6
  "mcp",