From 114ab1c18ccee9de5a3d511a27c5209844727293 Mon Sep 17 00:00:00 2001 From: Kylejeong2 Date: Mon, 17 Nov 2025 14:55:29 -0800 Subject: [PATCH 1/2] fix: change screenshot tool to use CDP screenshot --- package.json | 3 +- pnpm-lock.yaml | 344 +++++++++++++++++++++++++++++++++++++++- src/tools/screenshot.ts | 56 ++++++- 3 files changed, 392 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 6f6479a..7010e60 100644 --- a/package.json +++ b/package.json @@ -46,11 +46,12 @@ }, "dependencies": { "@browserbasehq/sdk": "^2.6.0", - "@browserbasehq/stagehand": "^3.0.2", + "@browserbasehq/stagehand": "^3.0.3", "@mcp-ui/server": "^5.10.0", "@modelcontextprotocol/sdk": "^1.13.1", "commander": "^14.0.0", "dotenv": "^16.4.6", + "sharp": "^0.33.0", "zod": "^3.25.67" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0655c51..942eeb1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,8 +11,8 @@ importers: specifier: ^2.6.0 version: 2.6.0 "@browserbasehq/stagehand": - specifier: ^3.0.2 - version: 3.0.2(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@16.6.1)(zod@3.25.76) + specifier: ^3.0.3 + version: 3.0.3(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@16.6.1)(zod@3.25.76) "@mcp-ui/server": specifier: ^5.10.0 version: 5.10.0 @@ -25,6 +25,9 @@ importers: dotenv: specifier: ^16.4.6 version: 16.6.1 + sharp: + specifier: ^0.33.0 + version: 0.33.5 zod: specifier: ^3.25.67 version: 3.25.76 @@ -293,10 +296,10 @@ packages: integrity: sha512-83iXP5D7xMm8Wyn66TUaUrgoByCmAJuoMoZQI3sGg3JAiMlTfnCIMqyVBoNSaItaPIkaCnrsj6LiusmXV2X9YA==, } - "@browserbasehq/stagehand@3.0.2": + "@browserbasehq/stagehand@3.0.3": resolution: { - integrity: sha512-m5GSOgHtRlC8wj4cdfJzB6sY6oQsTznmR2fjao0QRbtQd71Eh2dCYzmN/jZtc0K60Ga9ARMVTrix4iSaKaY2eQ==, + integrity: sha512-O/9VgmOmIX4ZYuu2hgQ+7BmK8wkSgPX/kLzGQ/SJLCNYRW9yuU6/b4NRdFU5uJ7OlCKdEOcV1u4Cc4PhY67S0w==, } peerDependencies: deepmerge: ^4.3.1 @@ -426,6 +429,12 @@ packages: peerDependencies: zod: ">=3.25.76 <4 || >=4.1 <5" + "@emnapi/runtime@1.7.1": + resolution: + { + integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==, + } + "@esbuild/aix-ppc64@0.25.6": resolution: { @@ -772,6 +781,168 @@ packages: } engines: { node: ">=18.18" } + "@img/sharp-darwin-arm64@0.33.5": + resolution: + { + integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [darwin] + + "@img/sharp-darwin-x64@0.33.5": + resolution: + { + integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [darwin] + + "@img/sharp-libvips-darwin-arm64@1.0.4": + resolution: + { + integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==, + } + cpu: [arm64] + os: [darwin] + + "@img/sharp-libvips-darwin-x64@1.0.4": + resolution: + { + integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==, + } + cpu: [x64] + os: [darwin] + + "@img/sharp-libvips-linux-arm64@1.0.4": + resolution: + { + integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==, + } + cpu: [arm64] + os: [linux] + + "@img/sharp-libvips-linux-arm@1.0.5": + resolution: + { + integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==, + } + cpu: [arm] + os: [linux] + + "@img/sharp-libvips-linux-s390x@1.0.4": + resolution: + { + integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==, + } + cpu: [s390x] + os: [linux] + + "@img/sharp-libvips-linux-x64@1.0.4": + resolution: + { + integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==, + } + cpu: [x64] + os: [linux] + + "@img/sharp-libvips-linuxmusl-arm64@1.0.4": + resolution: + { + integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==, + } + cpu: [arm64] + os: [linux] + + "@img/sharp-libvips-linuxmusl-x64@1.0.4": + resolution: + { + integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==, + } + cpu: [x64] + os: [linux] + + "@img/sharp-linux-arm64@0.33.5": + resolution: + { + integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + + "@img/sharp-linux-arm@0.33.5": + resolution: + { + integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm] + os: [linux] + + "@img/sharp-linux-s390x@0.33.5": + resolution: + { + integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [s390x] + os: [linux] + + "@img/sharp-linux-x64@0.33.5": + resolution: + { + integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + + "@img/sharp-linuxmusl-arm64@0.33.5": + resolution: + { + integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + + "@img/sharp-linuxmusl-x64@0.33.5": + resolution: + { + integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + + "@img/sharp-wasm32@0.33.5": + resolution: + { + integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [wasm32] + + "@img/sharp-win32-ia32@0.33.5": + resolution: + { + integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [ia32] + os: [win32] + + "@img/sharp-win32-x64@0.33.5": + resolution: + { + integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [win32] + "@inquirer/external-editor@1.0.1": resolution: { @@ -1720,6 +1891,19 @@ packages: integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, } + color-string@1.9.1: + resolution: + { + integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, + } + + color@4.2.3: + resolution: + { + integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, + } + engines: { node: ">=12.5.0" } + colorette@2.0.20: resolution: { @@ -1928,6 +2112,13 @@ packages: } engines: { node: ">=8" } + detect-libc@2.1.2: + resolution: + { + integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, + } + engines: { node: ">=8" } + devtools-protocol@0.0.1312386: resolution: { @@ -2912,6 +3103,12 @@ packages: } engines: { node: ">= 0.4" } + is-arrayish@0.3.4: + resolution: + { + integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==, + } + is-async-function@2.1.1: resolution: { @@ -4454,6 +4651,13 @@ packages: integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==, } + sharp@0.33.5: + resolution: + { + integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + shebang-command@2.0.0: resolution: { @@ -4525,6 +4729,12 @@ packages: } engines: { node: ">=14" } + simple-swizzle@0.2.4: + resolution: + { + integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==, + } + simple-wcswidth@1.1.2: resolution: { @@ -5396,7 +5606,7 @@ snapshots: transitivePeerDependencies: - encoding - "@browserbasehq/stagehand@3.0.2(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@16.6.1)(zod@3.25.76)": + "@browserbasehq/stagehand@3.0.3(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@16.6.1)(zod@3.25.76)": dependencies: "@ai-sdk/provider": 2.0.0 "@anthropic-ai/sdk": 0.39.0 @@ -5596,6 +5806,11 @@ snapshots: dependencies: zod: 3.25.76 + "@emnapi/runtime@1.7.1": + dependencies: + tslib: 2.8.1 + optional: true + "@esbuild/aix-ppc64@0.25.6": optional: true @@ -5743,6 +5958,81 @@ snapshots: "@humanwhocodes/retry@0.4.3": {} + "@img/sharp-darwin-arm64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-darwin-arm64": 1.0.4 + optional: true + + "@img/sharp-darwin-x64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-darwin-x64": 1.0.4 + optional: true + + "@img/sharp-libvips-darwin-arm64@1.0.4": + optional: true + + "@img/sharp-libvips-darwin-x64@1.0.4": + optional: true + + "@img/sharp-libvips-linux-arm64@1.0.4": + optional: true + + "@img/sharp-libvips-linux-arm@1.0.5": + optional: true + + "@img/sharp-libvips-linux-s390x@1.0.4": + optional: true + + "@img/sharp-libvips-linux-x64@1.0.4": + optional: true + + "@img/sharp-libvips-linuxmusl-arm64@1.0.4": + optional: true + + "@img/sharp-libvips-linuxmusl-x64@1.0.4": + optional: true + + "@img/sharp-linux-arm64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linux-arm64": 1.0.4 + optional: true + + "@img/sharp-linux-arm@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linux-arm": 1.0.5 + optional: true + + "@img/sharp-linux-s390x@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linux-s390x": 1.0.4 + optional: true + + "@img/sharp-linux-x64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linux-x64": 1.0.4 + optional: true + + "@img/sharp-linuxmusl-arm64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 + optional: true + + "@img/sharp-linuxmusl-x64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64": 1.0.4 + optional: true + + "@img/sharp-wasm32@0.33.5": + dependencies: + "@emnapi/runtime": 1.7.1 + optional: true + + "@img/sharp-win32-ia32@0.33.5": + optional: true + + "@img/sharp-win32-x64@0.33.5": + optional: true + "@inquirer/external-editor@1.0.1(@types/node@24.10.1)": dependencies: chardet: 2.1.0 @@ -6443,6 +6733,16 @@ snapshots: color-name@1.1.4: {} + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + colorette@2.0.20: {} combined-stream@1.0.8: @@ -6550,6 +6850,8 @@ snapshots: detect-indent@6.1.0: {} + detect-libc@2.1.2: {} + devtools-protocol@0.0.1312386: optional: true @@ -7323,6 +7625,8 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-arrayish@0.3.4: {} + is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -8257,6 +8561,32 @@ snapshots: setprototypeof@1.2.0: {} + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.1.2 + semver: 7.7.2 + optionalDependencies: + "@img/sharp-darwin-arm64": 0.33.5 + "@img/sharp-darwin-x64": 0.33.5 + "@img/sharp-libvips-darwin-arm64": 1.0.4 + "@img/sharp-libvips-darwin-x64": 1.0.4 + "@img/sharp-libvips-linux-arm": 1.0.5 + "@img/sharp-libvips-linux-arm64": 1.0.4 + "@img/sharp-libvips-linux-s390x": 1.0.4 + "@img/sharp-libvips-linux-x64": 1.0.4 + "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 + "@img/sharp-libvips-linuxmusl-x64": 1.0.4 + "@img/sharp-linux-arm": 0.33.5 + "@img/sharp-linux-arm64": 0.33.5 + "@img/sharp-linux-s390x": 0.33.5 + "@img/sharp-linux-x64": 0.33.5 + "@img/sharp-linuxmusl-arm64": 0.33.5 + "@img/sharp-linuxmusl-x64": 0.33.5 + "@img/sharp-wasm32": 0.33.5 + "@img/sharp-win32-ia32": 0.33.5 + "@img/sharp-win32-x64": 0.33.5 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -8306,6 +8636,10 @@ snapshots: signal-exit@4.1.0: {} + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + simple-wcswidth@1.1.2: {} slash@3.0.0: {} diff --git a/src/tools/screenshot.ts b/src/tools/screenshot.ts index 5a96bf9..e0a9a55 100644 --- a/src/tools/screenshot.ts +++ b/src/tools/screenshot.ts @@ -1,4 +1,5 @@ import { z } from "zod"; +import sharp from "sharp"; import type { Tool, ToolSchema, ToolResult } from "./tool.js"; import type { Context } from "../context.js"; import type { ToolActionResult } from "../types/types.js"; @@ -36,12 +37,57 @@ async function handleScreenshot( } // We're taking a full page screenshot to give context of the entire page, similar to a snapshot - const screenshotBuffer = await page.screenshot({ - fullPage: true, - }); + // Enable Page domain if needed + await page.sendCDP("Page.enable"); - // Convert buffer to base64 string and store in memory - const screenshotBase64 = screenshotBuffer.toString("base64"); + // Use CDP to capture screenshot + const { data } = await page.sendCDP<{ data: string }>( + "Page.captureScreenshot", + { + format: "png", + fromSurface: true, + }, + ); + + // data is already base64 string from CDP + let screenshotBase64 = data; + + // Scale down image if needed for Claude's vision API + // Claude constraints: max 1568px on any edge AND max 1.15 megapixels + // Reference: https://docs.anthropic.com/en/docs/build-with-claude/vision#evaluate-image-size + const imageBuffer = Buffer.from(data, "base64"); + const metadata = await sharp(imageBuffer).metadata(); + + if (metadata.width && metadata.height) { + const pixels = metadata.width * metadata.height; + + // Min of: width constraint, height constraint, and megapixel constraint + const shrink = Math.min( + 1568 / metadata.width, + 1568 / metadata.height, + Math.sqrt((1.15 * 1024 * 1024) / pixels), + ); + + // Only resize if we need to shrink (shrink < 1) + if (shrink < 1) { + const newWidth = Math.floor(metadata.width * shrink); + const newHeight = Math.floor(metadata.height * shrink); + + process.stderr.write( + `[Screenshot] Scaling image from ${metadata.width}x${metadata.height} (${(pixels / (1024 * 1024)).toFixed(2)}MP) to ${newWidth}x${newHeight} (${((newWidth * newHeight) / (1024 * 1024)).toFixed(2)}MP) for Claude vision API\n`, + ); + + const resizedBuffer = await sharp(imageBuffer) + .resize(newWidth, newHeight, { + fit: "inside", + withoutEnlargement: true, + }) + .png() + .toBuffer(); + + screenshotBase64 = resizedBuffer.toString("base64"); + } + } const name = params.name ? `screenshot-${params.name}-${new Date() .toISOString() From 5e8d7f3dc350929e841c0495f5cf3f4d8d948f2c Mon Sep 17 00:00:00 2001 From: Kylejeong2 Date: Mon, 17 Nov 2025 14:58:51 -0800 Subject: [PATCH 2/2] changesets --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c958af..853e93a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # @browserbasehq/mcp-server-browserbase +## 2.4.1 + +### Patch Changes + +- update stagehand version to 3.0.3, change screenshot tool to use CDP and scaling image to work with claude code + ## 2.4.0 ### Minor Changes diff --git a/package.json b/package.json index 7010e60..3df77c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@browserbasehq/mcp-server-browserbase", - "version": "2.4.0", + "version": "2.4.1", "description": "MCP server for AI web browser automation using Browserbase and Stagehand", "mcpName": "io.github.browserbase/mcp-server-browserbase", "license": "Apache-2.0",