Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@ The Playwright MCP provides a set of tools for browser automation. Here are all
- `ref` (string): Exact target element reference from the page snapshot
- `values` (array): Array of values to select in the dropdown.

- **browser_choose_file**
- Description: Choose one or multiple files to upload
- Parameters:
- `paths` (array): The absolute paths to the files to upload. Can be a single file or multiple files.

- **browser_press_key**
- Description: Press a key on the keyboard
- Parameters:
Expand Down Expand Up @@ -286,6 +291,11 @@ Vision Mode provides tools for visual-based interactions using screenshots. Here
- Parameters:
- `key` (string): Name of the key to press or a character to generate, such as `ArrowLeft` or `a`

- **browser_choose_file**
- Description: Choose one or multiple files to upload
- Parameters:
- `paths` (array): The absolute paths to the files to upload. Can be a single file or multiple files.

- **browser_save_as_pdf**
- Description: Save page as PDF
- Parameters: None
Expand Down
10 changes: 10 additions & 0 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class Context {
private _page: playwright.Page | undefined;
private _console: playwright.ConsoleMessage[] = [];
private _createPagePromise: Promise<playwright.Page> | undefined;
private _fileChooser: playwright.FileChooser | undefined;

constructor(userDataDir: string, launchOptions?: playwright.LaunchOptions) {
this._userDataDir = userDataDir;
Expand All @@ -40,6 +41,7 @@ export class Context {
this._console.length = 0;
});
page.on('close', () => this._onPageClose());
page.on('filechooser', chooser => this._fileChooser = chooser);
this._page = page;
this._browser = browser;
return page;
Expand All @@ -55,6 +57,7 @@ export class Context {
this._createPagePromise = undefined;
this._browser = undefined;
this._page = undefined;
this._fileChooser = undefined;
this._console.length = 0;
}

Expand All @@ -74,6 +77,13 @@ export class Context {
await this._page.close();
}

async submitFileChooser(paths: string[]) {
if (!this._fileChooser)
throw new Error('No file chooser visible');
await this._fileChooser.setFiles(paths);
this._fileChooser = undefined;
}

private async _createPage(): Promise<{ browser?: playwright.Browser, page: playwright.Page }> {
if (process.env.PLAYWRIGHT_WS_ENDPOINT) {
const url = new URL(process.env.PLAYWRIGHT_WS_ENDPOINT);
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const snapshotTools: Tool[] = [
common.navigate(true),
common.goBack(true),
common.goForward(true),
common.chooseFile(true),
snapshot.snapshot,
snapshot.click,
snapshot.hover,
Expand All @@ -48,6 +49,7 @@ const screenshotTools: Tool[] = [
common.navigate(false),
common.goBack(false),
common.goForward(false),
common.chooseFile(false),
screenshot.screenshot,
screenshot.moveMouse,
screenshot.click,
Expand Down
18 changes: 18 additions & 0 deletions src/tools/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,21 @@ export const close: Tool = {
};
},
};

const chooseFileSchema = z.object({
paths: z.array(z.string()).describe('The absolute paths to the files to upload. Can be a single file or multiple files.'),
});

export const chooseFile: ToolFactory = snapshot => ({
schema: {
name: 'browser_choose_file',
description: 'Choose one or multiple files to upload',
inputSchema: zodToJsonSchema(chooseFileSchema),
},
handle: async (context, params) => {
const validatedParams = chooseFileSchema.parse(params);
return await runAndWait(context, `Chose files ${validatedParams.paths.join(', ')}`, async () => {
await context.submitFileChooser(validatedParams.paths);
}, snapshot);
},
});
Loading