Skip to content

Commit 429444d

Browse files
committed
feat: fetching data before format to preserve format sync
1 parent e2b9470 commit 429444d

File tree

4 files changed

+181
-93
lines changed

4 files changed

+181
-93
lines changed

src/McpResponse.ts

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import type {
77
ImageContent,
88
TextContent,
99
} from '@modelcontextprotocol/sdk/types.js';
10-
import type {ResourceType} from 'puppeteer-core';
10+
import type { HTTPRequest, HTTPResponse, ResourceType } from 'puppeteer-core';
1111

12-
import {formatConsoleEvent} from './formatters/consoleFormatter.js';
12+
import { formatConsoleEvent } from './formatters/consoleFormatter.js';
1313
import {
1414
getFormattedHeaderValue,
1515
getFormattedResponseBody,
@@ -18,16 +18,23 @@ import {
1818
getStatusFromRequest,
1919
BODY_CONTEXT_SIZE_LIMIT,
2020
} from './formatters/networkFormatter.js';
21-
import {formatA11ySnapshot} from './formatters/snapshotFormatter.js';
22-
import type {McpContext} from './McpContext.js';
23-
import {handleDialog} from './tools/pages.js';
24-
import type {ImageContentData, Response} from './tools/ToolDefinition.js';
25-
import {paginate, type PaginationOptions} from './utils/pagination.js';
21+
import { formatA11ySnapshot } from './formatters/snapshotFormatter.js';
22+
import { McpContext } from './McpContext.js';
23+
import { handleDialog } from './tools/pages.js';
24+
import type { ImageContentData, Response } from './tools/ToolDefinition.js';
25+
26+
import { paginate, type PaginationOptions } from './utils/pagination.js';
27+
28+
export type NetworkRequestData = {
29+
networkRequestUrl: string;
30+
requestBody: string | null;
31+
responseBody: string | null;
32+
}
2633

2734
export class McpResponse implements Response {
2835
#includePages = false;
2936
#includeSnapshot = false;
30-
#attachedNetworkRequestUrl?: string;
37+
#attachedNetworkRequestData?: NetworkRequestData;
3138
#includeConsoleData = false;
3239
#textResponseLines: string[] = [];
3340
#formattedConsoleData?: string[];
@@ -64,9 +71,9 @@ export class McpResponse implements Response {
6471
pagination:
6572
options?.pageSize || options?.pageIdx
6673
? {
67-
pageSize: options.pageSize,
68-
pageIdx: options.pageIdx,
69-
}
74+
pageSize: options.pageSize,
75+
pageIdx: options.pageIdx,
76+
}
7077
: undefined,
7178
resourceTypes: options?.resourceTypes,
7279
};
@@ -77,7 +84,11 @@ export class McpResponse implements Response {
7784
}
7885

7986
attachNetworkRequest(url: string): void {
80-
this.#attachedNetworkRequestUrl = url;
87+
this.#attachedNetworkRequestData = {
88+
networkRequestUrl: url,
89+
responseBody: null,
90+
requestBody: null
91+
};
8192
}
8293

8394
get includePages(): boolean {
@@ -92,7 +103,7 @@ export class McpResponse implements Response {
92103
return this.#includeConsoleData;
93104
}
94105
get attachedNetworkRequestUrl(): string | undefined {
95-
return this.#attachedNetworkRequestUrl;
106+
return this.#attachedNetworkRequestData?.networkRequestUrl;
96107
}
97108
get networkRequestsPageIdx(): number | undefined {
98109
return this.#networkRequestsOptions?.pagination?.pageIdx;
@@ -130,6 +141,14 @@ export class McpResponse implements Response {
130141
}
131142

132143
let formattedConsoleMessages: string[];
144+
145+
if (this.#attachedNetworkRequestData?.networkRequestUrl) {
146+
const request = context.getNetworkRequestByUrl(this.#attachedNetworkRequestData.networkRequestUrl);
147+
148+
this.#attachedNetworkRequestData.requestBody = await this.processRequestBody(request);
149+
this.#attachedNetworkRequestData.responseBody = await this.processResponseBody(request.response());
150+
}
151+
133152
if (this.#includeConsoleData) {
134153
const consoleMessages = context.getConsoleData();
135154
if (consoleMessages) {
@@ -140,13 +159,46 @@ export class McpResponse implements Response {
140159
}
141160
}
142161

143-
return await this.format(toolName, context);
162+
return this.format(toolName, context);
163+
}
164+
165+
async processResponseBody(httpResponse: HTTPResponse | null): Promise<string | null> {
166+
if (!httpResponse) {
167+
return null;
168+
}
169+
170+
const formattedResponseData = await getFormattedResponseBody(
171+
httpResponse,
172+
BODY_CONTEXT_SIZE_LIMIT,
173+
);
174+
if (formattedResponseData.length > 0) {
175+
return formattedResponseData;
176+
}
177+
178+
return null;
179+
}
180+
181+
182+
async processRequestBody(httpRequest: HTTPRequest): Promise<string | null> {
183+
if (!httpRequest) {
184+
return null;
185+
}
186+
187+
const formattedResponseData = await getFormattedRequestBody(
188+
httpRequest,
189+
BODY_CONTEXT_SIZE_LIMIT,
190+
);
191+
if (formattedResponseData.length > 0) {
192+
return formattedResponseData;
193+
}
194+
195+
return null;
144196
}
145197

146-
async format(
198+
format(
147199
toolName: string,
148200
context: McpContext,
149-
): Promise<Array<TextContent | ImageContent>> {
201+
): Array<TextContent | ImageContent> {
150202
const response = [`# ${toolName} response`];
151203
for (const line of this.#textResponseLines) {
152204
response.push(line);
@@ -195,7 +247,7 @@ Call ${handleDialog.name} to handle it before continuing.`);
195247
}
196248
}
197249

198-
response.push(...(await this.#getIncludeNetworkRequestsData(context)));
250+
response.push(...this.#getIncludeNetworkRequestsData(context));
199251

200252
if (this.#networkRequestsOptions?.include) {
201253
let requests = context.getNetworkRequests();
@@ -256,7 +308,7 @@ Call ${handleDialog.name} to handle it before continuing.`);
256308
response.push('Invalid page number provided. Showing first page.');
257309
}
258310

259-
const {startIndex, endIndex, currentPage, totalPages} = paginationResult;
311+
const { startIndex, endIndex, currentPage, totalPages } = paginationResult;
260312
response.push(
261313
`Showing ${startIndex + 1}-${endIndex} of ${data.length} (Page ${currentPage + 1} of ${totalPages}).`,
262314
);
@@ -275,12 +327,13 @@ Call ${handleDialog.name} to handle it before continuing.`);
275327
};
276328
}
277329

278-
async #getIncludeNetworkRequestsData(context: McpContext): Promise<string[]> {
330+
#getIncludeNetworkRequestsData(context: McpContext): string[] {
279331
const response: string[] = [];
280-
const url = this.#attachedNetworkRequestUrl;
332+
const url = this.#attachedNetworkRequestData?.networkRequestUrl;
281333
if (!url) {
282334
return response;
283335
}
336+
284337
const httpRequest = context.getNetworkRequestByUrl(url);
285338
response.push(`## Request ${httpRequest.url()}`);
286339
response.push(`Status: ${getStatusFromRequest(httpRequest)}`);
@@ -289,13 +342,9 @@ Call ${handleDialog.name} to handle it before continuing.`);
289342
response.push(line);
290343
}
291344

292-
const formattedRequestData = await getFormattedRequestBody(
293-
'### Request body',
294-
httpRequest,
295-
BODY_CONTEXT_SIZE_LIMIT,
296-
);
297-
if (formattedRequestData.length > 0) {
298-
response.push(formattedRequestData);
345+
if(this.#attachedNetworkRequestData?.requestBody) {
346+
response.push(`### Request Body`);
347+
response.push(this.#attachedNetworkRequestData.requestBody)
299348
}
300349

301350
const httpResponse = httpRequest.response();
@@ -304,15 +353,11 @@ Call ${handleDialog.name} to handle it before continuing.`);
304353
for (const line of getFormattedHeaderValue(httpResponse.headers())) {
305354
response.push(line);
306355
}
356+
}
307357

308-
const formattedResponseData = await getFormattedResponseBody(
309-
'### Response body',
310-
httpResponse,
311-
BODY_CONTEXT_SIZE_LIMIT,
312-
);
313-
if (formattedResponseData.length > 0) {
314-
response.push(formattedResponseData);
315-
}
358+
if(this.#attachedNetworkRequestData?.responseBody) {
359+
response.push(`### Response Body`);
360+
response.push(this.#attachedNetworkRequestData.responseBody)
316361
}
317362

318363
const httpFailure = httpRequest.failure();

src/formatters/networkFormatter.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ export function getFormattedHeaderValue(
4343
}
4444

4545
export async function getFormattedResponseBody(
46-
title: string,
4746
httpResponse: HTTPResponse,
4847
sizeLimit: number,
4948
): Promise<string> {
@@ -54,36 +53,35 @@ export async function getFormattedResponseBody(
5453
const responseAsTest = responseBuffer.toString('utf-8');
5554

5655
if (responseAsTest.length === 0) {
57-
return `${title}\n<empty response>`;
56+
return `<empty response>`;
5857
}
5958

60-
return `${title}\n${getSizeLimitedString(responseAsTest, sizeLimit)}`;
59+
return `${getSizeLimitedString(responseAsTest, sizeLimit)}`;
6160
}
6261

63-
return `${title}\n<binary data>`;
62+
return `<binary data>`;
6463
} catch {
6564
// buffer() call might fail with CDP exception, in this case we don't print anything in the context
6665
return '';
6766
}
6867
}
6968

7069
export async function getFormattedRequestBody(
71-
title: string,
7270
httpRequest: HTTPRequest,
7371
sizeLimit: number,
7472
): Promise<string> {
7573
if (httpRequest.hasPostData()) {
7674
const data = httpRequest.postData();
7775

7876
if (data) {
79-
return `${title}\n${getSizeLimitedString(data, sizeLimit)}`;
77+
return `${getSizeLimitedString(data, sizeLimit)}`;
8078
}
8179

8280
try {
8381
const fetchData = await httpRequest.fetchPostData();
8482

8583
if (fetchData) {
86-
return `${title}\n${getSizeLimitedString(fetchData, sizeLimit)}`;
84+
return `${getSizeLimitedString(fetchData, sizeLimit)}`;
8785
}
8886
} catch {
8987
// fetchPostData() call might fail with CDP exception, in this case we don't print anything in the context

0 commit comments

Comments
 (0)