@ejazullah/browser-mcp 0.0.64 → 0.0.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/config.js +2 -0
- package/lib/program.js +1 -0
- package/lib/response.js +39 -5
- package/lib/tools/snapshot.js +4 -2
- package/package.json +1 -1
package/lib/config.js
CHANGED
|
@@ -134,6 +134,7 @@ export function configFromCLIOptions(cliOptions) {
|
|
|
134
134
|
saveTrace: cliOptions.saveTrace,
|
|
135
135
|
outputDir: cliOptions.outputDir,
|
|
136
136
|
imageResponses: cliOptions.imageResponses,
|
|
137
|
+
maxResponseChars: cliOptions.maxResponseChars ? parseInt(cliOptions.maxResponseChars, 10) : undefined,
|
|
137
138
|
mongodb: {
|
|
138
139
|
url: cliOptions.mongodbUrl,
|
|
139
140
|
dbName: cliOptions.mongodbDb,
|
|
@@ -166,6 +167,7 @@ function configFromEnv() {
|
|
|
166
167
|
options.isolated = envToBoolean(process.env.PLAYWRIGHT_MCP_ISOLATED);
|
|
167
168
|
if (process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES === 'omit')
|
|
168
169
|
options.imageResponses = 'omit';
|
|
170
|
+
options.maxResponseChars = envToString(process.env.PLAYWRIGHT_MCP_MAX_RESPONSE_CHARS);
|
|
169
171
|
options.sandbox = envToBoolean(process.env.PLAYWRIGHT_MCP_SANDBOX);
|
|
170
172
|
options.outputDir = envToString(process.env.PLAYWRIGHT_MCP_OUTPUT_DIR);
|
|
171
173
|
options.port = envToNumber(process.env.PLAYWRIGHT_MCP_PORT);
|
package/lib/program.js
CHANGED
|
@@ -65,6 +65,7 @@ program
|
|
|
65
65
|
.option('--ignore-https-errors', 'ignore https errors')
|
|
66
66
|
.option('--isolated', 'keep the browser profile in memory, do not save it to disk.')
|
|
67
67
|
.option('--image-responses <mode>', 'whether to send image responses to the client. Can be "allow" or "omit", Defaults to "allow".')
|
|
68
|
+
.option('--max-response-chars <number>', 'Maximum characters to send in a single response. Default is 100000.')
|
|
68
69
|
.option('--no-sandbox', 'disable the sandbox for all process types that are normally sandboxed.')
|
|
69
70
|
.option('--output-dir <path>', 'path to the directory for output files.')
|
|
70
71
|
.option('--port <port>', 'port to listen on for SSE transport.')
|
package/lib/response.js
CHANGED
|
@@ -20,6 +20,7 @@ export class Response {
|
|
|
20
20
|
_images = [];
|
|
21
21
|
_context;
|
|
22
22
|
_includeSnapshot = false;
|
|
23
|
+
_snapshotOffsetLine = 0;
|
|
23
24
|
_includeTabs = false;
|
|
24
25
|
_tabSnapshot;
|
|
25
26
|
_elementInteraction;
|
|
@@ -56,8 +57,11 @@ export class Response {
|
|
|
56
57
|
images() {
|
|
57
58
|
return this._images;
|
|
58
59
|
}
|
|
59
|
-
setIncludeSnapshot() {
|
|
60
|
+
setIncludeSnapshot(offsetLine) {
|
|
60
61
|
this._includeSnapshot = true;
|
|
62
|
+
if (offsetLine !== undefined) {
|
|
63
|
+
this._snapshotOffsetLine = offsetLine;
|
|
64
|
+
}
|
|
61
65
|
}
|
|
62
66
|
setIncludeTabs() {
|
|
63
67
|
this._includeTabs = true;
|
|
@@ -104,12 +108,20 @@ ${this._code.join('\n')}
|
|
|
104
108
|
response.push('');
|
|
105
109
|
}
|
|
106
110
|
else if (this._tabSnapshot) {
|
|
107
|
-
response.
|
|
111
|
+
const currentLength = response.join('\n').length;
|
|
112
|
+
const maxChars = this._context.config.maxResponseChars ?? 100000;
|
|
113
|
+
const remainingBudget = Math.max(1000, maxChars - currentLength);
|
|
114
|
+
response.push(renderTabSnapshot(this._tabSnapshot, remainingBudget, this._snapshotOffsetLine));
|
|
108
115
|
response.push('');
|
|
109
116
|
}
|
|
110
117
|
// Main response part
|
|
118
|
+
let responseText = response.join('\n');
|
|
119
|
+
const maxChars = this._context.config.maxResponseChars ?? 100000;
|
|
120
|
+
if (responseText.length > maxChars) {
|
|
121
|
+
responseText = responseText.slice(0, maxChars - 100) + '\n\n... [Response truncated due to length limits]';
|
|
122
|
+
}
|
|
111
123
|
const content = [
|
|
112
|
-
{ type: 'text', text:
|
|
124
|
+
{ type: 'text', text: responseText },
|
|
113
125
|
];
|
|
114
126
|
// Image attachments.
|
|
115
127
|
if (this._context.config.imageResponses !== 'omit') {
|
|
@@ -119,7 +131,7 @@ ${this._code.join('\n')}
|
|
|
119
131
|
return { content, isError: this._isError };
|
|
120
132
|
}
|
|
121
133
|
}
|
|
122
|
-
function renderTabSnapshot(tabSnapshot) {
|
|
134
|
+
function renderTabSnapshot(tabSnapshot, maxLength = Infinity, offsetLine = 0) {
|
|
123
135
|
const lines = [];
|
|
124
136
|
if (tabSnapshot.consoleMessages.length) {
|
|
125
137
|
lines.push(`### New console messages`);
|
|
@@ -141,8 +153,30 @@ function renderTabSnapshot(tabSnapshot) {
|
|
|
141
153
|
lines.push(`- Page URL: ${tabSnapshot.url}`);
|
|
142
154
|
lines.push(`- Page Title: ${tabSnapshot.title}`);
|
|
143
155
|
lines.push(`- Page Snapshot:`);
|
|
156
|
+
const prefix = '```yaml\n';
|
|
157
|
+
const suffix = '\n```';
|
|
158
|
+
const currentLength = lines.join('\n').length + prefix.length + suffix.length;
|
|
159
|
+
const budget = maxLength - currentLength;
|
|
160
|
+
let ariaSnapshotLines = tabSnapshot.ariaSnapshot.split('\n');
|
|
161
|
+
if (offsetLine > 0) {
|
|
162
|
+
ariaSnapshotLines = ariaSnapshotLines.slice(offsetLine);
|
|
163
|
+
}
|
|
164
|
+
let includedLines = 0;
|
|
165
|
+
let currentStringLength = 0;
|
|
166
|
+
let truncatedAriaSnapshot = '';
|
|
167
|
+
for (const line of ariaSnapshotLines) {
|
|
168
|
+
if (currentStringLength + line.length + 1 > budget)
|
|
169
|
+
break;
|
|
170
|
+
truncatedAriaSnapshot += line + '\n';
|
|
171
|
+
currentStringLength += line.length + 1;
|
|
172
|
+
includedLines++;
|
|
173
|
+
}
|
|
174
|
+
if (includedLines < ariaSnapshotLines.length) {
|
|
175
|
+
const nextOffset = offsetLine + includedLines;
|
|
176
|
+
truncatedAriaSnapshot += `\n... [ARIA Snapshot truncated due to length limits. To see more, call browser_snapshot with offset set to ${nextOffset}]`;
|
|
177
|
+
}
|
|
144
178
|
lines.push('```yaml');
|
|
145
|
-
lines.push(
|
|
179
|
+
lines.push(truncatedAriaSnapshot.trimEnd());
|
|
146
180
|
lines.push('```');
|
|
147
181
|
return lines.join('\n');
|
|
148
182
|
}
|
package/lib/tools/snapshot.js
CHANGED
|
@@ -23,12 +23,14 @@ const snapshot = defineTool({
|
|
|
23
23
|
name: 'browser_snapshot',
|
|
24
24
|
title: 'Page snapshot',
|
|
25
25
|
description: 'Capture accessibility snapshot of the current page, this is better than screenshot',
|
|
26
|
-
inputSchema: z.object({
|
|
26
|
+
inputSchema: z.object({
|
|
27
|
+
offset: z.number().int().optional().describe('Used for pagination. Starts reading the snapshot from this line offset. Use the offset provided in the truncation message.'),
|
|
28
|
+
}),
|
|
27
29
|
type: 'readOnly',
|
|
28
30
|
},
|
|
29
31
|
handle: async (context, params, response) => {
|
|
30
32
|
await context.ensureTab();
|
|
31
|
-
response.setIncludeSnapshot();
|
|
33
|
+
response.setIncludeSnapshot(params.offset);
|
|
32
34
|
},
|
|
33
35
|
});
|
|
34
36
|
export const elementSchema = z.object({
|