From 69bc0977d6d57fb113f2793612298c451506b790 Mon Sep 17 00:00:00 2001 From: Alan Date: Sun, 3 May 2026 21:15:03 +0800 Subject: [PATCH] fix: use async response status in network request list and detail views `getShortDescriptionForRequest` and `getStatusFromRequest` in the list/detail views were synchronous but Playwright's `request.response()` is async, so all requests showed `[pending]` even after the page finished loading. Requests where `request.failure()` was set (e.g. beacon/analytics) also showed `[failed - net::ERR_ABORTED]` even though they completed successfully. Add `getShortDescriptionForRequestAsync` that calls the existing `getStatusFromRequestAsync`, and wire it into `McpResponse.format()` and `#formatNetworkRequestData()` so list, detail, and redirect-chain views all show the real HTTP status code. Co-Authored-By: Claude Opus 4.7 --- src/McpResponse.ts | 18 ++++++++++-------- src/formatters/networkFormatter.ts | 9 +++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/McpResponse.ts b/src/McpResponse.ts index f827245..fd4af36 100644 --- a/src/McpResponse.ts +++ b/src/McpResponse.ts @@ -17,7 +17,9 @@ import { getFormattedResponseBody, getFormattedRequestBody, getShortDescriptionForRequest, + getShortDescriptionForRequestAsync, getStatusFromRequest, + getStatusFromRequestAsync, } from './formatters/networkFormatter.js'; import { formatWebSocketConnectionShort, @@ -344,7 +346,7 @@ export class McpResponse implements Response { }); } - format( + async format( toolName: string, context: McpContext, data: { @@ -355,7 +357,7 @@ export class McpResponse implements Response { consoleData: ConsoleMessageData | undefined; consoleListData: ConsoleMessageData[] | undefined; }, - ): Array { + ): Promise> { const response = [`# ${toolName} response`]; for (const line of this.#textResponseLines) { response.push(line); @@ -397,7 +399,7 @@ export class McpResponse implements Response { } } - response.push(...this.#formatNetworkRequestData(context, data.bodies)); + response.push(...await this.#formatNetworkRequestData(context, data.bodies)); response.push(...this.#formatConsoleData(data.consoleData)); if (this.#networkRequestsOptions?.include) { @@ -437,7 +439,7 @@ export class McpResponse implements Response { response.push(...data.info); for (const request of data.items) { response.push( - getShortDescriptionForRequest( + await getShortDescriptionForRequestAsync( request, context.getNetworkRequestStableId(request), context.getNetworkRequestStableId(request) === @@ -565,13 +567,13 @@ export class McpResponse implements Response { return response; } - #formatNetworkRequestData( + async #formatNetworkRequestData( context: McpContext, data: { requestBody?: string; responseBody?: string; }, - ): string[] { + ): Promise { const response: string[] = []; const id = this.#attachedNetworkRequestId; if (!id) { @@ -580,7 +582,7 @@ export class McpResponse implements Response { const httpRequest = context.getNetworkRequestById(id); response.push(`## Request ${httpRequest.url()}`); - response.push(`Status: ${getStatusFromRequest(httpRequest)}`); + response.push(`Status: ${await getStatusFromRequestAsync(httpRequest)}`); response.push(`### Request Headers`); for (const line of getFormattedHeaderValue(httpRequest.headers())) { response.push(line); @@ -617,7 +619,7 @@ export class McpResponse implements Response { let indent = 0; for (const request of redirectChain.reverse()) { response.push( - `${' '.repeat(indent)}${getShortDescriptionForRequest(request, context.getNetworkRequestStableId(request))}`, + `${' '.repeat(indent)}${await getShortDescriptionForRequestAsync(request, context.getNetworkRequestStableId(request))}`, ); indent++; } diff --git a/src/formatters/networkFormatter.ts b/src/formatters/networkFormatter.ts index 7bb8c7f..766debd 100644 --- a/src/formatters/networkFormatter.ts +++ b/src/formatters/networkFormatter.ts @@ -28,6 +28,15 @@ export function getShortDescriptionForRequest( return `reqid=${id} [${request.resourceType()}] ${request.method()} ${request.url()} ${getStatusFromRequest(request)}${selectedInDevToolsUI ? ` [selected in the DevTools Network panel]` : ''}`; } +export async function getShortDescriptionForRequestAsync( + request: HTTPRequest, + id: number, + selectedInDevToolsUI = false, +): Promise { + const status = await getStatusFromRequestAsync(request); + return `reqid=${id} [${request.resourceType()}] ${request.method()} ${request.url()} ${status}${selectedInDevToolsUI ? ` [selected in the DevTools Network panel]` : ''}`; +} + export function getStatusFromRequest(request: HTTPRequest): string { // In Playwright, request.response() is async, but we cache the failure info const failure = request.failure();