Skip to content

Commit 980e3c9

Browse files
cookie management
1 parent dd35634 commit 980e3c9

File tree

4 files changed

+344
-0
lines changed

4 files changed

+344
-0
lines changed

browserbase/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,31 @@ Contexts make it much easier to:
6767
- Reduce page load times by preserving cache
6868
- Avoid CAPTCHAs and detection by reusing browser fingerprints
6969
70+
## Cookie Management
71+
72+
This server also provides direct cookie management capabilities:
73+
74+
1. **Adding Cookies**:
75+
```
76+
browserbase_add_cookies: Add cookies to the current browser session with full control over properties
77+
```
78+
79+
2. **Getting Cookies**:
80+
```
81+
browserbase_get_cookies: View all cookies in the current session (optionally filtered by URLs)
82+
```
83+
84+
3. **Deleting Cookies**:
85+
```
86+
browserbase_delete_cookies: Delete specific cookies or clear all cookies from the session
87+
```
88+
89+
These tools are useful for:
90+
- Setting authentication cookies without navigating to login pages
91+
- Backing up and restoring cookie state
92+
- Debugging cookie-related issues
93+
- Manipulating cookie attributes (expiration, security flags, etc.)
94+
7095
## TODO
7196
7297
* Implement true `ref`-based interaction logic for click, type, drag, hover, select_option.

browserbase/src/tools/cookies.ts

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import { Page } from "playwright-core";
2+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3+
4+
/**
5+
* Handle adding cookies to the browser session
6+
*/
7+
export async function handleAddCookies(page: Page, args: any, targetSessionId: string): Promise<CallToolResult> {
8+
try {
9+
if (!args.cookies || !Array.isArray(args.cookies) || args.cookies.length === 0) {
10+
return {
11+
content: [{ type: "text", text: "Missing or invalid required argument: cookies (must be a non-empty array)" }],
12+
isError: true,
13+
};
14+
}
15+
16+
// Get the browser context for this page
17+
const context = page.context();
18+
19+
// Add each cookie to the context
20+
await context.addCookies(args.cookies);
21+
22+
console.error(`Added ${args.cookies.length} cookies to session ${targetSessionId}`);
23+
24+
return {
25+
content: [
26+
{
27+
type: "text",
28+
text: `Successfully added ${args.cookies.length} cookies to session ${targetSessionId}`,
29+
},
30+
],
31+
isError: false,
32+
};
33+
} catch (error) {
34+
console.error(
35+
`Failed to add cookies to session ${targetSessionId}: ${(error as Error).message}`
36+
);
37+
return {
38+
content: [
39+
{
40+
type: "text",
41+
text: `Failed to add cookies: ${(error as Error).message}`,
42+
},
43+
],
44+
isError: true,
45+
};
46+
}
47+
}
48+
49+
/**
50+
* Handle deleting cookies from the browser session
51+
*/
52+
export async function handleDeleteCookies(page: Page, args: any, targetSessionId: string): Promise<CallToolResult> {
53+
try {
54+
// Get the browser context for this page
55+
const context = page.context();
56+
57+
// If 'all' flag is true, clear all cookies
58+
if (args.all === true) {
59+
await context.clearCookies();
60+
console.error(`Cleared all cookies from session ${targetSessionId}`);
61+
return {
62+
content: [
63+
{
64+
type: "text",
65+
text: `Successfully cleared all cookies from session ${targetSessionId}`,
66+
},
67+
],
68+
isError: false,
69+
};
70+
}
71+
72+
// Otherwise, expect an array of cookies to delete
73+
if (!args.cookies || !Array.isArray(args.cookies) || args.cookies.length === 0) {
74+
return {
75+
content: [
76+
{
77+
type: "text",
78+
text: "Missing required arguments: either 'all: true' or 'cookies' array must be provided"
79+
}
80+
],
81+
isError: true,
82+
};
83+
}
84+
85+
// Get current cookies
86+
const currentCookies = await context.cookies();
87+
const initialCount = currentCookies.length;
88+
89+
// For each cookie in the list, delete it (one by one)
90+
for (const cookieToDelete of args.cookies) {
91+
// Playwright doesn't have a direct "delete specific cookie" method
92+
// So we need to get all cookies, filter out the one we want to delete, and set the rest
93+
94+
// Filter the cookies to exclude the one to delete
95+
const remainingCookies = currentCookies.filter(cookie =>
96+
!(cookie.name === cookieToDelete.name &&
97+
cookie.domain === cookieToDelete.domain &&
98+
(cookieToDelete.path ? cookie.path === cookieToDelete.path : true))
99+
);
100+
101+
// If we found cookies to delete
102+
if (remainingCookies.length < currentCookies.length) {
103+
// Clear all cookies and re-add the remaining ones
104+
await context.clearCookies();
105+
106+
// Re-add the remaining cookies
107+
if (remainingCookies.length > 0) {
108+
await context.addCookies(remainingCookies);
109+
}
110+
111+
// Update our tracking array for subsequent operations
112+
currentCookies.length = 0;
113+
currentCookies.push(...remainingCookies);
114+
}
115+
}
116+
117+
// Get the new count
118+
const finalCookies = await context.cookies();
119+
const deletedCount = initialCount - finalCookies.length;
120+
121+
console.error(`Deleted ${deletedCount} cookies from session ${targetSessionId}`);
122+
123+
return {
124+
content: [
125+
{
126+
type: "text",
127+
text: `Successfully deleted ${deletedCount} out of ${args.cookies.length} specified cookies from session ${targetSessionId}`,
128+
},
129+
],
130+
isError: false,
131+
};
132+
} catch (error) {
133+
console.error(
134+
`Failed to delete cookies from session ${targetSessionId}: ${(error as Error).message}`
135+
);
136+
return {
137+
content: [
138+
{
139+
type: "text",
140+
text: `Failed to delete cookies: ${(error as Error).message}`,
141+
},
142+
],
143+
isError: true,
144+
};
145+
}
146+
}
147+
148+
/**
149+
* Gets all cookies from the browser session and returns them
150+
*/
151+
export async function handleGetCookies(page: Page, args: any, targetSessionId: string): Promise<CallToolResult> {
152+
try {
153+
// Get the browser context for this page
154+
const context = page.context();
155+
156+
// Get all cookies (optionally filtered by URLs)
157+
const urls = args.urls || [];
158+
const cookies = await context.cookies(urls);
159+
160+
console.error(`Retrieved ${cookies.length} cookies from session ${targetSessionId}`);
161+
162+
return {
163+
content: [
164+
{
165+
type: "text",
166+
text: JSON.stringify(cookies, null, 2),
167+
},
168+
],
169+
isError: false,
170+
};
171+
} catch (error) {
172+
console.error(
173+
`Failed to get cookies from session ${targetSessionId}: ${(error as Error).message}`
174+
);
175+
return {
176+
content: [
177+
{
178+
type: "text",
179+
text: `Failed to get cookies: ${(error as Error).message}`,
180+
},
181+
],
182+
isError: true,
183+
};
184+
}
185+
}

browserbase/src/tools/definitions.ts

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,127 @@ export const TOOLS: Tool[] = [
334334
required: [], // selector is optional
335335
},
336336
},
337+
{
338+
name: "browserbase_add_cookies",
339+
description: "Add cookies to the current browser session",
340+
inputSchema: {
341+
type: "object",
342+
properties: {
343+
cookies: {
344+
type: "array",
345+
items: {
346+
type: "object",
347+
properties: {
348+
name: {
349+
type: "string",
350+
description: "Cookie name"
351+
},
352+
value: {
353+
type: "string",
354+
description: "Cookie value"
355+
},
356+
domain: {
357+
type: "string",
358+
description: "Cookie domain (required)"
359+
},
360+
path: {
361+
type: "string",
362+
description: "Cookie path",
363+
default: "/"
364+
},
365+
expires: {
366+
type: "number",
367+
description: "Cookie expiration time in seconds since epoch, or -1 for session cookies"
368+
},
369+
httpOnly: {
370+
type: "boolean",
371+
description: "Whether the cookie is HTTP-only"
372+
},
373+
secure: {
374+
type: "boolean",
375+
description: "Whether the cookie is secure"
376+
},
377+
sameSite: {
378+
type: "string",
379+
description: "Cookie same-site policy: 'Strict', 'Lax', or 'None'",
380+
enum: ["Strict", "Lax", "None"]
381+
}
382+
},
383+
required: ["name", "value", "domain"]
384+
},
385+
description: "Array of cookie objects to add to the browser"
386+
},
387+
sessionId: {
388+
type: "string",
389+
description: "Target session ID (optional, defaults to 'default')"
390+
}
391+
},
392+
required: ["cookies"]
393+
}
394+
},
395+
{
396+
name: "browserbase_delete_cookies",
397+
description: "Delete specific cookies from the current browser session",
398+
inputSchema: {
399+
type: "object",
400+
properties: {
401+
cookies: {
402+
type: "array",
403+
items: {
404+
type: "object",
405+
properties: {
406+
name: {
407+
type: "string",
408+
description: "Cookie name to delete"
409+
},
410+
domain: {
411+
type: "string",
412+
description: "Cookie domain (required for proper matching)"
413+
},
414+
path: {
415+
type: "string",
416+
description: "Cookie path",
417+
default: "/"
418+
}
419+
},
420+
required: ["name", "domain"]
421+
},
422+
description: "Array of cookie identifiers to delete"
423+
},
424+
all: {
425+
type: "boolean",
426+
description: "If true, delete all cookies (ignores the cookies array)",
427+
default: false
428+
},
429+
sessionId: {
430+
type: "string",
431+
description: "Target session ID (optional, defaults to 'default')"
432+
}
433+
},
434+
required: [] // Either cookies or all should be provided
435+
}
436+
},
437+
{
438+
name: "browserbase_get_cookies",
439+
description: "Get all cookies from the current browser session",
440+
inputSchema: {
441+
type: "object",
442+
properties: {
443+
urls: {
444+
type: "array",
445+
items: {
446+
type: "string"
447+
},
448+
description: "Optional list of URLs to get cookies for (if empty, gets all cookies)"
449+
},
450+
sessionId: {
451+
type: "string",
452+
description: "Target session ID (optional, defaults to 'default')"
453+
}
454+
},
455+
required: []
456+
}
457+
},
337458
// Other standard tools like browser_tab_*, browser_navigate_back/forward etc.
338459
// could be added here if needed, potentially wrapping existing Playwright functions.
339460
];

browserbase/src/tools/handlers.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; // Needed fo
1919
// Import specific tool handlers
2020
import { handleNavigate } from "./navigate.js";
2121
import { handleCreateContext, handleDeleteContext, getContextId } from "./context.js";
22+
import { handleAddCookies, handleDeleteCookies, handleGetCookies } from "./cookies.js";
2223
import {
2324
handleSnapshot,
2425
handleTakeScreenshot,
@@ -231,6 +232,18 @@ export async function handleToolCall(
231232
return handleGetText(page, args, targetSessionId);
232233
}
233234

235+
case "browserbase_add_cookies": {
236+
return handleAddCookies(page, args, targetSessionId);
237+
}
238+
239+
case "browserbase_delete_cookies": {
240+
return handleDeleteCookies(page, args, targetSessionId);
241+
}
242+
243+
case "browserbase_get_cookies": {
244+
return handleGetCookies(page, args, targetSessionId);
245+
}
246+
234247
// Add cases for other potential tools, delegating to handleNotImplemented for now
235248
case "browserbase_navigate_back":
236249
case "browserbase_navigate_forward":

0 commit comments

Comments
 (0)