Skip to content

Commit f495f47

Browse files
authored
Merge pull request #69 from browserbase/kj/cleanup
General clean up
2 parents 50a44cc + 40d4e6f commit f495f47

16 files changed

+48
-322
lines changed

browserbase/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
{
22
"name": "@browserbasehq/mcp",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"description": "MCP server for browser automation using browserbase",
5-
"license": "MIT",
65
"author": "Browserbase, Inc. (https://browserbase.com)",
76
"homepage": "https://browserbase.com",
87
"type": "module",
@@ -11,6 +10,7 @@
1110
"node": ">=18"
1211
},
1312
"files": [
13+
"../assets/browserbase-mcp.png",
1414
"dist",
1515
"cli.js",
1616
"index.d.ts",

browserbase/src/config.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import path from 'path';
44
import { sanitizeForFilePath } from './tools/utils.js';
55
import type { Cookie } from "playwright-core";
66

7-
export type ToolCapability = 'core' | string; // Example capabilities
7+
export type ToolCapability = 'core' | string;
88

99
export interface Config {
10-
browserbaseApiKey?: string; // Make optional for easier merging
11-
browserbaseProjectId?: string; // Make optional for easier merging
10+
browserbaseApiKey?: string;
11+
browserbaseProjectId?: string;
1212
server?: {
1313
port?: number;
1414
host?: string;

browserbase/src/context.ts

+3-24
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,28 @@ import type { BrowserSession } from "./sessionManager.js";
33
import {
44
getSession,
55
defaultSessionId,
6-
closeAllSessions,
76
} from "./sessionManager.js";
8-
import type { Tool, ToolContext, ToolResult } from "./tools/tool.js";
7+
import type { Tool, ToolResult } from "./tools/tool.js";
98
import type { Config } from "../config.js";
109
import {
1110
Resource,
1211
CallToolResult,
1312
TextContent,
1413
ImageContent,
15-
ResourceListChangedNotificationSchema,
1614
} from "@modelcontextprotocol/sdk/types.js";
1715
import { z } from "zod";
1816
import { PageSnapshot } from "./pageSnapshot.js";
19-
import { Writable } from "stream"; // Import Writable for process.stderr
20-
import type { Page, Locator } from "playwright"; // Import Page and Locator types
17+
import type { Page, Locator } from "playwright";
2118

22-
// Define ToolActionResult locally if not exported
2319
export type ToolActionResult =
2420
| { content?: (ImageContent | TextContent)[] }
2521
| undefined
2622
| void;
2723

2824
/**
2925
* Manages the context for tool execution within a specific Browserbase session.
30-
*
31-
* Role Analogy:
32-
* This class holds session-specific state (like latest snapshots, resources)
33-
* and provides access to the active page/browser for the current session.
34-
* This is somewhat analogous to the role of the `Tab` class in the Playwright
35-
* MCP example, which encapsulates state for a single page.
36-
*
37-
* Differences from Playwright MCP Context Example:
38-
* - Browser Lifecycle: This Context does NOT manage the browser launch/
39-
* connection lifecycle; that is handled by `sessionManager` (sessionManager.ts) interacting
40-
* with the Browserbase API.
41-
* - Tab Management: This Context focuses on a single active session determined
42-
* by `currentSessionId`, unlike the Playwright example which explicitly
43-
* manages an array of `Tab` objects.
44-
* - Execution Model: This Context uses a `run`/`CallToolResult` pattern. Its `run`
45-
* method calls `tool.run`, which performs the action and returns the final
46-
* result structure. The Playwright example uses a `handle`/`ToolActionResult`
47-
* pattern where the Context interprets the result to perform actions.
4826
*/
27+
4928
export class Context {
5029
private server: Server;
5130
public readonly config: Config;

browserbase/src/index.ts

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
#!/usr/bin/env node
2-
3-
// Load environment variables early
41
import dotenv from "dotenv";
52
dotenv.config();
63

7-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
84
import { Config } from "../config.js";
95
import type { Tool } from "./tools/tool.js";
106

@@ -15,6 +11,7 @@ import getText from "./tools/getText.js";
1511
import session from "./tools/session.js";
1612
import common from "./tools/common.js";
1713
import contextTools from "./tools/context.js";
14+
1815
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
1916
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
2017
import { z } from "zod";
@@ -32,8 +29,6 @@ Object.entries(requiredEnvVars).forEach(([name, value]) => {
3229
if (!value) throw new Error(`${name} environment variable is required`);
3330
});
3431

35-
// const serverVersion = "0.5.1";
36-
3732
export async function createServer(config: Config): Promise<Server> {
3833
// Create the server
3934
const server = new Server(
@@ -139,10 +134,9 @@ export async function createServer(config: Config): Promise<Server> {
139134
// Wrap server close to also close context
140135
const originalClose = server.close.bind(server);
141136
server.close = async () => {
142-
// await context.closeSession();
143137
await originalClose();
144138
};
145139

146-
// Return the configured server instance, DO NOT connect here
140+
// Return the configured server instance
147141
return server;
148142
}

browserbase/src/pageSnapshot.ts

+2-41
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,11 @@
1-
/**
2-
* Copyright (c) Microsoft Corporation.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
16-
17-
// Use types from playwright-core consistent with the project
181
import type { Page, FrameLocator, Locator } from 'playwright-core';
192
import yaml from 'yaml';
20-
// Import specific YAML types, remove Scalar from type-only
21-
// Removed YAML types no longer needed by this version
22-
import { Writable } from 'stream'; // Import Writable for process.stderr - KEEPING this as it might be used elsewhere implicitly, though not directly in this class version
233

244
type PageOrFrameLocator = Page | FrameLocator;
255

266
export class PageSnapshot {
277
private _frameLocators: PageOrFrameLocator[] = [];
288
private _text!: string;
29-
// Removed _snapshotDoc as it's not used in this version
309

3110
constructor() {
3211
}
@@ -42,7 +21,6 @@ export class PageSnapshot {
4221
}
4322

4423
private async _build(page: Page) {
45-
// Removed storing to _snapshotDoc
4624
const yamlDocument = await this._snapshotFrame(page);
4725
this._text = [
4826
`- Page Snapshot`,
@@ -53,15 +31,12 @@ export class PageSnapshot {
5331
].join('\n');
5432
}
5533

56-
// Reverted _snapshotFrame to match the provided example exactly
5734
private async _snapshotFrame(frame: Page | FrameLocator) {
5835
const frameIndex = this._frameLocators.push(frame) - 1;
59-
// Removed logging from this version
6036
let snapshotString = '';
6137
try {
6238
snapshotString = await (frame.locator('body') as any).ariaSnapshot({ ref: true, emitGeneric: true });
6339
} catch (e) {
64-
// Simple error string, removed logging
6540
snapshotString = `error: Could not take snapshot. Error: ${e instanceof Error ? e.message : String(e)}`;
6641
}
6742

@@ -79,21 +54,17 @@ export class PageSnapshot {
7954
} else if (yaml.isScalar(node)) {
8055
if (typeof node.value === 'string') {
8156
const value = node.value;
82-
// Simplified frame prefixing logic from example
8357
if (frameIndex > 0)
8458
node.value = value.replace('[ref=', `[ref=f${frameIndex}`);
8559

8660
if (value.startsWith('iframe ')) {
87-
const ref = value.match(/\[ref=(.*)\]/)?.[1]; // Original regex from example
61+
const ref = value.match(/\[ref=(.*)\]/)?.[1];
8862
if (ref) {
8963
try {
90-
// Original iframe locator strategy from example
9164
const childFrameLocator = frame.frameLocator(`aria-ref=${ref}`);
9265
const childSnapshot = await this._snapshotFrame(childFrameLocator);
93-
// Original createPair structure
9466
return snapshot.createPair(node.value, childSnapshot);
9567
} catch (error) {
96-
// Original error handling
9768
return snapshot.createPair(node.value, '<could not take iframe snapshot>');
9869
}
9970
}
@@ -107,20 +78,12 @@ export class PageSnapshot {
10778
if (snapshot.contents) {
10879
await visit(snapshot.contents);
10980
} else {
110-
// Handle empty snapshot doc contents like original
11181
const emptyMapDoc = yaml.parseDocument('{}');
11282
snapshot.contents = emptyMapDoc.contents;
11383
}
114-
// Removed logging
115-
return snapshot; // Return the processed document
84+
return snapshot;
11685
}
11786

118-
// Removed findNodeByRef helper
119-
120-
// Removed extractRoleAndName helper
121-
122-
123-
// Reverted refLocator to match the provided example exactly
12487
refLocator(ref: string): Locator {
12588
let frameIndex = 0;
12689
let frame: PageOrFrameLocator;
@@ -144,8 +107,6 @@ export class PageSnapshot {
144107
if (!frame)
145108
throw new Error(`Frame (index ${frameIndex}) could not be determined. Provide ref from the most current snapshot.`);
146109

147-
// Removed console warnings and complex strategy
148-
// Use the exact locator strategy from the Playwright MCP example
149110
return frame.locator(`aria-ref=${targetRef}`);
150111
}
151112
}

browserbase/src/sessionManager.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ export type BrowserSession = {
1717

1818
// Global state for managing browser sessions
1919
const browsers = new Map<string, BrowserSession>();
20+
2021
// Keep track of the default session explicitly
2122
let defaultBrowserSession: BrowserSession | null = null;
23+
2224
// Define a specific ID for the default session
2325
export const defaultSessionId = "browserbase_session_main";
2426

@@ -181,9 +183,7 @@ export async function createNewBrowserSession(
181183
? creationError.message
182184
: String(creationError)
183185
}`
184-
); // Keep ERROR comment if useful, but removed from output
185-
// Attempt to clean up partially created resources if possible (e.g., close browser if connection succeeded but context/page failed)
186-
// This part is complex, might need more state tracking. For now, just log and re-throw.
186+
);
187187
throw new Error(
188188
`Failed to create/connect session ${newSessionId}: ${errorMessage}`
189189
);

browserbase/src/tools/common.ts

+4-23
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,9 @@
1-
// import { AccessibilitySnapshot, AccessibilityNode } from "@modelcontextprotocol/sdk/types.js"; // Type might not be exported
2-
3-
// Common state and helpers for tools, moved from handlers.ts
4-
5-
// Store latest snapshot per session - MOVED TO Context
6-
// export const latestSnapshots = new Map<string, any>();
7-
8-
// findNodeByRef helper removed as interaction tools now use aria-ref selector directly.
9-
10-
// No common state remains here for now.
111
export {}; // Ensure file is treated as a module
122

133
import { z } from 'zod';
14-
import type { Tool, ToolSchema, ToolResult } from "./tool.js"; // Assuming ToolContext is needed if handle uses context
15-
import type { Context } from '../context.js'; // Import main Context for handle
16-
import type { ToolActionResult } from '../context.js'; // Import ToolActionResult
17-
18-
// Assuming createSuccessResult/createErrorResult exist in toolUtils.js
19-
// import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
4+
import type { Tool, ToolSchema, ToolResult } from "./tool.js";
5+
import type { Context } from '../context.js';
6+
import type { ToolActionResult } from '../context.js';
207

218
// --- Tool: Wait ---
229
const WaitInputSchema = z.object({
@@ -121,10 +108,4 @@ export default [
121108
waitTool,
122109
closeTool,
123110
resizeTool,
124-
];
125-
126-
// Remove old direct exports
127-
// export const waitTool: Tool<WaitInput> = { ... };
128-
// export const closeTool: Tool<CloseInput> = { ... };
129-
// export const resizeTool: Tool<ResizeInput> = { ... };
130-
// export function common(): Tool[] { ... };
111+
];

browserbase/src/tools/context.ts

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { z } from "zod";
2-
import type { Tool, ToolSchema, ToolContext, ToolResult } from "./tool.js";
3-
// import { createSuccessResult, createErrorResult } from "./toolUtils.js";
2+
import type { Tool, ToolSchema, ToolResult } from "./tool.js";
43
import type { Context } from "../context.js";
54
import type { ToolActionResult } from "../context.js";
65
import { Browserbase } from "@browserbasehq/sdk";
76

87
// Store contexts in memory
9-
// In a production app, these should be persisted to a database
10-
const contexts = new Map<string, string>();
8+
const contexts = new Map<string, string>();
119

1210
// --- Tool: Create Context ---
1311
const CreateContextInputSchema = z.object({
@@ -120,8 +118,7 @@ async function handleDeleteContext(
120118

121119
console.error(`Deleting Browserbase context: ${contextId}`);
122120

123-
// Delete from Browserbase API
124-
// The SDK may not have a delete method directly, so we use the REST API
121+
// Delete using Browserbase API
125122
const response = await fetch(`https://api.browserbase.com/v1/contexts/${contextId}`, {
126123
method: 'DELETE',
127124
headers: {

browserbase/src/tools/getText.ts

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { z } from 'zod';
2-
// Import ToolResult and adjust Tool type usage
3-
import type { Tool, ToolSchema, ToolContext, ToolResult } from "./tool.js";
4-
import { createSuccessResult, createErrorResult } from "./toolUtils.js"; // Assuming these exist
5-
import type { Context } from '../context.js'; // For handle signature
6-
import type { ToolActionResult } from '../context.js'; // For action return type
2+
import type { Tool, ToolSchema, ToolResult } from "./tool.js";
3+
import type { Context } from '../context.js';
4+
import type { ToolActionResult } from '../context.js';
75

86
// --- Tool: Get Text ---
97
const GetTextInputSchema = z.object({
@@ -34,7 +32,6 @@ async function handleGetText(context: Context, params: GetTextInput): Promise<To
3432
}
3533
return { content: [{ type: 'text', text: textContent ?? "" }] };
3634
} catch (error) {
37-
// Log error? Throw? Action results don't easily convey errors back to Context.run
3835
console.error(`GetText action failed: ${error}`);
3936
throw error; // Rethrow to be caught by Context.run's try/catch around handle/action
4037
}
@@ -55,5 +52,4 @@ const getTextTool: Tool<typeof GetTextInputSchema> = {
5552
handle: handleGetText,
5653
};
5754

58-
// Export the single tool object as default
59-
export default [getTextTool]; // Export as an array containing the tool
55+
export default [getTextTool];

0 commit comments

Comments
 (0)