Skip to content

Commit 82854ed

Browse files
committed
hotfix for screenshots
1 parent 2a02524 commit 82854ed

File tree

4 files changed

+46
-103
lines changed

4 files changed

+46
-103
lines changed

src/context.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { Stagehand } from "@browserbasehq/stagehand";
22
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
33
import type { Config } from "../config.d.ts";
44
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
5-
import { listResources, readResource } from "./mcp/resources.js";
65
import { SessionManager } from "./sessionManager.js";
76
import type { MCPTool } from "./types/types.js";
87

@@ -17,6 +16,7 @@ export class Context {
1716
public readonly config: Config;
1817
private server: Server;
1918
private sessionManager: SessionManager;
19+
private screenshots: Map<string, string> = new Map();
2020

2121
// currentSessionId is a getter that delegates to SessionManager to ensure synchronization
2222
// This prevents desync between Context and SessionManager session tracking
@@ -104,19 +104,57 @@ export class Context {
104104
}
105105
}
106106

107+
/**
108+
* Register a screenshot in this context's storage
109+
*/
110+
registerScreenshot(name: string, data: string): void {
111+
this.screenshots.set(name, data);
112+
}
113+
114+
/**
115+
* Clear all screenshots in this context
116+
*/
117+
clearScreenshots(): void {
118+
this.screenshots.clear();
119+
}
120+
107121
/**
108122
* List resources
109123
* Documentation: https://modelcontextprotocol.io/docs/concepts/resources
110124
*/
111125
listResources() {
112-
return listResources();
126+
return {
127+
resources: [
128+
...Array.from(this.screenshots.keys()).map((name) => ({
129+
uri: `screenshot://${name}`,
130+
mimeType: "image/png",
131+
name: `Screenshot: ${name}`,
132+
})),
133+
],
134+
};
113135
}
114136

115137
/**
116138
* Read a resource by URI
117139
* Documentation: https://modelcontextprotocol.io/docs/concepts/resources
118140
*/
119141
readResource(uri: string) {
120-
return readResource(uri);
142+
if (uri.startsWith("screenshot://")) {
143+
const name = uri.split("://")[1];
144+
const screenshot = this.screenshots.get(name);
145+
if (screenshot) {
146+
return {
147+
contents: [
148+
{
149+
uri,
150+
mimeType: "image/png",
151+
blob: screenshot,
152+
},
153+
],
154+
};
155+
}
156+
}
157+
158+
throw new Error(`Resource not found: ${uri}`);
121159
}
122160
}

src/mcp/resources.ts

Lines changed: 3 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,95 +2,13 @@
22
* Resources module for the Browserbase MCP server
33
* Contains resources definitions and handlers for resource-related requests
44
* Docs: https://modelcontextprotocol.io/docs/concepts/resources
5+
*
6+
* Note: Screenshot storage has been moved to Context class for per-session isolation.
7+
* Each MCP session has its own Context instance with isolated screenshot storage.
58
*/
69

710
// Define the resources
811
export const RESOURCES = [];
912

1013
// Define the resource templates
1114
export const RESOURCE_TEMPLATES = [];
12-
13-
// Store screenshots in a map
14-
export const screenshots = new Map<string, string>();
15-
16-
// Track screenshots by session so we can purge them on session end
17-
// key: sessionId (internal/current session id), value: set of screenshot names
18-
const sessionIdToScreenshotNames = new Map<string, Set<string>>();
19-
20-
export function registerScreenshot(
21-
sessionId: string,
22-
name: string,
23-
base64: string,
24-
) {
25-
screenshots.set(name, base64);
26-
let set = sessionIdToScreenshotNames.get(sessionId);
27-
if (!set) {
28-
set = new Set();
29-
sessionIdToScreenshotNames.set(sessionId, set);
30-
}
31-
set.add(name);
32-
}
33-
34-
export function clearScreenshotsForSession(sessionId: string) {
35-
const set = sessionIdToScreenshotNames.get(sessionId);
36-
if (set) {
37-
for (const name of set) {
38-
screenshots.delete(name);
39-
}
40-
sessionIdToScreenshotNames.delete(sessionId);
41-
}
42-
}
43-
44-
export function clearAllScreenshots() {
45-
screenshots.clear();
46-
sessionIdToScreenshotNames.clear();
47-
}
48-
49-
/**
50-
* Handle listing resources request
51-
* @returns A list of available resources including screenshots
52-
*/
53-
export function listResources() {
54-
return {
55-
resources: [
56-
...Array.from(screenshots.keys()).map((name) => ({
57-
uri: `screenshot://${name}`,
58-
mimeType: "image/png",
59-
name: `Screenshot: ${name}`,
60-
})),
61-
],
62-
};
63-
}
64-
65-
/**
66-
* Handle listing resource templates request
67-
* @returns An empty resource templates list response
68-
*/
69-
export function listResourceTemplates() {
70-
return { resourceTemplates: [] };
71-
}
72-
73-
/**
74-
* Read a resource by its URI
75-
* @param uri The URI of the resource to read
76-
* @returns The resource content or throws if not found
77-
*/
78-
export function readResource(uri: string) {
79-
if (uri.startsWith("screenshot://")) {
80-
const name = uri.split("://")[1];
81-
const screenshot = screenshots.get(name);
82-
if (screenshot) {
83-
return {
84-
contents: [
85-
{
86-
uri,
87-
mimeType: "image/png",
88-
blob: screenshot,
89-
},
90-
],
91-
};
92-
}
93-
}
94-
95-
throw new Error(`Resource not found: ${uri}`);
96-
}

src/sessionManager.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Stagehand } from "@browserbasehq/stagehand";
22
import type { Config } from "../config.d.ts";
3-
import { clearScreenshotsForSession } from "./mcp/resources.js";
43
import type { BrowserSession, CreateSessionParams } from "./types/types.js";
54
import { randomUUID } from "crypto";
65

@@ -243,16 +242,6 @@ export class SessionManager {
243242
process.stderr.write(
244243
`[SessionManager] Successfully closed Stagehand and browser for session: ${sessionIdToLog}\n`,
245244
);
246-
// After close, purge any screenshots associated with this session
247-
try {
248-
clearScreenshotsForSession(sessionIdToLog);
249-
} catch (err) {
250-
process.stderr.write(
251-
`[SessionManager] WARN - Failed to clear screenshots after close for ${sessionIdToLog}: ${
252-
err instanceof Error ? err.message : String(err)
253-
}\n`,
254-
);
255-
}
256245
} catch (closeError) {
257246
process.stderr.write(
258247
`[SessionManager] WARN - Error closing Stagehand for session ${sessionIdToLog}: ${

src/tools/screenshot.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { z } from "zod";
22
import type { Tool, ToolSchema, ToolResult } from "./tool.js";
33
import type { Context } from "../context.js";
44
import type { ToolActionResult } from "../types/types.js";
5-
import { registerScreenshot } from "../mcp/resources.js";
65

76
/**
87
* Screenshot
@@ -49,9 +48,8 @@ async function handleScreenshot(
4948
: `screenshot-${new Date().toISOString().replace(/:/g, "-")}` +
5049
context.config.browserbaseProjectId;
5150

52-
// Associate with current mcp session id and store in memory /src/mcp/resources.ts
53-
const sessionId = context.currentSessionId;
54-
registerScreenshot(sessionId, name, screenshotBase64);
51+
// Store screenshot in this context (scoped to this MCP session)
52+
context.registerScreenshot(name, screenshotBase64);
5553

5654
// Notify the client that the resources changed
5755
const serverInstance = context.getServer();

0 commit comments

Comments
 (0)