💬 Commit message: Update 2026-02-08 03:05:28, 17 files, 662 lines
📁 Files changed: 17 📝 Lines changed: 662 • plugin.json • .mcp.json • README.md • analyze.md • compare.md • end.md • extract.md • fill.md • goto.md • restore.md • save.md • scrape.md • screenshot.md • start.md • package.json • browser.ts • mcp.ts
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "browse",
|
||||
"description": "Browser automation and image processing tools for Claude Code using Playwright WebKit",
|
||||
"version": "0.2.0",
|
||||
"author": {
|
||||
"name": "aladac",
|
||||
"url": "https://github.com/aladac"
|
||||
},
|
||||
"repository": "https://github.com/aladac/claude-browse",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"browser",
|
||||
"automation",
|
||||
"playwright",
|
||||
"webkit",
|
||||
"screenshot",
|
||||
"scraping",
|
||||
"image-processing"
|
||||
],
|
||||
"mcpServers": "./.mcp.json",
|
||||
"commands": "./commands"
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"claude-browse": {
|
||||
"command": "npx",
|
||||
"args": ["claude-browse-mcp"]
|
||||
"command": "node",
|
||||
"args": ["${CLAUDE_PLUGIN_ROOT}/dist/mcp.js"],
|
||||
"env": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,9 +85,45 @@ curl -X POST localhost:3000 -d '{"cmd":"wait","ms":2000}'
|
||||
curl -X POST localhost:3000 -d '{"cmd":"close"}'
|
||||
```
|
||||
|
||||
## MCP Server (Model Context Protocol)
|
||||
## Claude Code Plugin (Recommended)
|
||||
|
||||
Use with Claude Code or any MCP-compatible client:
|
||||
Install as a Claude Code plugin for the best integration:
|
||||
|
||||
```bash
|
||||
# Install the plugin
|
||||
claude plugin install https://github.com/aladac/claude-browse
|
||||
|
||||
# Or load temporarily during development
|
||||
claude --plugin-dir /path/to/claude-browse
|
||||
```
|
||||
|
||||
### Plugin Features
|
||||
|
||||
**Slash Commands:**
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/browse:start` | Start an interactive browsing session |
|
||||
| `/browse:goto <url>` | Navigate to URL and describe findings |
|
||||
| `/browse:screenshot` | Take a screenshot of the current page |
|
||||
| `/browse:scrape <url>` | Scrape content from a webpage |
|
||||
| `/browse:analyze` | Analyze current page content and structure |
|
||||
| `/browse:extract [selector]` | Extract structured data from page |
|
||||
| `/browse:fill [data]` | Help fill out forms |
|
||||
| `/browse:compare [action]` | Compare page states before/after action |
|
||||
|
||||
**MCP Resources (@ mentions):**
|
||||
|
||||
| Resource | Description |
|
||||
|----------|-------------|
|
||||
| `@claude-browse:browser://state` | Browser state (URL, title, launched) |
|
||||
| `@claude-browse:browser://html` | Page HTML (truncated to 10KB) |
|
||||
| `@claude-browse:browser://html/full` | Complete page HTML |
|
||||
| `@claude-browse:browser://screenshot` | Page screenshot as base64 PNG |
|
||||
|
||||
## MCP Server (Standalone)
|
||||
|
||||
Use with any MCP-compatible client:
|
||||
|
||||
```bash
|
||||
# Run the MCP server
|
||||
@@ -106,7 +142,9 @@ Add to Claude Code's MCP config (`~/.claude/settings.json`):
|
||||
}
|
||||
```
|
||||
|
||||
Available tools: `goto`, `click`, `type`, `query`, `screenshot`, `url`, `html`, `back`, `forward`, `reload`, `wait`, `eval`
|
||||
**Available Tools:** `goto`, `click`, `type`, `query`, `screenshot`, `url`, `html`, `back`, `forward`, `reload`, `wait`, `eval`
|
||||
|
||||
**Image Processing Tools:** `favicon`, `convert`, `resize`, `crop`, `compress`, `thumbnail`
|
||||
|
||||
## Programmatic Usage
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
description: Analyze the current page content and structure
|
||||
---
|
||||
|
||||
Use the analyze_page MCP prompt to analyze the current browser page.
|
||||
|
||||
If the browser is not launched, first navigate to a URL using the goto tool, then analyze the page structure, content, and interactive elements.
|
||||
|
||||
Provide:
|
||||
1. A summary of the page purpose
|
||||
2. Key interactive elements (forms, buttons, links)
|
||||
3. Notable structure or patterns
|
||||
4. Suggestions for useful actions
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
description: Compare page states with screenshots before and after an action
|
||||
---
|
||||
|
||||
Compare page states:
|
||||
|
||||
1. Take an initial screenshot of the current page
|
||||
2. Ask what action to perform (click, navigate, submit, etc.)
|
||||
3. Perform the requested action
|
||||
4. Take another screenshot
|
||||
5. Describe the visual and structural differences
|
||||
|
||||
What action would you like to perform between screenshots? $ARGUMENTS
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
description: End the current browsing session and close the browser
|
||||
---
|
||||
|
||||
End the current browsing session.
|
||||
|
||||
Use the `close` tool to close the browser. This will:
|
||||
1. Close all browser pages
|
||||
2. Clear the browser state
|
||||
3. Free up system resources
|
||||
|
||||
The browser can be relaunched with any navigation command (goto, start, etc.)
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
description: Extract structured data from the current page
|
||||
---
|
||||
|
||||
Extract structured data from the current browser page.
|
||||
|
||||
Selector (optional): $ARGUMENTS
|
||||
|
||||
Steps:
|
||||
1. If a selector is provided, use the query tool to find matching elements
|
||||
2. Analyze the page structure to identify data patterns
|
||||
3. Extract and structure the data in a useful format (JSON, table, etc.)
|
||||
4. Identify patterns that could help with similar pages
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
description: Help fill out a form on the current page
|
||||
---
|
||||
|
||||
Fill form with data: $ARGUMENTS
|
||||
|
||||
Steps:
|
||||
1. Use the query tool to find form inputs (input, textarea, select)
|
||||
2. Identify required fields and their types
|
||||
3. If data is provided, parse it and fill the matching fields using the type tool
|
||||
4. Report what was filled and any issues encountered
|
||||
|
||||
If no data provided, describe the form fields found and ask what to fill in.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
description: Navigate to a URL and describe what you find
|
||||
---
|
||||
|
||||
Navigate to: $ARGUMENTS
|
||||
|
||||
Steps:
|
||||
1. Use the goto tool to navigate to the URL
|
||||
2. Take a screenshot to see the page
|
||||
3. Describe what you see
|
||||
4. Identify the main interactive elements
|
||||
5. Suggest what actions might be useful
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
description: Restore a previously saved browsing session
|
||||
---
|
||||
|
||||
Restore session from: $ARGUMENTS
|
||||
|
||||
Use the `session_restore` tool to restore a previously saved session:
|
||||
- Navigate to the saved URL
|
||||
- Restore all cookies
|
||||
- Restore localStorage data
|
||||
- Restore sessionStorage data
|
||||
|
||||
If no path is specified, restore from `session.json` in the current directory.
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
description: Save the current browsing session state to a file
|
||||
---
|
||||
|
||||
Save the current session state to: $ARGUMENTS
|
||||
|
||||
Use the `session_save` tool to save:
|
||||
- Current URL and page title
|
||||
- All cookies
|
||||
- localStorage data
|
||||
- sessionStorage data
|
||||
|
||||
If no path is specified, save to `session.json` in the current directory.
|
||||
|
||||
This allows you to restore the session later with `/claude-browse:restore`.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
description: Scrape content from a webpage
|
||||
---
|
||||
|
||||
Scrape and extract content from: $ARGUMENTS
|
||||
|
||||
Steps:
|
||||
1. Navigate to the URL using `goto`
|
||||
2. Wait for the page to load
|
||||
3. Query the page structure to understand the layout
|
||||
4. Extract the relevant content using `query` and `eval` tools
|
||||
5. Return the structured data
|
||||
|
||||
Focus on extracting meaningful content (text, links, data) rather than raw HTML.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
description: Take a screenshot of the current page
|
||||
---
|
||||
|
||||
Take a screenshot of the current browser page and analyze its contents.
|
||||
|
||||
If the browser hasn't been started yet, ask for a URL first, navigate there, then take the screenshot.
|
||||
|
||||
Use the `screenshot` tool with fullPage=$ARGUMENTS if specified (true/false), otherwise use default viewport.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
description: Start an interactive browsing session
|
||||
---
|
||||
|
||||
Start an interactive browser session. Use the browser tools to:
|
||||
1. Navigate to URLs with `goto`
|
||||
2. Take screenshots to see page content
|
||||
3. Query elements with CSS selectors
|
||||
4. Click and type to interact with pages
|
||||
|
||||
The browser is headless WebKit (Safari engine). Start by asking what URL to visit.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@aladac/claude-browse",
|
||||
"version": "0.1.2",
|
||||
"version": "0.2.0",
|
||||
"description": "Headless browser automation for Claude Code using Playwright WebKit",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -44,6 +44,16 @@ export class ClaudeBrowser {
|
||||
return this.page;
|
||||
}
|
||||
|
||||
/** Get the current page instance (for advanced usage) */
|
||||
getPage(): Page | null {
|
||||
return this.page;
|
||||
}
|
||||
|
||||
/** Get the browser context (for advanced usage like cookies) */
|
||||
getContext(): BrowserContext | null {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
async goto(url: string): Promise<{ url: string; title: string }> {
|
||||
const page = this.ensurePage();
|
||||
await page.goto(url, { waitUntil: 'networkidle' });
|
||||
|
||||
+440
-1
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import { z } from 'zod';
|
||||
import { ClaudeBrowser } from './browser.js';
|
||||
@@ -8,6 +8,7 @@ import { type CommandLike, type ResultLike, stderrLogger as log } from './logger
|
||||
|
||||
const browser = new ClaudeBrowser({ headless: true, width: 1280, height: 800 });
|
||||
let launched = false;
|
||||
let currentScreenshotBuffer: Buffer | null = null;
|
||||
|
||||
async function ensureLaunched(): Promise<void> {
|
||||
if (!launched) {
|
||||
@@ -188,6 +189,124 @@ server.tool(
|
||||
})
|
||||
);
|
||||
|
||||
// Session management
|
||||
server.tool(
|
||||
'close',
|
||||
'Close the browser and end the current session',
|
||||
{},
|
||||
withLogging('close', async () => {
|
||||
if (launched) {
|
||||
await browser.close();
|
||||
launched = false;
|
||||
}
|
||||
return textResult(JSON.stringify({ ok: true, message: 'Browser closed' }));
|
||||
})
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'session_save',
|
||||
'Save the current session state (URL, cookies, localStorage, sessionStorage) to a JSON file',
|
||||
{
|
||||
path: z.string().optional().default('session.json').describe('Path to save session file'),
|
||||
},
|
||||
withLogging('session_save', async ({ path }) => {
|
||||
await ensureLaunched();
|
||||
const { writeFile } = await import('node:fs/promises');
|
||||
const { resolve } = await import('node:path');
|
||||
|
||||
const page = browser.getPage();
|
||||
const context = browser.getContext();
|
||||
if (!page || !context) {
|
||||
return textResult(JSON.stringify({ ok: false, error: 'No active page' }));
|
||||
}
|
||||
|
||||
const url = page.url();
|
||||
const title = await page.title();
|
||||
const cookies = await context.cookies();
|
||||
|
||||
// Get localStorage and sessionStorage (runs in browser context)
|
||||
const storage = await page.evaluate(`({
|
||||
localStorage: Object.fromEntries(
|
||||
Array.from({ length: localStorage.length }, (_, i) => localStorage.key(i))
|
||||
.filter(k => k !== null)
|
||||
.map(k => [k, localStorage.getItem(k) || ''])
|
||||
),
|
||||
sessionStorage: Object.fromEntries(
|
||||
Array.from({ length: sessionStorage.length }, (_, i) => sessionStorage.key(i))
|
||||
.filter(k => k !== null)
|
||||
.map(k => [k, sessionStorage.getItem(k) || ''])
|
||||
),
|
||||
})`) as { localStorage: Record<string, string>; sessionStorage: Record<string, string> };
|
||||
|
||||
const sessionData = {
|
||||
url,
|
||||
title,
|
||||
cookies,
|
||||
localStorage: storage.localStorage,
|
||||
sessionStorage: storage.sessionStorage,
|
||||
savedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const resolvedPath = resolve(path);
|
||||
await writeFile(resolvedPath, JSON.stringify(sessionData, null, 2));
|
||||
return textResult(
|
||||
JSON.stringify({ ok: true, path: resolvedPath, url, cookieCount: cookies.length })
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'session_restore',
|
||||
'Restore a previously saved session state from a JSON file',
|
||||
{
|
||||
path: z.string().optional().default('session.json').describe('Path to session file'),
|
||||
},
|
||||
withLogging('session_restore', async ({ path }) => {
|
||||
await ensureLaunched();
|
||||
const { readFile } = await import('node:fs/promises');
|
||||
const { resolve } = await import('node:path');
|
||||
|
||||
const resolvedPath = resolve(path);
|
||||
const data = JSON.parse(await readFile(resolvedPath, 'utf-8'));
|
||||
|
||||
const page = browser.getPage();
|
||||
const context = browser.getContext();
|
||||
if (!page || !context) {
|
||||
return textResult(JSON.stringify({ ok: false, error: 'No active page' }));
|
||||
}
|
||||
|
||||
// Restore cookies first
|
||||
if (data.cookies?.length > 0) {
|
||||
await context.addCookies(data.cookies);
|
||||
}
|
||||
|
||||
// Navigate to saved URL
|
||||
if (data.url) {
|
||||
await page.goto(data.url, { waitUntil: 'networkidle' });
|
||||
}
|
||||
|
||||
// Restore storage (runs in browser context)
|
||||
const local = data.localStorage || {};
|
||||
const session = data.sessionStorage || {};
|
||||
await page.evaluate(
|
||||
`((data) => {
|
||||
for (const [k, v] of Object.entries(data.local)) localStorage.setItem(k, v);
|
||||
for (const [k, v] of Object.entries(data.session)) sessionStorage.setItem(k, v);
|
||||
})(${JSON.stringify({ local, session })})`
|
||||
);
|
||||
|
||||
return textResult(
|
||||
JSON.stringify({
|
||||
ok: true,
|
||||
url: data.url,
|
||||
title: data.title,
|
||||
cookiesRestored: data.cookies?.length || 0,
|
||||
savedAt: data.savedAt,
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
// Image processing
|
||||
server.tool(
|
||||
'favicon',
|
||||
@@ -290,7 +409,327 @@ server.tool(
|
||||
})
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// MCP Resources - Browser state accessible via @ mentions
|
||||
// ============================================================================
|
||||
|
||||
// Resource: browser://state - Current browser state (URL, title, launched status)
|
||||
server.resource(
|
||||
'Browser State',
|
||||
'browser://state',
|
||||
{
|
||||
description: 'Current browser state including URL, title, and status',
|
||||
mimeType: 'application/json',
|
||||
},
|
||||
async () => {
|
||||
if (!launched) {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'browser://state',
|
||||
mimeType: 'application/json',
|
||||
text: JSON.stringify({ launched: false, url: null, title: null }),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const state = await browser.getUrl();
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'browser://state',
|
||||
mimeType: 'application/json',
|
||||
text: JSON.stringify({ launched: true, ...state }),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Resource: browser://html - Current page HTML content
|
||||
server.resource(
|
||||
'Page HTML',
|
||||
'browser://html',
|
||||
{ description: 'HTML content of the current page (truncated to 10KB)', mimeType: 'text/html' },
|
||||
async () => {
|
||||
if (!launched) {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'browser://html',
|
||||
mimeType: 'text/plain',
|
||||
text: 'Browser not launched. Use goto tool first.',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const html = await browser.getHtml(false);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'browser://html',
|
||||
mimeType: 'text/html',
|
||||
text: html,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Resource: browser://html/full - Full page HTML content
|
||||
server.resource(
|
||||
'Full Page HTML',
|
||||
'browser://html/full',
|
||||
{ description: 'Complete HTML content of the current page', mimeType: 'text/html' },
|
||||
async () => {
|
||||
if (!launched) {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'browser://html/full',
|
||||
mimeType: 'text/plain',
|
||||
text: 'Browser not launched. Use goto tool first.',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const html = await browser.getHtml(true);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'browser://html/full',
|
||||
mimeType: 'text/html',
|
||||
text: html,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Resource: browser://screenshot - Current page screenshot (base64)
|
||||
server.resource(
|
||||
'Page Screenshot',
|
||||
'browser://screenshot',
|
||||
{ description: 'Screenshot of the current page as base64 PNG', mimeType: 'image/png' },
|
||||
async () => {
|
||||
if (!launched) {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'browser://screenshot',
|
||||
mimeType: 'text/plain',
|
||||
text: 'Browser not launched. Use goto tool first.',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const result = await browser.screenshot(undefined, false);
|
||||
currentScreenshotBuffer = result.buffer || null;
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'browser://screenshot',
|
||||
mimeType: 'image/png',
|
||||
blob: result.buffer?.toString('base64') || '',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// MCP Prompts - Common workflows accessible via / commands
|
||||
// ============================================================================
|
||||
|
||||
// Prompt: Analyze current page
|
||||
server.prompt('analyze_page', 'Analyze the current page content and structure', async () => {
|
||||
if (!launched) {
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: 'The browser is not launched yet. Please use the goto tool to navigate to a URL first, then I can analyze the page.',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const state = await browser.getUrl();
|
||||
const html = await browser.getHtml(false);
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Analyze the following webpage:
|
||||
|
||||
URL: ${state.url}
|
||||
Title: ${state.title}
|
||||
|
||||
HTML Content (truncated):
|
||||
\`\`\`html
|
||||
${html}
|
||||
\`\`\`
|
||||
|
||||
Please provide:
|
||||
1. A summary of the page purpose and content
|
||||
2. Key interactive elements (forms, buttons, links)
|
||||
3. Any notable structure or patterns
|
||||
4. Suggestions for what actions might be useful`,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// Prompt: Extract data from page
|
||||
server.prompt(
|
||||
'extract_data',
|
||||
'Extract structured data from the current page',
|
||||
{ selector: z.string().optional().describe('CSS selector to focus extraction (optional)') },
|
||||
async ({ selector }) => {
|
||||
if (!launched) {
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: 'The browser is not launched yet. Please use the goto tool to navigate to a URL first.',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const state = await browser.getUrl();
|
||||
let elements: { tag: string; text: string; attributes: Record<string, string> }[] = [];
|
||||
if (selector) {
|
||||
elements = await browser.query(selector);
|
||||
}
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Extract structured data from this webpage:
|
||||
|
||||
URL: ${state.url}
|
||||
Title: ${state.title}
|
||||
${selector ? `\nSelector: ${selector}\nMatched Elements: ${elements.length}\n\nElements:\n${JSON.stringify(elements, null, 2)}` : ''}
|
||||
|
||||
Please:
|
||||
1. Use the query tool to find relevant data elements
|
||||
2. Extract and structure the data in a useful format (JSON, table, etc.)
|
||||
3. Identify patterns that could help with similar pages`,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Prompt: Navigate and interact
|
||||
server.prompt(
|
||||
'navigate_to',
|
||||
'Navigate to a URL and describe what you find',
|
||||
{ url: z.string().url().describe('URL to navigate to') },
|
||||
async ({ url }) => {
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Please navigate to ${url} and:
|
||||
|
||||
1. Use the goto tool to navigate there
|
||||
2. Take a screenshot to see the page
|
||||
3. Describe what you see
|
||||
4. Identify the main interactive elements
|
||||
5. Suggest what actions might be useful
|
||||
|
||||
Start by navigating to the URL.`,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Prompt: Fill form
|
||||
server.prompt(
|
||||
'fill_form',
|
||||
'Help fill out a form on the current page',
|
||||
{ formData: z.string().optional().describe('JSON object with field names and values to fill') },
|
||||
async ({ formData }) => {
|
||||
if (!launched) {
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: 'The browser is not launched yet. Please use the goto tool to navigate to a page with a form first.',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
const state = await browser.getUrl();
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Help fill out a form on this page:
|
||||
|
||||
URL: ${state.url}
|
||||
Title: ${state.title}
|
||||
${formData ? `\nData to fill: ${formData}` : ''}
|
||||
|
||||
Please:
|
||||
1. Use the query tool to find form inputs (input, textarea, select)
|
||||
2. Identify required fields and their types
|
||||
3. Use the type tool to fill in each field
|
||||
4. Report what was filled and any issues encountered`,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Prompt: Screenshot comparison
|
||||
server.prompt('compare_screenshots', 'Take screenshots and compare changes', async () => {
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `I'll help you compare page states:
|
||||
|
||||
1. Take an initial screenshot
|
||||
2. Perform some action (click, navigate, etc.)
|
||||
3. Take another screenshot
|
||||
4. Describe the differences
|
||||
|
||||
What action would you like me to perform between screenshots?`,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Start server
|
||||
// ============================================================================
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
|
||||
Reference in New Issue
Block a user