diff --git a/src/puppeteer/README.md b/src/puppeteer/README.md index e81c69e6..a951a9a3 100644 --- a/src/puppeteer/README.md +++ b/src/puppeteer/README.md @@ -22,12 +22,22 @@ A Model Context Protocol server that provides browser automation capabilities us - Click elements on the page - Input: `selector` (string): CSS selector for element to click +- **puppeteer_hover** + - Hover elements on the page + - Input: `selector` (string): CSS selector for element to hover + - **puppeteer_fill** - Fill out input fields - Inputs: - `selector` (string): CSS selector for input field - `value` (string): Value to fill +- **puppeteer_select** + - Select an element with SELECT tag + - Inputs: + - `selector` (string): CSS selector for element to select + - `value` (string): Value to select + - **puppeteer_evaluate** - Execute JavaScript in the browser console - Input: `script` (string): JavaScript code to execute @@ -64,6 +74,7 @@ Here's the Claude Desktop configuration to use the Puppeter server: } } } +``` ## License diff --git a/src/puppeteer/index.ts b/src/puppeteer/index.ts index 9ad05cbe..d3aa2a30 100644 --- a/src/puppeteer/index.ts +++ b/src/puppeteer/index.ts @@ -64,6 +64,29 @@ const TOOLS: Tool[] = [ required: ["selector", "value"], }, }, + { + name: "puppeteer_select", + description: "Select an element on the page with Select tag", + inputSchema: { + type: "object", + properties: { + selector: { type: "string", description: "CSS selector for element to select" }, + value: { type: "string", description: "Value to select" }, + }, + required: ["selector", "value"], + }, + }, + { + name: "puppeteer_hover", + description: "Hover an element on the page", + inputSchema: { + type: "object", + properties: { + selector: { type: "string", description: "CSS selector for element to hover" }, + }, + required: ["selector"], + }, + }, { name: "puppeteer_evaluate", description: "Execute JavaScript in the browser console", @@ -88,7 +111,7 @@ async function ensureBrowser() { browser = await puppeteer.launch({ headless: false }); const pages = await browser.pages(); page = pages[0]; - + page.on("console", (msg) => { const logEntry = `[${msg.type()}] ${msg.text()}`; consoleLogs.push(logEntry); @@ -122,7 +145,7 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca const height = args.height ?? 600; await page.setViewport({ width, height }); - const screenshot = await (args.selector ? + const screenshot = await (args.selector ? (await page.$(args.selector))?.screenshot({ encoding: "base64" }) : page.screenshot({ encoding: "base64", fullPage: false })); @@ -210,12 +233,62 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca }; } + case "puppeteer_select": + try { + await page.waitForSelector(args.selector); + await page.select(args.selector, args.value); + return { + toolResult: { + content: [{ + type: "text", + text: `Selected ${args.selector} with: ${args.value}`, + }], + isError: false, + }, + }; + } catch (error) { + return { + toolResult: { + content: [{ + type: "text", + text: `Failed to select ${args.selector}: ${(error as Error).message}`, + }], + isError: true, + }, + }; + } + + case "puppeteer_hover": + try { + await page.waitForSelector(args.selector); + await page.hover(args.selector); + return { + toolResult: { + content: [{ + type: "text", + text: `Hovered ${args.selector}`, + }], + isError: false, + }, + }; + } catch (error) { + return { + toolResult: { + content: [{ + type: "text", + text: `Failed to hover ${args.selector}: ${(error as Error).message}`, + }], + isError: true, + }, + }; + } + case "puppeteer_evaluate": try { const result = await page.evaluate((script) => { const logs: string[] = []; const originalConsole = { ...console }; - + ['log', 'info', 'warn', 'error'].forEach(method => { (console as any)[method] = (...args: any[]) => { logs.push(`[${method}] ${args.join(' ')}`); @@ -301,7 +374,7 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => ({ server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const uri = request.params.uri.toString(); - + if (uri === "console://logs") { return { contents: [{ @@ -333,7 +406,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS, })); -server.setRequestHandler(CallToolRequestSchema, async (request) => +server.setRequestHandler(CallToolRequestSchema, async (request) => handleToolCall(request.params.name, request.params.arguments ?? {}) );