diff --git a/package.json b/package.json index 3df77c1..e79ebe9 100644 --- a/package.json +++ b/package.json @@ -46,12 +46,11 @@ }, "dependencies": { "@browserbasehq/sdk": "^2.6.0", - "@browserbasehq/stagehand": "^3.0.3", + "@browserbasehq/stagehand": "^3.0.8", "@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 942eeb1..efad090 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.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) + specifier: ^3.0.8 + version: 3.0.8(@opentelemetry/api@1.9.0)(deepmerge@4.3.1)(dotenv@16.6.1)(zod@3.25.76) "@mcp-ui/server": specifier: ^5.10.0 version: 5.10.0 @@ -25,9 +25,6 @@ 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 @@ -100,6 +97,15 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + "@ai-sdk/anthropic@2.0.57": + resolution: + { + integrity: sha512-DREpYqW2pylgaj69gZ+K8u92bo9DaMgFdictYnY+IwYeY3bawQ4zI7l/o1VkDsBDljAx8iYz5lPURwVZNu+Xpg==, + } + engines: { node: ">=18" } + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + "@ai-sdk/azure@2.0.60": resolution: { @@ -136,6 +142,15 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + "@ai-sdk/google-vertex@3.0.97": + resolution: + { + integrity: sha512-s4tI7Z15i6FlbtCvS4SBRal8wRfkOXJzKxlS6cU4mJW/QfUfoVy4b22836NVNJwDvkG/HkDSfzwm/X8mn46MhA==, + } + engines: { node: ">=18" } + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + "@ai-sdk/google@2.0.26": resolution: { @@ -145,6 +160,15 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + "@ai-sdk/google@2.0.52": + resolution: + { + integrity: sha512-2XUnGi3f7TV4ujoAhA+Fg3idUoG/+Y2xjCRg70a1/m0DH1KSQqYaCboJ1C19y6ZHGdf5KNT20eJdswP6TvrY2g==, + } + engines: { node: ">=18" } + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + "@ai-sdk/groq@2.0.27": resolution: { @@ -217,6 +241,15 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + "@ai-sdk/provider-utils@3.0.20": + resolution: + { + integrity: sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ==, + } + engines: { node: ">=18" } + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + "@ai-sdk/provider@1.1.3": resolution: { @@ -231,6 +264,13 @@ packages: } engines: { node: ">=18" } + "@ai-sdk/provider@2.0.1": + resolution: + { + integrity: sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==, + } + engines: { node: ">=18" } + "@ai-sdk/react@1.2.12": resolution: { @@ -296,15 +336,15 @@ packages: integrity: sha512-83iXP5D7xMm8Wyn66TUaUrgoByCmAJuoMoZQI3sGg3JAiMlTfnCIMqyVBoNSaItaPIkaCnrsj6LiusmXV2X9YA==, } - "@browserbasehq/stagehand@3.0.3": + "@browserbasehq/stagehand@3.0.8": resolution: { - integrity: sha512-O/9VgmOmIX4ZYuu2hgQ+7BmK8wkSgPX/kLzGQ/SJLCNYRW9yuU6/b4NRdFU5uJ7OlCKdEOcV1u4Cc4PhY67S0w==, + integrity: sha512-ppI4PmqjRnFEpTtaQyRzKZgL4uVzscOQsDjBpQlvZNhhEp3da1wBaP1ml/hMfsuAmY9wOUwdN4V0uyyRbxWAdA==, } peerDependencies: deepmerge: ^4.3.1 dotenv: ^16.4.5 - zod: 3.25.67 + zod: ^3.25.76 || ^4.2.0 "@cfworker/json-schema@4.1.1": resolution: @@ -429,12 +469,6 @@ 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: { @@ -781,168 +815,6 @@ 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: { @@ -955,6 +827,13 @@ packages: "@types/node": optional: true + "@isaacs/cliui@8.0.2": + resolution: + { + integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, + } + engines: { node: ">=12" } + "@langchain/core@0.3.79": resolution: { @@ -1154,6 +1033,13 @@ packages: } engines: { node: ">=8.0.0" } + "@pkgjs/parseargs@0.11.0": + resolution: + { + integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, + } + engines: { node: ">=14" } + "@puppeteer/browsers@2.3.0": resolution: { @@ -1891,19 +1777,6 @@ 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: { @@ -1991,6 +1864,13 @@ packages: } engines: { node: ">= 8" } + data-uri-to-buffer@4.0.1: + resolution: + { + integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==, + } + engines: { node: ">= 12" } + data-uri-to-buffer@6.0.2: resolution: { @@ -2112,13 +1992,6 @@ packages: } engines: { node: ">=8" } - detect-libc@2.1.2: - resolution: - { - integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, - } - engines: { node: ">=8" } - devtools-protocol@0.0.1312386: resolution: { @@ -2165,6 +2038,12 @@ packages: } engines: { node: ">= 0.4" } + eastasianwidth@0.2.0: + resolution: + { + integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, + } + ecdsa-sig-formatter@1.0.11: resolution: { @@ -2189,6 +2068,12 @@ packages: integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, } + emoji-regex@9.2.2: + resolution: + { + integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, + } + encodeurl@2.0.0: resolution: { @@ -2566,6 +2451,13 @@ packages: integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==, } + fetch-blob@3.2.0: + resolution: + { + integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==, + } + engines: { node: ^12.20 || >= 14.13 } + fetch-cookie@3.1.0: resolution: { @@ -2634,6 +2526,13 @@ packages: } engines: { node: ">= 0.4" } + foreground-child@3.3.1: + resolution: + { + integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, + } + engines: { node: ">=14" } + form-data-encoder@1.7.2: resolution: { @@ -2654,6 +2553,13 @@ packages: } engines: { node: ">= 12.20" } + formdata-polyfill@4.0.10: + resolution: + { + integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==, + } + engines: { node: ">=12.20.0" } + forwarded@0.2.0: resolution: { @@ -2730,6 +2636,13 @@ packages: } engines: { node: ">=14" } + gaxios@7.1.3: + resolution: + { + integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==, + } + engines: { node: ">=18" } + gcp-metadata@6.1.1: resolution: { @@ -2737,6 +2650,13 @@ packages: } engines: { node: ">=14" } + gcp-metadata@8.1.2: + resolution: + { + integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==, + } + engines: { node: ">=18" } + get-caller-file@2.0.5: resolution: { @@ -2813,6 +2733,13 @@ packages: } engines: { node: ">=10.13.0" } + glob@10.5.0: + resolution: + { + integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==, + } + hasBin: true + glob@7.2.3: resolution: { @@ -2848,6 +2775,13 @@ packages: } engines: { node: ">=10" } + google-auth-library@10.5.0: + resolution: + { + integrity: sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==, + } + engines: { node: ">=18" } + google-auth-library@9.15.1: resolution: { @@ -2862,6 +2796,13 @@ packages: } engines: { node: ">=14" } + google-logging-utils@1.1.3: + resolution: + { + integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==, + } + engines: { node: ">=14" } + gopd@1.2.0: resolution: { @@ -2888,6 +2829,13 @@ packages: } engines: { node: ">=14.0.0" } + gtoken@8.0.0: + resolution: + { + integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==, + } + engines: { node: ">=18" } + has-bigints@1.1.0: resolution: { @@ -3103,12 +3051,6 @@ packages: } engines: { node: ">= 0.4" } - is-arrayish@0.3.4: - resolution: - { - integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==, - } - is-async-function@2.1.1: resolution: { @@ -3401,6 +3343,12 @@ packages: } engines: { node: ">= 0.4" } + jackspeak@3.4.3: + resolution: + { + integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==, + } + joycon@3.1.1: resolution: { @@ -3618,6 +3566,12 @@ packages: } hasBin: true + lru-cache@10.4.3: + resolution: + { + integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, + } + lru-cache@7.18.3: resolution: { @@ -3747,6 +3701,13 @@ packages: integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, } + minipass@7.1.2: + resolution: + { + integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==, + } + engines: { node: ">=16 || 14 >=14.17" } + mitt@3.0.1: resolution: { @@ -3833,6 +3794,13 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: + { + integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + node-gyp-build@4.8.4: resolution: { @@ -4099,6 +4067,12 @@ packages: } engines: { node: ">= 14" } + package-json-from-dist@1.0.1: + resolution: + { + integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, + } + package-manager-detector@0.2.11: resolution: { @@ -4161,6 +4135,13 @@ packages: integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, } + path-scurry@1.11.1: + resolution: + { + integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==, + } + engines: { node: ">=16 || 14 >=14.18" } + path-to-regexp@8.2.0: resolution: { @@ -4517,6 +4498,13 @@ packages: integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==, } + rimraf@5.0.10: + resolution: + { + integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==, + } + hasBin: true + router@2.2.0: resolution: { @@ -4651,13 +4639,6 @@ 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: { @@ -4729,12 +4710,6 @@ packages: } engines: { node: ">=14" } - simple-swizzle@0.2.4: - resolution: - { - integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==, - } - simple-wcswidth@1.1.2: resolution: { @@ -4863,6 +4838,13 @@ packages: } engines: { node: ">=8" } + string-width@5.1.2: + resolution: + { + integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, + } + engines: { node: ">=12" } + string-width@7.2.0: resolution: { @@ -5254,6 +5236,13 @@ packages: integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==, } + web-streams-polyfill@3.3.3: + resolution: + { + integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==, + } + engines: { node: ">= 8" } + web-streams-polyfill@4.0.0-beta.3: resolution: { @@ -5330,6 +5319,13 @@ packages: } engines: { node: ">=10" } + wrap-ansi@8.1.0: + resolution: + { + integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, + } + engines: { node: ">=12" } + wrap-ansi@9.0.0: resolution: { @@ -5408,6 +5404,14 @@ packages: peerDependencies: zod: ^3.24.1 + zod-to-json-schema@3.25.1: + resolution: + { + integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==, + } + peerDependencies: + zod: ^3.25 || ^4 + zod@3.23.8: resolution: { @@ -5434,6 +5438,13 @@ snapshots: zod: 3.25.76 optional: true + "@ai-sdk/anthropic@2.0.57(zod@3.25.76)": + dependencies: + "@ai-sdk/provider": 2.0.1 + "@ai-sdk/provider-utils": 3.0.20(zod@3.25.76) + zod: 3.25.76 + optional: true + "@ai-sdk/azure@2.0.60(zod@3.25.76)": dependencies: "@ai-sdk/openai": 2.0.59(zod@3.25.76) @@ -5465,6 +5476,18 @@ snapshots: "@vercel/oidc": 3.0.3 zod: 3.25.76 + "@ai-sdk/google-vertex@3.0.97(zod@3.25.76)": + dependencies: + "@ai-sdk/anthropic": 2.0.57(zod@3.25.76) + "@ai-sdk/google": 2.0.52(zod@3.25.76) + "@ai-sdk/provider": 2.0.1 + "@ai-sdk/provider-utils": 3.0.20(zod@3.25.76) + google-auth-library: 10.5.0 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + optional: true + "@ai-sdk/google@2.0.26(zod@3.25.76)": dependencies: "@ai-sdk/provider": 2.0.0 @@ -5472,6 +5495,13 @@ snapshots: zod: 3.25.76 optional: true + "@ai-sdk/google@2.0.52(zod@3.25.76)": + dependencies: + "@ai-sdk/provider": 2.0.1 + "@ai-sdk/provider-utils": 3.0.20(zod@3.25.76) + zod: 3.25.76 + optional: true + "@ai-sdk/groq@2.0.27(zod@3.25.76)": dependencies: "@ai-sdk/provider": 2.0.0 @@ -5527,6 +5557,14 @@ snapshots: eventsource-parser: 3.0.6 zod: 3.25.76 + "@ai-sdk/provider-utils@3.0.20(zod@3.25.76)": + dependencies: + "@ai-sdk/provider": 2.0.1 + "@standard-schema/spec": 1.0.0 + eventsource-parser: 3.0.6 + zod: 3.25.76 + optional: true + "@ai-sdk/provider@1.1.3": dependencies: json-schema: 0.4.0 @@ -5535,6 +5573,11 @@ snapshots: dependencies: json-schema: 0.4.0 + "@ai-sdk/provider@2.0.1": + dependencies: + json-schema: 0.4.0 + optional: true + "@ai-sdk/react@1.2.12(react@19.1.0)(zod@3.25.76)": dependencies: "@ai-sdk/provider-utils": 2.2.8(zod@3.25.76) @@ -5606,7 +5649,7 @@ snapshots: transitivePeerDependencies: - encoding - "@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)": + "@browserbasehq/stagehand@3.0.8(@opentelemetry/api@1.9.0)(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 @@ -5622,16 +5665,17 @@ snapshots: openai: 4.104.0(ws@8.18.3(bufferutil@4.0.9))(zod@3.25.76) pino: 9.7.0 pino-pretty: 13.0.0 - playwright: 1.54.1 + uuid: 11.1.0 ws: 8.18.3(bufferutil@4.0.9) zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + zod-to-json-schema: 3.25.1(zod@3.25.76) optionalDependencies: "@ai-sdk/anthropic": 2.0.40(zod@3.25.76) "@ai-sdk/azure": 2.0.60(zod@3.25.76) "@ai-sdk/cerebras": 1.0.28(zod@3.25.76) "@ai-sdk/deepseek": 1.0.26(zod@3.25.76) "@ai-sdk/google": 2.0.26(zod@3.25.76) + "@ai-sdk/google-vertex": 3.0.97(zod@3.25.76) "@ai-sdk/groq": 2.0.27(zod@3.25.76) "@ai-sdk/mistral": 2.0.22(zod@3.25.76) "@ai-sdk/openai": 2.0.59(zod@3.25.76) @@ -5639,9 +5683,11 @@ snapshots: "@ai-sdk/togetherai": 1.0.26(zod@3.25.76) "@ai-sdk/xai": 2.0.30(zod@3.25.76) "@langchain/core": 0.3.79(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.18.3(bufferutil@4.0.9))(zod@3.25.76)) + bufferutil: 4.0.9 chrome-launcher: 1.2.1 ollama-ai-provider-v2: 1.5.2(zod@3.25.76) patchright-core: 1.56.1 + playwright: 1.54.1 playwright-core: 1.54.1 puppeteer-core: 22.15.0(bufferutil@4.0.9) transitivePeerDependencies: @@ -5650,7 +5696,6 @@ snapshots: - "@opentelemetry/sdk-trace-base" - bare-abort-controller - bare-buffer - - bufferutil - encoding - react-native-b4a - supports-color @@ -5806,11 +5851,6 @@ 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 @@ -5958,81 +5998,6 @@ 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 @@ -6040,6 +6005,16 @@ snapshots: optionalDependencies: "@types/node": 24.10.1 + "@isaacs/cliui@8.0.2": + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + optional: true + "@langchain/core@0.3.79(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.18.3(bufferutil@4.0.9))(zod@3.25.76))": dependencies: "@cfworker/json-schema": 4.1.1 @@ -6053,7 +6028,7 @@ snapshots: p-retry: 4.6.2 uuid: 10.0.0 zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - "@opentelemetry/api" - "@opentelemetry/exporter-trace-otlp-proto" @@ -6066,7 +6041,7 @@ snapshots: js-tiktoken: 1.0.21 openai: 4.104.0(ws@8.18.3(bufferutil@4.0.9))(zod@3.25.76) zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - encoding - ws @@ -6196,6 +6171,9 @@ snapshots: "@opentelemetry/api@1.9.0": {} + "@pkgjs/parseargs@0.11.0": + optional: true + "@puppeteer/browsers@2.3.0": dependencies: debug: 4.4.1 @@ -6733,16 +6711,6 @@ 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: @@ -6786,6 +6754,9 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + data-uri-to-buffer@4.0.1: + optional: true + data-uri-to-buffer@6.0.2: optional: true @@ -6850,8 +6821,6 @@ snapshots: detect-indent@6.1.0: {} - detect-libc@2.1.2: {} - devtools-protocol@0.0.1312386: optional: true @@ -6875,6 +6844,9 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + eastasianwidth@0.2.0: + optional: true + ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 @@ -6885,6 +6857,9 @@ snapshots: emoji-regex@8.0.0: {} + emoji-regex@9.2.2: + optional: true + encodeurl@2.0.0: {} end-of-stream@1.4.5: @@ -7158,7 +7133,7 @@ snapshots: eventsource@3.0.7: dependencies: - eventsource-parser: 3.0.3 + eventsource-parser: 3.0.6 execa@8.0.1: dependencies: @@ -7261,6 +7236,12 @@ snapshots: pend: 1.2.0 optional: true + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + optional: true + fetch-cookie@3.1.0: dependencies: set-cookie-parser: 2.7.1 @@ -7310,6 +7291,12 @@ snapshots: dependencies: is-callable: 1.2.7 + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + optional: true + form-data-encoder@1.7.2: {} form-data@4.0.3: @@ -7325,6 +7312,11 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 4.0.0-beta.3 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + optional: true + forwarded@0.2.0: {} fresh@2.0.0: {} @@ -7373,6 +7365,16 @@ snapshots: - encoding - supports-color + gaxios@7.1.3: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + rimraf: 5.0.10 + transitivePeerDependencies: + - supports-color + optional: true + gcp-metadata@6.1.1: dependencies: gaxios: 6.7.1 @@ -7382,6 +7384,15 @@ snapshots: - encoding - supports-color + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.1.3 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + optional: true + get-caller-file@2.0.5: optional: true @@ -7439,6 +7450,16 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + optional: true + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -7466,6 +7487,19 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + google-auth-library@10.5.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.3 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + gtoken: 8.0.0 + jws: 4.0.0 + transitivePeerDependencies: + - supports-color + optional: true + google-auth-library@9.15.1: dependencies: base64-js: 1.5.1 @@ -7480,6 +7514,9 @@ snapshots: google-logging-utils@0.0.2: {} + google-logging-utils@1.1.3: + optional: true + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -7494,6 +7531,14 @@ snapshots: - encoding - supports-color + gtoken@8.0.0: + dependencies: + gaxios: 7.1.3 + jws: 4.0.0 + transitivePeerDependencies: + - supports-color + optional: true + has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -7625,8 +7670,6 @@ 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 @@ -7779,6 +7822,13 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 + jackspeak@3.4.3: + dependencies: + "@isaacs/cliui": 8.0.2 + optionalDependencies: + "@pkgjs/parseargs": 0.11.0 + optional: true + joycon@3.1.1: {} js-tiktoken@1.0.21: @@ -7928,6 +7978,9 @@ snapshots: dependencies: js-tokens: 4.0.0 + lru-cache@10.4.3: + optional: true + lru-cache@7.18.3: optional: true @@ -7992,6 +8045,9 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.2: + optional: true + mitt@3.0.1: optional: true @@ -8020,6 +8076,13 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + optional: true + node-gyp-build@4.8.4: optional: true @@ -8212,6 +8275,9 @@ snapshots: netmask: 2.0.2 optional: true + package-json-from-dist@1.0.1: + optional: true + package-manager-detector@0.2.11: dependencies: quansync: 0.2.11 @@ -8235,6 +8301,12 @@ snapshots: path-parse@1.0.7: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + optional: true + path-to-regexp@8.2.0: {} path-type@4.0.0: {} @@ -8288,13 +8360,15 @@ snapshots: pkce-challenge@5.0.0: {} - playwright-core@1.54.1: {} + playwright-core@1.54.1: + optional: true playwright@1.54.1: dependencies: playwright-core: 1.54.1 optionalDependencies: fsevents: 2.3.2 + optional: true possible-typed-array-names@1.1.0: {} @@ -8459,6 +8533,11 @@ snapshots: rfdc@1.4.1: {} + rimraf@5.0.10: + dependencies: + glob: 10.5.0 + optional: true + router@2.2.0: dependencies: debug: 4.4.1 @@ -8561,32 +8640,6 @@ 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 @@ -8636,10 +8689,6 @@ 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: {} @@ -8717,6 +8766,13 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + optional: true + string-width@7.2.0: dependencies: emoji-regex: 10.4.0 @@ -8978,6 +9034,9 @@ snapshots: dependencies: defaults: 1.0.4 + web-streams-polyfill@3.3.3: + optional: true + web-streams-polyfill@4.0.0-beta.3: {} webidl-conversions@3.0.1: {} @@ -9047,6 +9106,13 @@ snapshots: strip-ansi: 6.0.1 optional: true + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + optional: true + wrap-ansi@9.0.0: dependencies: ansi-styles: 6.2.1 @@ -9090,6 +9156,10 @@ snapshots: dependencies: zod: 3.25.76 + zod-to-json-schema@3.25.1(zod@3.25.76): + dependencies: + zod: 3.25.76 + zod@3.23.8: optional: true diff --git a/src/context.ts b/src/context.ts index 00a27e5..b23762d 100644 --- a/src/context.ts +++ b/src/context.ts @@ -2,7 +2,6 @@ import type { Stagehand } from "@browserbasehq/stagehand"; import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import type { Config } from "../config.d.ts"; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; -import { listResources, readResource } from "./mcp/resources.js"; import { SessionManager } from "./sessionManager.js"; import type { MCPTool } from "./types/types.js"; @@ -17,6 +16,7 @@ export class Context { public readonly config: Config; private server: Server; private sessionManager: SessionManager; + private screenshots: Map = new Map(); // currentSessionId is a getter that delegates to SessionManager to ensure synchronization // This prevents desync between Context and SessionManager session tracking @@ -104,12 +104,34 @@ export class Context { } } + /** + * Register a screenshot in this context's storage + */ + registerScreenshot(name: string, data: string): void { + this.screenshots.set(name, data); + } + + /** + * Clear all screenshots in this context + */ + clearScreenshots(): void { + this.screenshots.clear(); + } + /** * List resources * Documentation: https://modelcontextprotocol.io/docs/concepts/resources */ listResources() { - return listResources(); + return { + resources: [ + ...Array.from(this.screenshots.keys()).map((name) => ({ + uri: `screenshot://${name}`, + mimeType: "image/png", + name: `Screenshot: ${name}`, + })), + ], + }; } /** @@ -117,6 +139,22 @@ export class Context { * Documentation: https://modelcontextprotocol.io/docs/concepts/resources */ readResource(uri: string) { - return readResource(uri); + if (uri.startsWith("screenshot://")) { + const name = uri.split("://")[1]; + const screenshot = this.screenshots.get(name); + if (screenshot) { + return { + contents: [ + { + uri, + mimeType: "image/png", + blob: screenshot, + }, + ], + }; + } + } + + throw new Error(`Resource not found: ${uri}`); } } diff --git a/src/index.ts b/src/index.ts index f77c6a4..21b7502 100644 --- a/src/index.ts +++ b/src/index.ts @@ -139,6 +139,17 @@ export default function ({ config }: { config: z.infer }) { const contextId = randomUUID(); const context = new Context(server.server, internalConfig, contextId); + // Cleanup handler for when the MCP connection closes (SHTTP/Smithery) + server.server.onclose = async () => { + try { + await context.getSessionManager().closeAllSessions(); + } catch (err) { + process.stderr.write( + `[Cleanup] Error during session cleanup: ${err instanceof Error ? err.message : String(err)}\n`, + ); + } + }; + server.server.registerCapabilities({ resources: { subscribe: true, diff --git a/src/mcp/resources.ts b/src/mcp/resources.ts index 5b9a327..ce9a64a 100644 --- a/src/mcp/resources.ts +++ b/src/mcp/resources.ts @@ -2,6 +2,9 @@ * Resources module for the Browserbase MCP server * Contains resources definitions and handlers for resource-related requests * Docs: https://modelcontextprotocol.io/docs/concepts/resources + * + * Note: Screenshot storage has been moved to Context class for per-session isolation. + * Each MCP session has its own Context instance with isolated screenshot storage. */ // Define the resources @@ -9,88 +12,3 @@ export const RESOURCES = []; // Define the resource templates export const RESOURCE_TEMPLATES = []; - -// Store screenshots in a map -export const screenshots = new Map(); - -// Track screenshots by session so we can purge them on session end -// key: sessionId (internal/current session id), value: set of screenshot names -const sessionIdToScreenshotNames = new Map>(); - -export function registerScreenshot( - sessionId: string, - name: string, - base64: string, -) { - screenshots.set(name, base64); - let set = sessionIdToScreenshotNames.get(sessionId); - if (!set) { - set = new Set(); - sessionIdToScreenshotNames.set(sessionId, set); - } - set.add(name); -} - -export function clearScreenshotsForSession(sessionId: string) { - const set = sessionIdToScreenshotNames.get(sessionId); - if (set) { - for (const name of set) { - screenshots.delete(name); - } - sessionIdToScreenshotNames.delete(sessionId); - } -} - -export function clearAllScreenshots() { - screenshots.clear(); - sessionIdToScreenshotNames.clear(); -} - -/** - * Handle listing resources request - * @returns A list of available resources including screenshots - */ -export function listResources() { - return { - resources: [ - ...Array.from(screenshots.keys()).map((name) => ({ - uri: `screenshot://${name}`, - mimeType: "image/png", - name: `Screenshot: ${name}`, - })), - ], - }; -} - -/** - * Handle listing resource templates request - * @returns An empty resource templates list response - */ -export function listResourceTemplates() { - return { resourceTemplates: [] }; -} - -/** - * Read a resource by its URI - * @param uri The URI of the resource to read - * @returns The resource content or throws if not found - */ -export function readResource(uri: string) { - if (uri.startsWith("screenshot://")) { - const name = uri.split("://")[1]; - const screenshot = screenshots.get(name); - if (screenshot) { - return { - contents: [ - { - uri, - mimeType: "image/png", - blob: screenshot, - }, - ], - }; - } - } - - throw new Error(`Resource not found: ${uri}`); -} diff --git a/src/sessionManager.ts b/src/sessionManager.ts index 602f869..6eb4ad5 100644 --- a/src/sessionManager.ts +++ b/src/sessionManager.ts @@ -1,6 +1,5 @@ import { Stagehand } from "@browserbasehq/stagehand"; import type { Config } from "../config.d.ts"; -import { clearScreenshotsForSession } from "./mcp/resources.js"; import type { BrowserSession, CreateSessionParams } from "./types/types.js"; import { randomUUID } from "crypto"; @@ -243,16 +242,6 @@ export class SessionManager { process.stderr.write( `[SessionManager] Successfully closed Stagehand and browser for session: ${sessionIdToLog}\n`, ); - // After close, purge any screenshots associated with this session - try { - clearScreenshotsForSession(sessionIdToLog); - } catch (err) { - process.stderr.write( - `[SessionManager] WARN - Failed to clear screenshots after close for ${sessionIdToLog}: ${ - err instanceof Error ? err.message : String(err) - }\n`, - ); - } } catch (closeError) { process.stderr.write( `[SessionManager] WARN - Error closing Stagehand for session ${sessionIdToLog}: ${ diff --git a/src/tools/screenshot.ts b/src/tools/screenshot.ts index facc895..4a30b8b 100644 --- a/src/tools/screenshot.ts +++ b/src/tools/screenshot.ts @@ -1,9 +1,7 @@ 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"; -import { registerScreenshot } from "../mcp/resources.js"; /** * Screenshot @@ -37,57 +35,12 @@ async function handleScreenshot( } // We're taking a full page screenshot to give context of the entire page, similar to a snapshot - // Enable Page domain if needed - await page.sendCDP("Page.enable"); + const screenshotBuffer = await page.screenshot({ + fullPage: true, + }); - // 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"); - } - } + // Convert buffer to base64 string and store in memory + const screenshotBase64 = screenshotBuffer.toString("base64"); const name = params.name ? `screenshot-${params.name}-${new Date() .toISOString() @@ -95,9 +48,8 @@ async function handleScreenshot( : `screenshot-${new Date().toISOString().replace(/:/g, "-")}` + context.config.browserbaseProjectId; - // Associate with current mcp session id and store in memory /src/mcp/resources.ts - const sessionId = context.currentSessionId; - registerScreenshot(sessionId, name, screenshotBase64); + // Store screenshot in this context (scoped to this MCP session) + context.registerScreenshot(name, screenshotBase64); // Notify the client that the resources changed const serverInstance = context.getServer(); diff --git a/src/transport.ts b/src/transport.ts index 4885bf9..fa886dc 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -53,10 +53,11 @@ async function handleStreamable( sessionIdGenerator: () => sessionId, }); sessions.set(sessionId, transport); + const server = await serverList.create(); transport.onclose = () => { if (transport.sessionId) sessions.delete(transport.sessionId); + serverList.close(server); }; - const server = await serverList.create(); await server.connect(transport); return await transport.handleRequest(req, res); }