Skip to content

Commit dc89087

Browse files
fixed mcp stagehand
1 parent fd249ac commit dc89087

File tree

1 file changed

+89
-11
lines changed

1 file changed

+89
-11
lines changed

stagehand/src/index.ts

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import {
77
ListToolsRequestSchema,
88
CallToolResult,
99
Tool,
10+
ListResourcesRequestSchema,
11+
ListResourceTemplatesRequestSchema
1012
} from "@modelcontextprotocol/sdk/types.js";
1113

1214
import { Stagehand } from "@browserbasehq/stagehand";
15+
import type { ConstructorParams, LogLine } from "@browserbasehq/stagehand";
1316

1417
import { AnyZodObject } from "zod";
1518
import { jsonSchemaToZod } from "./utils.js";
@@ -29,6 +32,41 @@ if (!fs.existsSync(LOG_DIR)) {
2932
fs.mkdirSync(LOG_DIR, { recursive: true });
3033
}
3134

35+
// Helper function to convert LogLine to string
36+
function logLineToString(logLine: LogLine): string {
37+
const timestamp = logLine.timestamp ? new Date(logLine.timestamp).toISOString() : new Date().toISOString();
38+
const level = logLine.level !== undefined ?
39+
(logLine.level === 0 ? 'DEBUG' :
40+
logLine.level === 1 ? 'INFO' :
41+
logLine.level === 2 ? 'ERROR' : 'UNKNOWN') : 'UNKNOWN';
42+
return `[${timestamp}] [${level}] ${logLine.message || ''}`;
43+
}
44+
45+
// Define Stagehand configuration
46+
const stagehandConfig: ConstructorParams = {
47+
env:
48+
process.env.BROWSERBASE_API_KEY && process.env.BROWSERBASE_PROJECT_ID
49+
? "BROWSERBASE"
50+
: "LOCAL",
51+
apiKey: process.env.BROWSERBASE_API_KEY /* API key for authentication */,
52+
projectId: process.env.BROWSERBASE_PROJECT_ID /* Project identifier */,
53+
debugDom: true /* Enable DOM debugging features */,
54+
headless: false /* Run browser in headless mode */,
55+
logger: (message: LogLine) =>
56+
console.log(logLineToString(message)) /* Custom logging function */,
57+
domSettleTimeoutMs: 30_000 /* Timeout for DOM to settle in milliseconds */,
58+
browserbaseSessionCreateParams: {
59+
projectId: process.env.BROWSERBASE_PROJECT_ID!,
60+
},
61+
enableCaching: true /* Enable caching functionality */,
62+
browserbaseSessionID:
63+
undefined /* Session ID for resuming Browserbase sessions */,
64+
modelName: "gpt-4o" /* Name of the model to use */,
65+
modelClientOptions: {
66+
apiKey: process.env.OPENAI_API_KEY,
67+
} /* Configuration options for the model client */,
68+
};
69+
3270
// Define the Stagehand tools
3371
const TOOLS: Tool[] = [
3472
{
@@ -44,7 +82,7 @@ const TOOLS: Tool[] = [
4482
},
4583
{
4684
name: "stagehand_act",
47-
description: "Performs an action on the web page",
85+
description: "Performs an action on a web page element",
4886
inputSchema: {
4987
type: "object",
5088
properties: {
@@ -58,6 +96,7 @@ const TOOLS: Tool[] = [
5896
required: ["action"],
5997
},
6098
},
99+
/*
61100
{
62101
name: "stagehand_extract",
63102
description: `Extracts structured data from the web page based on an instruction and a JSON schema.`,
@@ -153,6 +192,7 @@ const TOOLS: Tool[] = [
153192
required: ["instruction", "schema"],
154193
},
155194
},
195+
*/
156196
{
157197
name: "stagehand_observe",
158198
description: "Observes actions that can be performed on the web page",
@@ -161,9 +201,10 @@ const TOOLS: Tool[] = [
161201
properties: {
162202
instruction: {
163203
type: "string",
164-
description: "Instruction for observation",
204+
description: "Instruction for observation (e.g., 'find the login button')",
165205
},
166206
},
207+
required: ["instruction"],
167208
},
168209
},
169210
];
@@ -210,13 +251,7 @@ async function ensureStagehand() {
210251
log("Ensuring Stagehand is initialized...");
211252
if (!stagehand) {
212253
log("Initializing Stagehand...");
213-
stagehand = new Stagehand({
214-
env: "BROWSERBASE",
215-
headless: true,
216-
verbose: 2,
217-
debugDom: true,
218-
modelName: "claude-3-5-sonnet-20241022",
219-
});
254+
stagehand = new Stagehand(stagehandConfig);
220255
log("Running init()");
221256
await stagehand.init();
222257
log("Stagehand initialized successfully");
@@ -319,7 +354,7 @@ async function handleToolCall(
319354
case "stagehand_act":
320355
try {
321356
log(`Performing action: ${args.action}`);
322-
await stagehand.act({
357+
await stagehand.page.act({
323358
action: args.action,
324359
variables: args.variables,
325360
});
@@ -351,6 +386,7 @@ async function handleToolCall(
351386
};
352387
}
353388

389+
/*
354390
case "stagehand_extract":
355391
try {
356392
log(`Extracting data with instruction: ${args.instruction}`);
@@ -396,10 +432,11 @@ async function handleToolCall(
396432
isError: true,
397433
};
398434
}
435+
*/
399436
case "stagehand_observe":
400437
try {
401438
log(`Starting observation with instruction: ${args.instruction}`);
402-
const observations = await stagehand.observe({
439+
const observations = await stagehand.page.observe({
403440
instruction: args.instruction,
404441
});
405442
log(
@@ -513,6 +550,47 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
513550
}
514551
});
515552

553+
554+
server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
555+
try {
556+
logRequest('ListResources', request.params);
557+
// Return an empty list since we don't have any resources defined
558+
const response = { resources: [] };
559+
const sanitizedResponse = sanitizeMessage(response);
560+
logResponse('ListResources', JSON.parse(sanitizedResponse));
561+
return JSON.parse(sanitizedResponse);
562+
} catch (error) {
563+
const errorMsg = error instanceof Error ? error.message : String(error);
564+
log(`ListResources handler error: ${errorMsg}`, 'error');
565+
return {
566+
error: {
567+
code: -32603,
568+
message: `Internal error: ${errorMsg}`,
569+
},
570+
};
571+
}
572+
});
573+
574+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async (request) => {
575+
try {
576+
logRequest('ListResourceTemplates', request.params);
577+
// Return an empty list since we don't have any resource templates defined
578+
const response = { resourceTemplates: [] };
579+
const sanitizedResponse = sanitizeMessage(response);
580+
logResponse('ListResourceTemplates', JSON.parse(sanitizedResponse));
581+
return JSON.parse(sanitizedResponse);
582+
} catch (error) {
583+
const errorMsg = error instanceof Error ? error.message : String(error);
584+
log(`ListResourceTemplates handler error: ${errorMsg}`, 'error');
585+
return {
586+
error: {
587+
code: -32603,
588+
message: `Internal error: ${errorMsg}`,
589+
},
590+
};
591+
}
592+
});
593+
516594
// Run the server
517595
async function runServer() {
518596
log("Starting Stagehand MCP server...", 'info');

0 commit comments

Comments
 (0)