@tontoko/fast-playwright-mcp 0.0.8 → 0.1.0

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.
Files changed (44) hide show
  1. package/README.md +277 -117
  2. package/lib/batch/batch-executor.js +4 -5
  3. package/lib/browser-context-factory.js +2 -4
  4. package/lib/browser-server-backend.js +5 -7
  5. package/lib/config.js +1 -1
  6. package/lib/context.js +1 -4
  7. package/lib/diagnostics/common/error-enrichment-utils.js +3 -2
  8. package/lib/diagnostics/common/index.js +4 -55
  9. package/lib/diagnostics/element-discovery.js +1 -2
  10. package/lib/diagnostics/frame-reference-manager.js +5 -6
  11. package/lib/diagnostics/resource-manager.js +1 -2
  12. package/lib/diagnostics/smart-config.js +5 -6
  13. package/lib/diagnostics/smart-handle.js +1 -2
  14. package/lib/extension/cdp-relay.js +32 -34
  15. package/lib/extension/extension-context-factory.js +4 -5
  16. package/lib/in-process-client.js +1 -1
  17. package/lib/loop/loop.js +5 -5
  18. package/lib/loopTools/main.js +1 -1
  19. package/lib/mcp/proxy-backend.js +2 -2
  20. package/lib/mcp/server.js +4 -6
  21. package/lib/{log.js → mcp/tool.js} +17 -11
  22. package/lib/mcp/transport.js +2 -4
  23. package/lib/program.js +2 -3
  24. package/lib/response.js +1 -2
  25. package/lib/session-log.js +1 -1
  26. package/lib/tab.js +2 -4
  27. package/lib/tools/diagnose/diagnose-config-handler.js +2 -3
  28. package/lib/tools/evaluate.js +1 -1
  29. package/lib/tools/keyboard.js +1 -1
  30. package/lib/tools/network.js +97 -6
  31. package/lib/tools/pdf.js +1 -1
  32. package/lib/tools/screenshot.js +1 -1
  33. package/lib/tools/snapshot.js +1 -1
  34. package/lib/tools/utils.js +6 -7
  35. package/lib/{javascript.js → utils/codegen.js} +1 -1
  36. package/lib/utils/common-formatters.js +2 -3
  37. package/lib/utils/error-handler-middleware.js +1 -2
  38. package/lib/{utils.js → utils/guid.js} +1 -1
  39. package/lib/utils/index.js +6 -0
  40. package/lib/utils/log.js +90 -0
  41. package/lib/utils/network-filter.js +114 -0
  42. package/lib/{package.js → utils/package.js} +2 -2
  43. package/lib/utils/request-logger.js +1 -1
  44. package/package.json +3 -3
@@ -1,56 +1,5 @@
1
- import { createRequire } from "node:module";
2
- var __create = Object.create;
3
- var __getProtoOf = Object.getPrototypeOf;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __toESM = (mod, isNodeMode, target) => {
8
- target = mod != null ? __create(__getProtoOf(mod)) : {};
9
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
- for (let key of __getOwnPropNames(mod))
11
- if (!__hasOwnProp.call(to, key))
12
- __defProp(to, key, {
13
- get: () => mod[key],
14
- enumerable: true
15
- });
16
- return to;
17
- };
18
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
-
20
1
  // src/diagnostics/common/index.ts
21
- import {
22
- DiagnosticBase
23
- } from "./diagnostic-base.js";
24
- import {
25
- analyzeErrorPatterns,
26
- createEnrichedError,
27
- generateRecoverySuggestions,
28
- generateSuggestions,
29
- safeDispose,
30
- safeDisposeAll
31
- } from "./error-enrichment-utils.js";
32
- import {
33
- createAdvancedStage,
34
- createCoreStage,
35
- createDependentStage,
36
- InitializationManager
37
- } from "./initialization-manager.js";
38
- import {
39
- globalPerformanceTracker,
40
- PerformanceTracker
41
- } from "./performance-tracker.js";
42
- export {
43
- safeDisposeAll,
44
- safeDispose,
45
- globalPerformanceTracker,
46
- generateSuggestions,
47
- generateRecoverySuggestions,
48
- createEnrichedError,
49
- createDependentStage,
50
- createCoreStage,
51
- createAdvancedStage,
52
- analyzeErrorPatterns,
53
- PerformanceTracker,
54
- InitializationManager,
55
- DiagnosticBase
56
- };
2
+ export * from "./diagnostic-base.js";
3
+ export * from "./error-enrichment-utils.js";
4
+ export * from "./initialization-manager.js";
5
+ export * from "./performance-tracker.js";
@@ -18,11 +18,10 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/diagnostics/element-discovery.ts
21
- import debug from "debug";
21
+ import { elementDiscoveryDebug } from "../utils/log.js";
22
22
  import { DiagnosticBase } from "./common/diagnostic-base.js";
23
23
  import { safeDispose } from "./common/error-enrichment-utils.js";
24
24
  import { SmartHandleBatch } from "./smart-handle.js";
25
- var elementDiscoveryDebug = debug("pw:mcp:element-discovery");
26
25
  class ElementDiscovery extends DiagnosticBase {
27
26
  smartHandleBatch;
28
27
  maxBatchSize = 100;
@@ -18,8 +18,7 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/diagnostics/frame-reference-manager.ts
21
- import debug from "debug";
22
- var frameDebug = debug("pw:mcp:frame");
21
+ import { frameReferenceDebug } from "../utils/log.js";
23
22
 
24
23
  class FrameReferenceManager {
25
24
  frameRefs = new WeakMap;
@@ -44,7 +43,7 @@ class FrameReferenceManager {
44
43
  this.frameRefs.set(frame, metadata);
45
44
  this.activeFrames.add(frame);
46
45
  } catch (error) {
47
- frameDebug("Frame tracking failed (frame might be detached):", {
46
+ frameReferenceDebug("Frame tracking failed (frame might be detached):", {
48
47
  error: error instanceof Error ? error.message : "Unknown error"
49
48
  });
50
49
  }
@@ -81,9 +80,9 @@ class FrameReferenceManager {
81
80
  try {
82
81
  frameUrl = frame.url();
83
82
  } catch (urlError) {
84
- frameDebug("Could not retrieve frame URL:", urlError);
83
+ frameReferenceDebug("Could not retrieve frame URL:", urlError);
85
84
  }
86
- frameDebug("Frame accessibility check failed (frame likely detached):", {
85
+ frameReferenceDebug("Frame accessibility check failed (frame likely detached):", {
87
86
  url: frameUrl,
88
87
  error: error instanceof Error ? error.message : "Unknown error"
89
88
  });
@@ -157,7 +156,7 @@ class FrameReferenceManager {
157
156
  startCleanupTimer() {
158
157
  this.cleanupInterval = setInterval(() => {
159
158
  this.cleanupDetachedFrames().catch((error) => {
160
- frameDebug("Frame cleanup timer failed:", error instanceof Error ? error.message : "Unknown error");
159
+ frameReferenceDebug("Frame cleanup timer failed:", error instanceof Error ? error.message : "Unknown error");
161
160
  });
162
161
  }, 30000);
163
162
  }
@@ -18,8 +18,7 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/diagnostics/resource-manager.ts
21
- import debug from "debug";
22
- var resourceDebug = debug("pw:mcp:resource");
21
+ import { resourceDebug } from "../utils/log.js";
23
22
 
24
23
  class ResourceManager {
25
24
  resources = new Map;
@@ -18,10 +18,9 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/diagnostics/smart-config.ts
21
- import debug from "debug";
21
+ import { smartConfigDebug } from "../utils/log.js";
22
22
  import { DiagnosticLevel } from "./diagnostic-level.js";
23
23
  import { DiagnosticThresholds } from "./diagnostic-thresholds.js";
24
- var configDebug = debug("pw:mcp:config");
25
24
 
26
25
  class SmartConfigManager {
27
26
  static instance;
@@ -38,7 +37,7 @@ class SmartConfigManager {
38
37
  static getInstance(initialConfig) {
39
38
  SmartConfigManager.instance ??= new SmartConfigManager(initialConfig);
40
39
  if (!SmartConfigManager.instance) {
41
- configDebug("Critical: SmartConfigManager instance is null after creation");
40
+ smartConfigDebug("Critical: SmartConfigManager instance is null after creation");
42
41
  SmartConfigManager.instance = new SmartConfigManager(initialConfig);
43
42
  }
44
43
  return SmartConfigManager.instance;
@@ -46,7 +45,7 @@ class SmartConfigManager {
46
45
  static resetInstance() {
47
46
  const wasNull = SmartConfigManager.instance === null;
48
47
  SmartConfigManager.instance = null;
49
- configDebug("SmartConfigManager instance reset", {
48
+ smartConfigDebug("SmartConfigManager instance reset", {
50
49
  wasAlreadyNull: wasNull
51
50
  });
52
51
  }
@@ -136,7 +135,7 @@ class SmartConfigManager {
136
135
  try {
137
136
  listener(this.config);
138
137
  } catch (error) {
139
- configDebug("Config change listener failed:", error);
138
+ smartConfigDebug("Config change listener failed:", error);
140
139
  }
141
140
  }
142
141
  }
@@ -229,7 +228,7 @@ class SmartConfigManager {
229
228
  };
230
229
  this.thresholdsManager.updateThresholds(thresholdsConfig);
231
230
  } catch (error) {
232
- configDebug("Failed to sync thresholds:", error);
231
+ smartConfigDebug("Failed to sync thresholds:", error);
233
232
  }
234
233
  }
235
234
  getThresholdsFromManager() {
@@ -18,11 +18,10 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/diagnostics/smart-handle.ts
21
- import debug from "debug";
21
+ import { smartHandleDebug } from "../utils/log.js";
22
22
  import {
23
23
  globalResourceManager
24
24
  } from "./resource-manager.js";
25
- var smartHandleDebug = debug("pw:mcp:smart-handle");
26
25
 
27
26
  class SmartHandle {
28
27
  disposed = false;
@@ -19,13 +19,11 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/extension/cdp-relay.ts
21
21
  import { spawn } from "node:child_process";
22
- import debug from "debug";
23
22
  import { WebSocket, WebSocketServer } from "ws";
24
23
  import { httpAddressToString } from "../http-server.js";
25
- import { logUnhandledError } from "../log.js";
26
24
  import { ManualPromise } from "../manual-promise.js";
25
+ import { cdpRelayDebug, logUnhandledError } from "../utils/log.js";
27
26
  var { registry } = await import("playwright-core/lib/server/registry/index");
28
- var debugLogger = debug("pw:mcp:relay");
29
27
  var HTTP_TO_WS_REGEX = /^http/;
30
28
  var EXTENSION_ID_REGEX = /^[a-p]{32}$/;
31
29
  var DANGEROUS_PATH_PATTERNS = [
@@ -64,17 +62,17 @@ class CDPRelayServer {
64
62
  return `${this._wsHost}${this._extensionPath}`;
65
63
  }
66
64
  async ensureExtensionConnectionForMCPContext(clientInfo, abortSignal) {
67
- debugLogger("Ensuring extension connection for MCP context");
65
+ cdpRelayDebug("Ensuring extension connection for MCP context");
68
66
  if (this._extensionConnection) {
69
67
  return;
70
68
  }
71
69
  this._connectBrowser(clientInfo);
72
- debugLogger("Waiting for incoming extension connection");
70
+ cdpRelayDebug("Waiting for incoming extension connection");
73
71
  await Promise.race([
74
72
  this._extensionConnectionPromise,
75
73
  new Promise((_, reject) => abortSignal.addEventListener("abort", reject))
76
74
  ]);
77
- debugLogger("Extension connection established");
75
+ cdpRelayDebug("Extension connection established");
78
76
  }
79
77
  _connectBrowser(clientInfo) {
80
78
  const mcpRelayEndpoint = `${this._wsHost}${this._extensionPath}`;
@@ -127,7 +125,7 @@ class CDPRelayServer {
127
125
  _safeJsonParse(jsonString) {
128
126
  try {
129
127
  if (jsonString.includes("__proto__") || jsonString.includes("constructor") || jsonString.includes("prototype")) {
130
- debugLogger("Potential prototype pollution attempt detected");
128
+ cdpRelayDebug("Potential prototype pollution attempt detected");
131
129
  return null;
132
130
  }
133
131
  const result = JSON.parse(jsonString);
@@ -137,7 +135,7 @@ class CDPRelayServer {
137
135
  this._sanitizeObject(result);
138
136
  return result;
139
137
  } catch (error) {
140
- debugLogger("JSON parsing failed:", error);
138
+ cdpRelayDebug("JSON parsing failed:", error);
141
139
  return null;
142
140
  }
143
141
  }
@@ -173,19 +171,19 @@ class CDPRelayServer {
173
171
  }
174
172
  _onConnection(ws, request) {
175
173
  const url = new URL(`http://localhost${request.url}`);
176
- debugLogger(`New connection to ${url.pathname}`);
174
+ cdpRelayDebug(`New connection to ${url.pathname}`);
177
175
  if (url.pathname === this._cdpPath) {
178
176
  this._handlePlaywrightConnection(ws);
179
177
  } else if (url.pathname === this._extensionPath) {
180
178
  this._handleExtensionConnection(ws);
181
179
  } else {
182
- debugLogger(`Invalid path: ${url.pathname}`);
180
+ cdpRelayDebug(`Invalid path: ${url.pathname}`);
183
181
  ws.close(4004, "Invalid path");
184
182
  }
185
183
  }
186
184
  _handlePlaywrightConnection(ws) {
187
185
  if (this._playwrightConnection) {
188
- debugLogger("Rejecting second Playwright connection");
186
+ cdpRelayDebug("Rejecting second Playwright connection");
189
187
  ws.close(1000, "Another CDP client already connected");
190
188
  return;
191
189
  }
@@ -194,18 +192,18 @@ class CDPRelayServer {
194
192
  try {
195
193
  const messageString = data.toString();
196
194
  if (messageString.length > 1048576) {
197
- debugLogger("Message too large, rejecting");
195
+ cdpRelayDebug("Message too large, rejecting");
198
196
  return;
199
197
  }
200
198
  const message = this._safeJsonParse(messageString);
201
199
  if (message === null) {
202
- debugLogger("Invalid JSON message received from Playwright");
200
+ cdpRelayDebug("Invalid JSON message received from Playwright");
203
201
  return;
204
202
  }
205
203
  await this._handlePlaywrightMessage(message);
206
204
  } catch (error) {
207
205
  const truncatedData = String(data).slice(0, 500);
208
- debugLogger(`Error while handling Playwright message
206
+ cdpRelayDebug(`Error while handling Playwright message
209
207
  ${truncatedData}...
210
208
  `, error);
211
209
  }
@@ -216,12 +214,12 @@ ${truncatedData}...
216
214
  }
217
215
  this._playwrightConnection = null;
218
216
  this._closeExtensionConnection("Playwright client disconnected");
219
- debugLogger("Playwright WebSocket closed");
217
+ cdpRelayDebug("Playwright WebSocket closed");
220
218
  });
221
219
  ws.on("error", (error) => {
222
- debugLogger("Playwright WebSocket error:", error);
220
+ cdpRelayDebug("Playwright WebSocket error:", error);
223
221
  });
224
- debugLogger("Playwright MCP connected");
222
+ cdpRelayDebug("Playwright MCP connected");
225
223
  }
226
224
  _closeExtensionConnection(reason) {
227
225
  this._extensionConnection?.close(reason);
@@ -247,7 +245,7 @@ ${truncatedData}...
247
245
  }
248
246
  this._extensionConnection = new ExtensionConnection(ws);
249
247
  this._extensionConnection.onclose = (c, reason) => {
250
- debugLogger("Extension WebSocket closed:", reason, c === this._extensionConnection);
248
+ cdpRelayDebug("Extension WebSocket closed:", reason, c === this._extensionConnection);
251
249
  if (this._extensionConnection !== c) {
252
250
  return;
253
251
  }
@@ -269,26 +267,26 @@ ${truncatedData}...
269
267
  break;
270
268
  }
271
269
  case "detachedFromTab":
272
- debugLogger("← Debugger detached from tab:", params);
270
+ cdpRelayDebug("← Debugger detached from tab:", params);
273
271
  this._connectedTabInfo = undefined;
274
272
  break;
275
273
  default:
276
- debugLogger(`← Extension: unhandled method ${method}`, params);
274
+ cdpRelayDebug(`← Extension: unhandled method ${method}`, params);
277
275
  break;
278
276
  }
279
277
  }
280
278
  async _handlePlaywrightMessage(message) {
281
279
  if (!this._isValidCDPCommand(message)) {
282
- debugLogger("Invalid CDP command received from Playwright");
280
+ cdpRelayDebug("Invalid CDP command received from Playwright");
283
281
  return;
284
282
  }
285
- debugLogger("← Playwright:", `${message.method} (id=${message.id})`);
283
+ cdpRelayDebug("← Playwright:", `${message.method} (id=${message.id})`);
286
284
  const { id, sessionId, method, params } = message;
287
285
  try {
288
286
  const result = await this._handleCDPCommand(method, params, sessionId);
289
287
  this._sendToPlaywright({ id, sessionId, result });
290
288
  } catch (e) {
291
- debugLogger("Error in the extension:", e);
289
+ cdpRelayDebug("Error in the extension:", e);
292
290
  this._sendToPlaywright({
293
291
  id,
294
292
  sessionId,
@@ -319,7 +317,7 @@ ${truncatedData}...
319
317
  targetInfo,
320
318
  sessionId: `pw-tab-${this._nextSessionId++}`
321
319
  };
322
- debugLogger("Simulating auto-attach");
320
+ cdpRelayDebug("Simulating auto-attach");
323
321
  this._sendToPlaywright({
324
322
  method: "Target.attachedToTarget",
325
323
  params: {
@@ -358,7 +356,7 @@ ${truncatedData}...
358
356
  }
359
357
  _sendToPlaywright(message) {
360
358
  const messageDesc = message.method ?? `response(id=${message.id})`;
361
- debugLogger("→ Playwright:", messageDesc);
359
+ cdpRelayDebug("→ Playwright:", messageDesc);
362
360
  this._playwrightConnection?.send(JSON.stringify(message));
363
361
  }
364
362
  }
@@ -387,7 +385,7 @@ class ExtensionConnection {
387
385
  });
388
386
  }
389
387
  close(message) {
390
- debugLogger("closing extension connection:", message);
388
+ cdpRelayDebug("closing extension connection:", message);
391
389
  if (this._ws.readyState === WebSocket.OPEN) {
392
390
  this._ws.close(1000, message);
393
391
  }
@@ -395,7 +393,7 @@ class ExtensionConnection {
395
393
  _parseJsonSafely(jsonString) {
396
394
  try {
397
395
  if (jsonString.includes("__proto__") || jsonString.includes("constructor") || jsonString.includes("prototype")) {
398
- debugLogger("Potential prototype pollution attempt detected");
396
+ cdpRelayDebug("Potential prototype pollution attempt detected");
399
397
  return null;
400
398
  }
401
399
  const result = JSON.parse(jsonString);
@@ -405,7 +403,7 @@ class ExtensionConnection {
405
403
  this._sanitizeJsonObject(result);
406
404
  return result;
407
405
  } catch (error) {
408
- debugLogger("JSON parsing failed:", error);
406
+ cdpRelayDebug("JSON parsing failed:", error);
409
407
  return null;
410
408
  }
411
409
  }
@@ -427,13 +425,13 @@ class ExtensionConnection {
427
425
  _onMessage(event) {
428
426
  const eventData = event.toString();
429
427
  if (eventData.length > 1048576) {
430
- debugLogger("<closing ws> Message too large, closing websocket");
428
+ cdpRelayDebug("<closing ws> Message too large, closing websocket");
431
429
  this._ws.close();
432
430
  return;
433
431
  }
434
432
  const parsedJson = this._parseJsonSafely(eventData);
435
433
  if (parsedJson === null) {
436
- debugLogger(`<closing ws> Closing websocket due to malformed JSON. eventData=${eventData.slice(0, 200)}...`);
434
+ cdpRelayDebug(`<closing ws> Closing websocket due to malformed JSON. eventData=${eventData.slice(0, 200)}...`);
437
435
  this._ws.close();
438
436
  return;
439
437
  }
@@ -441,7 +439,7 @@ class ExtensionConnection {
441
439
  this._handleParsedMessage(parsedJson);
442
440
  } catch (e) {
443
441
  const errorMessage = e?.message;
444
- debugLogger(`<closing ws> Closing websocket due to failed onmessage callback. eventData=${eventData} e=${errorMessage}`);
442
+ cdpRelayDebug(`<closing ws> Closing websocket due to failed onmessage callback. eventData=${eventData} e=${errorMessage}`);
445
443
  this._ws.close();
446
444
  }
447
445
  }
@@ -460,18 +458,18 @@ class ExtensionConnection {
460
458
  callback.resolve(object.result);
461
459
  }
462
460
  } else if (object.id) {
463
- debugLogger("← Extension: unexpected response", object);
461
+ cdpRelayDebug("← Extension: unexpected response", object);
464
462
  } else if (object.method) {
465
463
  this.onmessage?.(object.method, object.params ?? {});
466
464
  }
467
465
  }
468
466
  _onClose(event) {
469
- debugLogger(`<ws closed> code=${event.code} reason=${event.reason}`);
467
+ cdpRelayDebug(`<ws closed> code=${event.code} reason=${event.reason}`);
470
468
  this._dispose();
471
469
  this.onclose?.(this, event.reason);
472
470
  }
473
471
  _onError(event) {
474
- debugLogger(`<ws error> message=${event.message} type=${event.type} target=${String(event.target)}`);
472
+ cdpRelayDebug(`<ws error> message=${event.message} type=${event.type} target=${String(event.target)}`);
475
473
  this._dispose();
476
474
  }
477
475
  _dispose() {
@@ -18,11 +18,10 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/extension/extension-context-factory.ts
21
- import debug from "debug";
22
21
  import { chromium } from "playwright";
23
22
  import { startHttpServer } from "../http-server.js";
23
+ import { extensionContextFactoryDebug } from "../utils/log.js";
24
24
  import { CDPRelayServer } from "./cdp-relay.js";
25
- var debugLogger = debug("pw:mcp:relay");
26
25
 
27
26
  class ExtensionContextFactory {
28
27
  name = "extension";
@@ -39,7 +38,7 @@ class ExtensionContextFactory {
39
38
  return {
40
39
  browserContext: browser.contexts()[0],
41
40
  close: async () => {
42
- debugLogger("close() called for browser context");
41
+ extensionContextFactoryDebug("close() called for browser context");
43
42
  await browser.close();
44
43
  this._browserPromise = undefined;
45
44
  }
@@ -53,14 +52,14 @@ class ExtensionContextFactory {
53
52
  const browser = await chromium.connectOverCDP(relay.cdpEndpoint());
54
53
  browser.on("disconnected", () => {
55
54
  this._browserPromise = undefined;
56
- debugLogger("Browser disconnected");
55
+ extensionContextFactoryDebug("Browser disconnected");
57
56
  });
58
57
  return browser;
59
58
  }
60
59
  async _startRelay(abortSignal) {
61
60
  const httpServer = await startHttpServer({});
62
61
  const cdpRelayServer = new CDPRelayServer(httpServer, this._browserChannel);
63
- debugLogger(`CDP relay server started, extension endpoint: ${cdpRelayServer.extensionEndpoint()}.`);
62
+ extensionContextFactoryDebug(`CDP relay server started, extension endpoint: ${cdpRelayServer.extensionEndpoint()}.`);
64
63
  if (abortSignal.aborted) {
65
64
  cdpRelayServer.stop();
66
65
  } else {
@@ -23,7 +23,7 @@ import { ListRootsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
23
23
  import { BrowserServerBackend } from "./browser-server-backend.js";
24
24
  import { InProcessTransport } from "./mcp/in-process-transport.js";
25
25
  import { createServer } from "./mcp/server.js";
26
- import { packageJSON } from "./package.js";
26
+ import { packageJSON } from "./utils/package.js";
27
27
 
28
28
  class InProcessClientFactory {
29
29
  name;
package/lib/loop/loop.js CHANGED
@@ -18,8 +18,8 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/loop/loop.ts
21
- import debug from "debug";
22
21
  import { getErrorMessage } from "../utils/common-formatters.js";
22
+ import { historyDebug, toolDebug } from "../utils/log.js";
23
23
  async function runTask(delegate, client, task, oneShot = false) {
24
24
  const { tools } = await client.listTools();
25
25
  const taskContent = createTaskContent(task, oneShot);
@@ -44,7 +44,7 @@ function shouldTerminateLoop(result, oneShot) {
44
44
  return result.isDone || oneShot;
45
45
  }
46
46
  async function executeIteration(delegate, client, conversation, iteration) {
47
- debug("history")("Making API call for iteration", iteration);
47
+ historyDebug("Making API call for iteration", iteration);
48
48
  const toolCalls = await delegate.makeApiCall(conversation);
49
49
  validateToolCallsPresent(toolCalls);
50
50
  const { toolResults, isDone } = await processToolCalls(delegate, client, toolCalls);
@@ -138,14 +138,14 @@ function shouldBreakOnError(result, toolCalls, currentToolCall, toolResults) {
138
138
  async function executeToolCall(client, toolCall) {
139
139
  const { name, arguments: args, id } = toolCall;
140
140
  try {
141
- debug("tool")(name, args);
141
+ toolDebug(name, args);
142
142
  const response = await client.callTool({ name, arguments: args });
143
143
  const responseContent = response.content ?? [];
144
- debug("tool")(responseContent);
144
+ toolDebug(responseContent);
145
145
  const text = extractTextFromResponse(responseContent);
146
146
  return { toolCallId: id, content: text };
147
147
  } catch (error) {
148
- debug("tool")(error);
148
+ toolDebug(error);
149
149
  return {
150
150
  toolCallId: id,
151
151
  content: `Error while executing tool "${name}": ${getErrorMessage(error)}
@@ -20,7 +20,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
20
  // src/loopTools/main.ts
21
21
  import dotenv from "dotenv";
22
22
  import { start } from "../mcp/transport.js";
23
- import { packageJSON } from "../package.js";
23
+ import { packageJSON } from "../utils/package.js";
24
24
  import { Context } from "./context.js";
25
25
  import { perform } from "./perform.js";
26
26
  import { snapshot } from "./snapshot.js";
@@ -19,9 +19,9 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/mcp/proxy-backend.ts
21
21
  import { z } from "zod";
22
- import { logUnhandledError } from "../log.js";
23
- import { packageJSON } from "../package.js";
24
22
  import { defineTool } from "../tools/tool.js";
23
+ import { logUnhandledError } from "../utils/log.js";
24
+ import { packageJSON } from "../utils/package.js";
25
25
 
26
26
  class ProxyBackend {
27
27
  name = "Playwright MCP Client Switcher";
package/lib/mcp/server.js CHANGED
@@ -23,13 +23,11 @@ import {
23
23
  CallToolRequestSchema,
24
24
  ListToolsRequestSchema
25
25
  } from "@modelcontextprotocol/sdk/types.js";
26
- import debug from "debug";
27
26
  import { z } from "zod";
28
27
  import { zodToJsonSchema } from "zod-to-json-schema";
29
- import { logUnhandledError } from "../log.js";
30
28
  import { ManualPromise } from "../manual-promise.js";
29
+ import { logUnhandledError, mcpServerDebug } from "../utils/log.js";
31
30
  import { logRequest } from "../utils/request-logger.js";
32
- var serverDebug = debug("pw:mcp:server");
33
31
  async function connect(serverBackendFactory, transport, runHeartbeat) {
34
32
  const backend = serverBackendFactory();
35
33
  const server = createServer(backend, runHeartbeat);
@@ -98,16 +96,16 @@ var startHeartbeat = (server) => {
98
96
  ]);
99
97
  setTimeout(beat, 3000);
100
98
  } catch (error) {
101
- serverDebug("Heartbeat ping failed:", error);
99
+ mcpServerDebug("Heartbeat ping failed:", error);
102
100
  try {
103
101
  await server.close();
104
102
  } catch (closeError) {
105
- serverDebug("Failed to close server after heartbeat failure:", closeError);
103
+ mcpServerDebug("Failed to close server after heartbeat failure:", closeError);
106
104
  }
107
105
  }
108
106
  };
109
107
  beat().catch((error) => {
110
- serverDebug("Heartbeat initialization failed:", error);
108
+ mcpServerDebug("Heartbeat initialization failed:", error);
111
109
  });
112
110
  };
113
111
  function addServerListener(server, event, listener) {
@@ -17,17 +17,23 @@ var __toESM = (mod, isNodeMode, target) => {
17
17
  };
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
- // src/log.ts
21
- import debug from "debug";
22
- var errorsDebug = debug("pw:mcp:errors");
23
- var requestsDebug = debug("pw:mcp:requests");
24
- function logUnhandledError(error) {
25
- errorsDebug(error);
20
+ // src/mcp/tool.ts
21
+ import { zodToJsonSchema } from "zod-to-json-schema";
22
+ function toMcpTool(tool) {
23
+ return {
24
+ name: tool.name,
25
+ description: tool.description,
26
+ inputSchema: zodToJsonSchema(tool.inputSchema, {
27
+ strictUnions: true
28
+ }),
29
+ annotations: {
30
+ title: tool.title,
31
+ readOnlyHint: tool.type === "readOnly",
32
+ destructiveHint: tool.type === "destructive",
33
+ openWorldHint: true
34
+ }
35
+ };
26
36
  }
27
- var testDebug = debug("pw:mcp:test");
28
- var requestDebug = requestsDebug;
29
37
  export {
30
- testDebug,
31
- requestDebug,
32
- logUnhandledError
38
+ toMcpTool
33
39
  };
@@ -22,9 +22,9 @@ import crypto from "node:crypto";
22
22
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
23
23
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
24
24
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
25
- import debug from "debug";
26
25
  import { httpAddressToString, startHttpServer } from "../http-server.js";
27
26
  import { connect } from "./server.js";
27
+ import { mcpTransportDebug, testDebug } from "../utils/log.js";
28
28
  async function start(serverBackendFactory, options) {
29
29
  if (options.port !== undefined) {
30
30
  const httpServer = await startHttpServer(options);
@@ -36,8 +36,6 @@ async function start(serverBackendFactory, options) {
36
36
  async function startStdioTransport(serverBackendFactory) {
37
37
  await connect(serverBackendFactory, new StdioServerTransport, false);
38
38
  }
39
- var testDebug = debug("pw:mcp:test");
40
- var transportDebug = debug("pw:mcp:transport");
41
39
  async function handleSSE(serverBackendFactory, req, res, url, sessions) {
42
40
  if (req.method === "POST") {
43
41
  const sessionId = url.searchParams.get("sessionId");
@@ -152,7 +150,7 @@ function startHttpTransport(httpServer, serverBackendFactory) {
152
150
  "For legacy SSE transport support, you can use the /sse endpoint instead."
153
151
  ].join(`
154
152
  `);
155
- transportDebug("Server listening:", message);
153
+ mcpTransportDebug("Server listening:", message);
156
154
  }
157
155
  export {
158
156
  start