Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/_internal/browser-eval-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,16 @@ export async function stopBrowserEvalMCP(): Promise<void> {
}

/**
* Cleanup on process exit
* Cleanup on process exit.
* Signal handling and process.exit() are intentionally left to src/index.ts
* so there is a single, ordered shutdown sequence. These listeners only close
* the Playwright MCP connection; they do not call process.exit() themselves.
*/
process.on("SIGINT", async () => {
await stopBrowserEvalMCP()
process.exit(0)
})

process.on("SIGTERM", async () => {
await stopBrowserEvalMCP()
process.exit(0)
})

12 changes: 11 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,19 @@ async function main() {

log('Server started')

const shutdown = () => {
const shutdown = async () => {
log('Server terminated')

// Close the MCP server transport before exiting so the host (e.g. Claude
// Code) receives a clean EOF on the stdio channel instead of an abrupt
// disconnect. Without this the host reports "MCP server failed" even
// though the exit code is 0.
try {
await server.close()
} catch {
// Ignore close errors during shutdown
}

const aggregationJSON = getSessionAggregationJSON()

if (aggregationJSON) {
Expand Down