Skip to content

Commit c188402

Browse files
dprevoznikclaude
andcommitted
Cap execute_playwright_code output and fix snapshot tip
The tool returned executed-code output verbatim and unbounded, so a single whole-page read (innerText/ariaSnapshot on body) could dump tens to hundreds of KB into the model context. The code param also recommended page._snapshotForAI(), which is a large full-page dump and is not reliably available in the execution runtime. - Cap each returned field at 25k chars with a truncation marker that nudges toward targeted selectors. Small structured results keep their shape. - Replace the _snapshotForAI() tip with guidance to scope reads to a selector or region. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ed1f7e7 commit c188402

2 files changed

Lines changed: 18 additions & 6 deletions

File tree

‎src/lib/mcp/tools/playwright.ts‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22
import { z } from "zod";
33
import { createKernelClient } from "@/lib/mcp/kernel-client";
44

5+
// Cap per-field output so a single call can't flood the model's context. Whole-page
6+
// reads (innerText/ariaSnapshot on body) routinely run tens to hundreds of KB.
7+
const MAX_FIELD_CHARS = 25_000;
8+
9+
function cap(value: unknown): unknown {
10+
if (value === undefined || value === null) return value;
11+
const text = typeof value === "string" ? value : JSON.stringify(value);
12+
if (text.length <= MAX_FIELD_CHARS) return value;
13+
const dropped = text.length - MAX_FIELD_CHARS;
14+
return `${text.slice(0, MAX_FIELD_CHARS)}\n\n[output truncated: showing ${MAX_FIELD_CHARS} of ${text.length} chars, ${dropped} dropped. Return a targeted selector instead of a whole-page read.]`;
15+
}
16+
517
export function registerPlaywrightTool(server: McpServer) {
618
// execute_playwright_code -- Run Playwright/TypeScript code against a browser
719
server.tool(
@@ -11,7 +23,7 @@ export function registerPlaywrightTool(server: McpServer) {
1123
code: z
1224
.string()
1325
.describe(
14-
'Playwright/TypeScript code with a `page` object in scope. Example: "await page.goto(\\"https://example.com\\"); return await page.title();" Tip: Use `await page._snapshotForAI()` for a comprehensive page state snapshot.',
26+
'Playwright/TypeScript code with a `page` object in scope. Example: "await page.goto(\\"https://example.com\\"); return await page.title();" Return only what you need: prefer a targeted selector (e.g. `await page.locator(SELECTOR).innerText()`) over reading a whole page. Whole-page dumps like `innerText()`/`ariaSnapshot()` on `body` return large output that is truncated. To understand an unfamiliar page, scope the snapshot to a region (e.g. `await page.locator("main").ariaSnapshot()`).',
1527
),
1628
session_id: z
1729
.string()
@@ -44,10 +56,10 @@ export function registerPlaywrightTool(server: McpServer) {
4456
text: JSON.stringify(
4557
{
4658
success: response.success,
47-
result: response.result,
48-
error: response.error,
49-
stdout: response.stdout,
50-
stderr: response.stderr,
59+
result: cap(response.result),
60+
error: cap(response.error),
61+
stdout: cap(response.stdout),
62+
stderr: cap(response.stderr),
5163
},
5264
null,
5365
2,

‎tsconfig.tsbuildinfo‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)