Add unified mcpLog for relay server and stderr logging

This commit is contained in:
Tommy D. Rossi
2025-12-31 22:41:32 +01:00
parent 240ce5be74
commit c15cf5947a
4 changed files with 31 additions and 20 deletions
+22 -12
View File
@@ -189,6 +189,15 @@ async function sendLogToRelayServer(level: string, ...args: any[]) {
}
}
/**
* Log to both console.error (for early startup) and relay server log file.
* Fire-and-forget to avoid blocking.
*/
function mcpLog(...args: any[]) {
console.error(...args)
sendLogToRelayServer('log', ...args)
}
async function getServerVersion(port: number): Promise<string | null> {
try {
const response = await fetch(`http://127.0.0.1:${port}/version`, {
@@ -246,10 +255,10 @@ async function ensureRelayServer(): Promise<void> {
}
if (serverVersion !== null) {
console.error(`CDP relay server version mismatch (server: ${serverVersion}, mcp: ${VERSION}), restarting...`)
mcpLog(`CDP relay server version mismatch (server: ${serverVersion}, mcp: ${VERSION}), restarting...`)
await killRelayServer(RELAY_PORT)
} else {
console.error('CDP relay server not running, starting it...')
mcpLog('CDP relay server not running, starting it...')
}
const scriptPath = require.resolve('../dist/start-relay-server.js')
@@ -265,7 +274,7 @@ async function ensureRelayServer(): Promise<void> {
await sleep(500)
const newVersion = await getServerVersion(RELAY_PORT)
if (newVersion === VERSION) {
console.error('CDP relay server started successfully, waiting for extension to connect...')
mcpLog('CDP relay server started successfully, waiting for extension to connect...')
await sleep(1000)
return
}
@@ -370,7 +379,7 @@ function setupPageConsoleListener(page: Page) {
pageLogs.shift()
}
} catch (e) {
console.error('[MCP] Failed to get console message text:', e)
mcpLog('[MCP] Failed to get console message text:', e)
return
}
})
@@ -402,7 +411,7 @@ async function resetConnection(): Promise<{ browser: Browser; page: Page; contex
try {
await state.browser.close()
} catch (e) {
console.error('Error closing browser:', e)
mcpLog('Error closing browser:', e)
}
}
@@ -547,7 +556,7 @@ server.tool(
const page = await getCurrentPage(timeout)
const context = state.context || page.context()
console.error('Executing code:', code)
mcpLog('Executing code:', code)
const customConsole = {
log: (...args: any[]) => {
@@ -813,15 +822,16 @@ server.tool(
}
} catch (error: any) {
const errorStack = error.stack || error.message
const isTimeoutError = error instanceof CodeExecutionTimeoutError || error.name === 'TimeoutError'
// Always log to stderr, but only send non-timeout errors to relay server
console.error('Error in execute tool:', errorStack)
if (!isTimeoutError) {
sendLogToRelayServer('error', 'Error in execute tool:', errorStack)
}
const logsText = formatConsoleLogs(consoleLogs, 'Console output (before error)')
const isTimeoutError = error instanceof CodeExecutionTimeoutError || error.name === 'TimeoutError'
if (!isTimeoutError) {
sendLogToRelayServer('error', '[MCP] Error:', errorStack)
}
const resetHint = isTimeoutError
? ''
: '\n\n[HINT: If this is an internal Playwright error, page/browser closed, or connection issue, call the `reset` tool to reconnect. Do NOT reset for other non-connection non-internal errors.]'
@@ -908,7 +918,7 @@ export async function startMcp(options: { host?: string; token?: string } = {})
if (!remote) {
await ensureRelayServer()
} else {
console.error(`Using remote CDP relay server: ${remote.host}:${remote.port}`)
mcpLog(`Using remote CDP relay server: ${remote.host}:${remote.port}`)
await checkRemoteServer(remote)
}
const transport = new StdioServerTransport()
+4 -3
View File
@@ -3,7 +3,7 @@
## Types
```ts
import type { CDPSession } from './cdp-session.js';
import type { ICDPSession } from './cdp-session.js';
export interface BreakpointInfo {
id: string;
file: string;
@@ -57,7 +57,8 @@ export declare class Debugger {
* Creates a new Debugger instance.
*
* @param options - Configuration options
* @param options.cdp - A CDPSession instance for sending CDP commands
* @param options.cdp - A CDPSession instance for sending CDP commands (works with both
* our CDPSession and Playwright's CDPSession)
*
* @example
* ```ts
@@ -66,7 +67,7 @@ export declare class Debugger {
* ```
*/
constructor({ cdp }: {
cdp: CDPSession;
cdp: ICDPSession;
});
private setupEventListeners;
/**
+2 -2
View File
@@ -5,7 +5,7 @@ The Editor class provides a Claude Code-like interface for viewing and editing w
## Types
```ts
import type { CDPSession } from './cdp-session.js';
import type { ICDPSession } from './cdp-session.js';
export interface ReadResult {
content: string;
totalLines: number;
@@ -55,7 +55,7 @@ export declare class Editor {
private stylesheets;
private sourceCache;
constructor({ cdp }: {
cdp: CDPSession;
cdp: ICDPSession;
});
private setupEventListeners;
/**
+3 -3
View File
@@ -5,7 +5,7 @@ The getStylesForLocator function inspects CSS styles applied to an element, simi
## Types
```ts
import type { CDPSession } from './cdp-session.js';
import type { ICDPSession } from './cdp-session.js';
import type { Locator } from 'playwright-core';
export interface StyleSource {
url: string;
@@ -25,9 +25,9 @@ export interface StylesResult {
inlineStyle: StyleDeclarations | null;
rules: StyleRule[];
}
export declare function getStylesForLocator({ locator, cdp, includeUserAgentStyles, }: {
export declare function getStylesForLocator({ locator, cdp: cdpSession, includeUserAgentStyles, }: {
locator: Locator;
cdp: CDPSession;
cdp: ICDPSession;
includeUserAgentStyles?: boolean;
}): Promise<StylesResult>;
export declare function formatStylesAsText(styles: StylesResult): string;