chore: introduce capabilities argument (#135)
This commit is contained in:
@@ -282,7 +282,7 @@ class PageSnapshot {
|
||||
results.push('');
|
||||
}
|
||||
if (options?.hasFileChooser) {
|
||||
results.push('- There is a file chooser visible that requires browser_choose_file to be called');
|
||||
results.push('- There is a file chooser visible that requires browser_file_upload to be called');
|
||||
results.push('');
|
||||
}
|
||||
results.push(this._text);
|
||||
|
||||
16
src/index.ts
16
src/index.ts
@@ -16,7 +16,7 @@
|
||||
|
||||
import { createServerWithTools } from './server';
|
||||
import common from './tools/common';
|
||||
import fileChooser from './tools/fileChooser';
|
||||
import files from './tools/files';
|
||||
import install from './tools/install';
|
||||
import keyboard from './tools/keyboard';
|
||||
import navigate from './tools/navigate';
|
||||
@@ -24,16 +24,16 @@ import pdf from './tools/pdf';
|
||||
import snapshot from './tools/snapshot';
|
||||
import tabs from './tools/tabs';
|
||||
import screen from './tools/screen';
|
||||
import { console } from './resources/console';
|
||||
import { console as consoleResource } from './resources/console';
|
||||
|
||||
import type { Tool } from './tools/tool';
|
||||
import type { Tool, ToolCapability } from './tools/tool';
|
||||
import type { Resource } from './resources/resource';
|
||||
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import type { LaunchOptions } from 'playwright';
|
||||
|
||||
const snapshotTools: Tool[] = [
|
||||
...common,
|
||||
...fileChooser(true),
|
||||
...files(true),
|
||||
...install,
|
||||
...keyboard(true),
|
||||
...navigate(true),
|
||||
@@ -44,7 +44,7 @@ const snapshotTools: Tool[] = [
|
||||
|
||||
const screenshotTools: Tool[] = [
|
||||
...common,
|
||||
...fileChooser(false),
|
||||
...files(false),
|
||||
...install,
|
||||
...keyboard(false),
|
||||
...navigate(false),
|
||||
@@ -54,7 +54,7 @@ const screenshotTools: Tool[] = [
|
||||
];
|
||||
|
||||
const resources: Resource[] = [
|
||||
console,
|
||||
consoleResource,
|
||||
];
|
||||
|
||||
type Options = {
|
||||
@@ -63,12 +63,14 @@ type Options = {
|
||||
launchOptions?: LaunchOptions;
|
||||
cdpEndpoint?: string;
|
||||
vision?: boolean;
|
||||
capabilities?: ToolCapability[];
|
||||
};
|
||||
|
||||
const packageJSON = require('../package.json');
|
||||
|
||||
export function createServer(options?: Options): Server {
|
||||
const tools = options?.vision ? screenshotTools : snapshotTools;
|
||||
const allTools = options?.vision ? screenshotTools : snapshotTools;
|
||||
const tools = allTools.filter(tool => !options?.capabilities || tool.capability === 'core' || options.capabilities.includes(tool.capability));
|
||||
return createServerWithTools({
|
||||
name: 'Playwright',
|
||||
version: packageJSON.version,
|
||||
|
||||
@@ -29,6 +29,7 @@ import { ServerList } from './server';
|
||||
|
||||
import type { LaunchOptions } from 'playwright';
|
||||
import assert from 'assert';
|
||||
import { ToolCapability } from './tools/tool';
|
||||
|
||||
const packageJSON = require('../package.json');
|
||||
|
||||
@@ -36,6 +37,7 @@ program
|
||||
.version('Version ' + packageJSON.version)
|
||||
.name(packageJSON.name)
|
||||
.option('--browser <browser>', 'Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.')
|
||||
.option('--caps <caps>', 'Comma-separated list of capabilities to enable, possible values: tabs, pdf, history, wait, files, install. Default is all.')
|
||||
.option('--cdp-endpoint <endpoint>', 'CDP endpoint to connect to.')
|
||||
.option('--executable-path <path>', 'Path to the browser executable.')
|
||||
.option('--headless', 'Run browser in headless mode, headed by default')
|
||||
@@ -85,6 +87,7 @@ program
|
||||
launchOptions,
|
||||
vision: !!options.vision,
|
||||
cdpEndpoint: options.cdpEndpoint,
|
||||
capabilities: options.caps?.split(',').map((c: string) => c.trim() as ToolCapability),
|
||||
}));
|
||||
setupExitWatchdog(serverList);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ const waitSchema = z.object({
|
||||
});
|
||||
|
||||
const wait: Tool = {
|
||||
capability: 'wait',
|
||||
schema: {
|
||||
name: 'browser_wait',
|
||||
description: 'Wait for a specified time in seconds',
|
||||
@@ -44,6 +45,7 @@ const wait: Tool = {
|
||||
const closeSchema = z.object({});
|
||||
|
||||
const close: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_close',
|
||||
description: 'Close the page',
|
||||
|
||||
@@ -19,18 +19,19 @@ import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||
|
||||
import type { ToolFactory } from './tool';
|
||||
|
||||
const chooseFileSchema = z.object({
|
||||
const uploadFileSchema = z.object({
|
||||
paths: z.array(z.string()).describe('The absolute paths to the files to upload. Can be a single file or multiple files.'),
|
||||
});
|
||||
|
||||
const chooseFile: ToolFactory = captureSnapshot => ({
|
||||
const uploadFile: ToolFactory = captureSnapshot => ({
|
||||
capability: 'files',
|
||||
schema: {
|
||||
name: 'browser_choose_file',
|
||||
description: 'Choose one or multiple files to upload',
|
||||
inputSchema: zodToJsonSchema(chooseFileSchema),
|
||||
name: 'browser_file_upload',
|
||||
description: 'Upload one or multiple files',
|
||||
inputSchema: zodToJsonSchema(uploadFileSchema),
|
||||
},
|
||||
handle: async (context, params) => {
|
||||
const validatedParams = chooseFileSchema.parse(params);
|
||||
const validatedParams = uploadFileSchema.parse(params);
|
||||
const tab = context.currentTab();
|
||||
return await tab.runAndWait(async () => {
|
||||
await tab.submitFileChooser(validatedParams.paths);
|
||||
@@ -43,5 +44,5 @@ const chooseFile: ToolFactory = captureSnapshot => ({
|
||||
});
|
||||
|
||||
export default (captureSnapshot: boolean) => [
|
||||
chooseFile(captureSnapshot),
|
||||
uploadFile(captureSnapshot),
|
||||
];
|
||||
@@ -23,6 +23,7 @@ import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||
import type { Tool } from './tool';
|
||||
|
||||
const install: Tool = {
|
||||
capability: 'install',
|
||||
schema: {
|
||||
name: 'browser_install',
|
||||
description: 'Install the browser specified in the config. Call this if you get an error about the browser not being installed.',
|
||||
|
||||
@@ -24,6 +24,7 @@ const pressKeySchema = z.object({
|
||||
});
|
||||
|
||||
const pressKey: ToolFactory = captureSnapshot => ({
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_press_key',
|
||||
description: 'Press a key on the keyboard',
|
||||
|
||||
@@ -24,6 +24,7 @@ const navigateSchema = z.object({
|
||||
});
|
||||
|
||||
const navigate: ToolFactory = captureSnapshot => ({
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_navigate',
|
||||
description: 'Navigate to a URL',
|
||||
@@ -44,6 +45,7 @@ const navigate: ToolFactory = captureSnapshot => ({
|
||||
const goBackSchema = z.object({});
|
||||
|
||||
const goBack: ToolFactory = snapshot => ({
|
||||
capability: 'history',
|
||||
schema: {
|
||||
name: 'browser_navigate_back',
|
||||
description: 'Go back to the previous page',
|
||||
@@ -62,6 +64,7 @@ const goBack: ToolFactory = snapshot => ({
|
||||
const goForwardSchema = z.object({});
|
||||
|
||||
const goForward: ToolFactory = snapshot => ({
|
||||
capability: 'history',
|
||||
schema: {
|
||||
name: 'browser_navigate_forward',
|
||||
description: 'Go forward to the next page',
|
||||
|
||||
@@ -27,6 +27,7 @@ import type { Tool } from './tool';
|
||||
const pdfSchema = z.object({});
|
||||
|
||||
const pdf: Tool = {
|
||||
capability: 'pdf',
|
||||
schema: {
|
||||
name: 'browser_pdf_save',
|
||||
description: 'Save page as PDF',
|
||||
|
||||
@@ -20,6 +20,7 @@ import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||
import type { Tool } from './tool';
|
||||
|
||||
const screenshot: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_screen_capture',
|
||||
description: 'Take a screenshot of the current page',
|
||||
@@ -45,6 +46,7 @@ const moveMouseSchema = elementSchema.extend({
|
||||
});
|
||||
|
||||
const moveMouse: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_screen_move_mouse',
|
||||
description: 'Move mouse to a given position',
|
||||
@@ -67,6 +69,7 @@ const clickSchema = elementSchema.extend({
|
||||
});
|
||||
|
||||
const click: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_screen_click',
|
||||
description: 'Click left mouse button',
|
||||
@@ -93,6 +96,7 @@ const dragSchema = elementSchema.extend({
|
||||
});
|
||||
|
||||
const drag: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_screen_drag',
|
||||
description: 'Drag left mouse button',
|
||||
@@ -118,6 +122,7 @@ const typeSchema = z.object({
|
||||
});
|
||||
|
||||
const type: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_screen_type',
|
||||
description: 'Type text',
|
||||
|
||||
@@ -21,6 +21,7 @@ import type * as playwright from 'playwright';
|
||||
import type { Tool } from './tool';
|
||||
|
||||
const snapshot: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_snapshot',
|
||||
description: 'Capture accessibility snapshot of the current page, this is better than screenshot',
|
||||
@@ -38,6 +39,7 @@ const elementSchema = z.object({
|
||||
});
|
||||
|
||||
const click: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_click',
|
||||
description: 'Perform click on a web page',
|
||||
@@ -63,6 +65,7 @@ const dragSchema = z.object({
|
||||
});
|
||||
|
||||
const drag: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_drag',
|
||||
description: 'Perform drag and drop between two elements',
|
||||
@@ -82,6 +85,7 @@ const drag: Tool = {
|
||||
};
|
||||
|
||||
const hover: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_hover',
|
||||
description: 'Hover over element on page',
|
||||
@@ -106,6 +110,7 @@ const typeSchema = elementSchema.extend({
|
||||
});
|
||||
|
||||
const type: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_type',
|
||||
description: 'Type text into editable element',
|
||||
@@ -133,6 +138,7 @@ const selectOptionSchema = elementSchema.extend({
|
||||
});
|
||||
|
||||
const selectOption: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_select_option',
|
||||
description: 'Select an option in a dropdown',
|
||||
@@ -155,6 +161,7 @@ const screenshotSchema = z.object({
|
||||
});
|
||||
|
||||
const screenshot: Tool = {
|
||||
capability: 'core',
|
||||
schema: {
|
||||
name: 'browser_take_screenshot',
|
||||
description: `Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.`,
|
||||
|
||||
@@ -20,6 +20,7 @@ import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||
import type { ToolFactory, Tool } from './tool';
|
||||
|
||||
const listTabs: Tool = {
|
||||
capability: 'tabs',
|
||||
schema: {
|
||||
name: 'browser_tab_list',
|
||||
description: 'List browser tabs',
|
||||
@@ -40,6 +41,7 @@ const selectTabSchema = z.object({
|
||||
});
|
||||
|
||||
const selectTab: ToolFactory = captureSnapshot => ({
|
||||
capability: 'tabs',
|
||||
schema: {
|
||||
name: 'browser_tab_select',
|
||||
description: 'Select a tab by index',
|
||||
@@ -58,6 +60,7 @@ const newTabSchema = z.object({
|
||||
});
|
||||
|
||||
const newTab: Tool = {
|
||||
capability: 'tabs',
|
||||
schema: {
|
||||
name: 'browser_tab_new',
|
||||
description: 'Open a new tab',
|
||||
@@ -77,6 +80,7 @@ const closeTabSchema = z.object({
|
||||
});
|
||||
|
||||
const closeTab: ToolFactory = captureSnapshot => ({
|
||||
capability: 'tabs',
|
||||
schema: {
|
||||
name: 'browser_tab_close',
|
||||
description: 'Close a tab',
|
||||
|
||||
@@ -18,6 +18,8 @@ import type { ImageContent, TextContent } from '@modelcontextprotocol/sdk/types'
|
||||
import type { JsonSchema7Type } from 'zod-to-json-schema';
|
||||
import type { Context } from '../context';
|
||||
|
||||
export type ToolCapability = 'core' | 'tabs' | 'pdf' | 'history' | 'wait' | 'files' | 'install';
|
||||
|
||||
export type ToolSchema = {
|
||||
name: string;
|
||||
description: string;
|
||||
@@ -30,6 +32,7 @@ export type ToolResult = {
|
||||
};
|
||||
|
||||
export type Tool = {
|
||||
capability: ToolCapability;
|
||||
schema: ToolSchema;
|
||||
handle: (context: Context, params?: Record<string, any>) => Promise<ToolResult>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user