Skip to main content
Glama

Playwright Browserbase MCP Server

by ampcome-mcps
session.ts8.97 kB
import { z } from "zod"; import type { Tool, ToolSchema, ToolResult } from "./tool.js"; import type { Context } from "../context.js"; import type { ToolActionResult } from "../context.js"; // Import SessionManager functions import { createNewBrowserSession, defaultSessionId, ensureDefaultSessionInternal, cleanupSession, type BrowserSession, } from "../sessionManager.js"; // --- Tool: Create Session --- const CreateSessionInputSchema = z.object({ // Keep sessionId optional, but clarify its role sessionId: z .string() .optional() .describe( "Optional session ID to use/reuse. If not provided or invalid, a new session is created." ), }); type CreateSessionInput = z.infer<typeof CreateSessionInputSchema>; const createSessionSchema: ToolSchema<typeof CreateSessionInputSchema> = { name: "browserbase_session_create", description: "Create or reuse a cloud browser session using Browserbase. Updates the active session.", inputSchema: CreateSessionInputSchema, }; // Handle function for CreateSession using SessionManager async function handleCreateSession( context: Context, params: CreateSessionInput ): Promise<ToolResult> { const action = async (): Promise<ToolActionResult> => { try { const config = context.config; // Get config from context let targetSessionId: string; if (params.sessionId) { const projectId = config.browserbaseProjectId || ''; targetSessionId = `${params.sessionId}_${projectId}`; process.stderr.write( `[tool.createSession] Attempting to create/assign session with specified ID: ${targetSessionId}` ); } else { targetSessionId = defaultSessionId; } let session: BrowserSession; if (targetSessionId === defaultSessionId) { session = await ensureDefaultSessionInternal(config); } else { session = await createNewBrowserSession(targetSessionId, config); } if (!session || !session.browser || !session.page || !session.sessionId) { throw new Error( `SessionManager failed to return a valid session object with actualSessionId for ID: ${targetSessionId}` ); } context.currentSessionId = targetSessionId; process.stderr.write( `[tool.connected] Successfully connected to Browserbase session. Internal ID: ${targetSessionId}, Actual ID: ${session.sessionId}` ); process.stderr.write(`[SessionManager] Browserbase Live Debugger URL: https://www.browserbase.com/sessions/${session.sessionId}`); return { content: [ { type: "text", text: `https://www.browserbase.com/sessions/${session.sessionId}`, }, ], }; } catch (error: any) { process.stderr.write( `[tool.createSession] Action failed: ${ error.message || String(error) }` ); // Re-throw to be caught by Context.run's error handling for actions throw new Error( `Failed to create Browserbase session: ${ error.message || String(error) }` ); } }; // Return the ToolResult structure expected by Context.run return { action: action, captureSnapshot: false, code: [], waitForNetwork: false, }; } // Define tool using handle const createSessionTool: Tool<typeof CreateSessionInputSchema> = { capability: "core", // Add capability schema: createSessionSchema, handle: handleCreateSession, }; // --- Tool: Close Session --- const CloseSessionInputSchema = z.object({ random_string: z .string() .optional() .describe("Dummy parameter to ensure consistent tool call format."), }); type CloseSessionInput = z.infer<typeof CloseSessionInputSchema>; const closeSessionSchema: ToolSchema<typeof CloseSessionInputSchema> = { name: "browserbase_session_close", description: "Closes the current Browserbase session by disconnecting the Playwright browser. This will terminate the recording for the session.", inputSchema: CloseSessionInputSchema, }; async function handleCloseSession( context: Context, _params: CloseSessionInput ): Promise<ToolResult> { const code = [`// Attempting to close the current Browserbase session.`]; const action = async (): Promise<ToolActionResult> => { // Store the current session ID before it's potentially changed. // This allows us to reference the original session ID later if needed. const previousSessionId = context.currentSessionId; // Capture the ID before any changes let browser: BrowserSession["browser"] | null = null; let browserClosedSuccessfully = false; let browserCloseErrorMessage = ""; // Step 1: Attempt to get the active browser instance WITHOUT creating a new one try { // Use read-only version to avoid creating new sessions browser = context.getActiveBrowserReadOnly(); } catch (error: any) { process.stderr.write( `[tool.closeSession] Error retrieving active browser (session ID was ${previousSessionId || 'default/unknown'}): ${error.message || String(error)}` ); // If we can't even get the browser, we can't close it. // We will still proceed to reset context. } // Step 2: If a browser instance was retrieved, attempt to close it if (browser) { try { process.stderr.write( `[tool.closeSession] Attempting to close browser for session: ${previousSessionId || 'default (actual might differ)'}` ); await browser.close(); browserClosedSuccessfully = true; process.stderr.write( `[tool.closeSession] Browser connection for session (was ${previousSessionId}) closed.` ); // Clean up the session from tracking cleanupSession(previousSessionId); process.stderr.write( `[tool.closeSession] View session replay at https://www.browserbase.com/sessions/${previousSessionId}` ); } catch (error: any) { browserCloseErrorMessage = error.message || String(error); process.stderr.write( `[tool.closeSession] Error during browser.close() for session (was ${previousSessionId}): ${browserCloseErrorMessage}` ); } } else { process.stderr.write( `[tool.closeSession] No active browser instance found to close. (Session ID in context was: ${previousSessionId || 'default/unknown'}).` ); } // Step 3: Always reset the context's current session ID to default // and clear snapshot if the previous session was a specific one. const oldContextSessionId = context.currentSessionId; // This should effectively be 'previousSessionId' context.currentSessionId = defaultSessionId; if (oldContextSessionId && oldContextSessionId !== defaultSessionId) { context.clearLatestSnapshot(); process.stderr.write( `[tool.closeSession] Snapshot cleared for previous session: ${oldContextSessionId}.` ); } process.stderr.write( `[tool.closeSession] Session context reset to default. Previous context session ID was ${oldContextSessionId || 'default/unknown'}.` ); // Step 4: Determine the result message if (browser && !browserClosedSuccessfully) { // An attempt was made to close, but it failed throw new Error( `Failed to close the Browserbase browser (session ID in context was ${previousSessionId || 'default/unknown'}). Error: ${browserCloseErrorMessage}. Session context has been reset to default.` ); } if (browserClosedSuccessfully) { // Browser was present and closed let successMessage = `Browserbase session (associated with context ID ${previousSessionId || 'default'}) closed successfully. Context reset to default.`; if (previousSessionId && previousSessionId !== defaultSessionId) { successMessage += ` If this was a uniquely named session (${previousSessionId}), view replay (if available) at https://browserbase.com/sessions`; } return { content: [{ type: "text", text: successMessage }] }; } // No browser was found, or browser was null initially. let infoMessage = "No active browser instance was found to close. Session context has been reset to default."; if (previousSessionId && previousSessionId !== defaultSessionId) { // This means a specific session was in context, but no browser for it. infoMessage = `No active browser found for session ID '${previousSessionId}' in context. The context has been reset to default.`; } return { content: [{ type: "text", text: infoMessage }] }; }; return { action: action, code: code, captureSnapshot: false, waitForNetwork: false, }; } const closeSessionTool: Tool<typeof CloseSessionInputSchema> = { capability: "core", schema: closeSessionSchema, handle: handleCloseSession, }; export default [createSessionTool, closeSessionTool];

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ampcome-mcps/browserbase-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server