From be1b9514d3182e7ea468ee746422030a8ec82248 Mon Sep 17 00:00:00 2001 From: "Tommy D. Rossi" Date: Wed, 31 Dec 2025 16:15:17 +0100 Subject: [PATCH] Add ping/pong keep-alive to prevent service worker termination --- extension/manifest.json | 2 +- extension/package.json | 2 +- playwriter/src/cdp-relay.ts | 25 +++++++++++++++++++++++-- playwriter/src/protocol.ts | 15 ++++++++++++++- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/extension/manifest.json b/extension/manifest.json index 54e8ffd..53d540c 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Playwriter MCP", - "version": "0.0.61", + "version": "0.0.64", "description": "Automate your Browser using Cursor, Claude, VS Code. More capable and context efficient than Playwright MCP.", "permissions": ["debugger", "tabGroups", "contextMenus", "tabs"], "host_permissions": [""], diff --git a/extension/package.json b/extension/package.json index b3e0bbb..d463a32 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,6 +1,6 @@ { "name": "mcp-extension", - "version": "0.0.61", + "version": "0.0.64", "description": "Playwright MCP Browser Extension", "private": true, "repository": { diff --git a/playwriter/src/cdp-relay.ts b/playwriter/src/cdp-relay.ts index 8cff367..12cbd17 100644 --- a/playwriter/src/cdp-relay.ts +++ b/playwriter/src/cdp-relay.ts @@ -41,6 +41,23 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127. reject: (error: Error) => void }>() let extensionMessageId = 0 + let extensionPingInterval: ReturnType | null = null + + function startExtensionPing() { + if (extensionPingInterval) { + clearInterval(extensionPingInterval) + } + extensionPingInterval = setInterval(() => { + extensionWs?.send(JSON.stringify({ method: 'ping' })) + }, 5000) + } + + function stopExtensionPing() { + if (extensionPingInterval) { + clearInterval(extensionPingInterval) + extensionPingInterval = null + } + } function logCdpMessage({ direction, @@ -504,6 +521,7 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127. } extensionWs = ws + startExtensionPing() logger?.log('Extension connected with clean state') }, @@ -517,7 +535,7 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127. return } - if ('id' in message) { + if (message.id !== undefined) { const pending = extensionPendingRequests.get(message.id) if (!pending) { logger?.log('Unexpected response with id:', message.id) @@ -531,6 +549,8 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127. } else { pending.resolve(message.result) } + } else if (message.method === 'pong') { + // Keep-alive response, nothing to do } else if (message.method === 'log') { const { level, args } = message.params const logFn = (logger as any)?.[level] || logger?.log @@ -681,7 +701,8 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127. }, onClose(event, ws) { - logger?.log('Extension disconnected') + logger?.log(`Extension disconnected: code=${event.code} reason=${event.reason || 'none'}`) + stopExtensionPing() // If this is an old connection closing after we've already established a new one, // don't clear the global state diff --git a/playwriter/src/protocol.ts b/playwriter/src/protocol.ts index 52fe15c..f86330a 100644 --- a/playwriter/src/protocol.ts +++ b/playwriter/src/protocol.ts @@ -19,6 +19,7 @@ export type ExtensionCommandMessage = ForwardCDPCommand export type ExtensionResponseMessage = { id: number + method?: undefined result?: any error?: string } @@ -30,6 +31,7 @@ export type ExtensionResponseMessage = { export type ExtensionEventMessage = { [K in keyof ProtocolMapping.Events]: { + id?: undefined method: 'forwardCDPEvent' params: { method: CDPEventFor['method'] @@ -40,6 +42,7 @@ export type ExtensionEventMessage = }[keyof ProtocolMapping.Events] export type ExtensionLogMessage = { + id?: undefined method: 'log' params: { level: 'log' | 'debug' | 'info' | 'warn' | 'error' @@ -47,4 +50,14 @@ export type ExtensionLogMessage = { } } -export type ExtensionMessage = ExtensionResponseMessage | ExtensionEventMessage | ExtensionLogMessage +export type ExtensionPongMessage = { + id?: undefined + method: 'pong' +} + +export type ServerPingMessage = { + method: 'ping' + id?: undefined +} + +export type ExtensionMessage = ExtensionResponseMessage | ExtensionEventMessage | ExtensionLogMessage | ExtensionPongMessage