Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
190 changes: 95 additions & 95 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,100 +24,100 @@ jobs:
- name: Ensure no changes
run: git diff --exit-code

test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-15, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Playwright install
run: npx playwright install --with-deps
- name: Install MS Edge
# MS Edge is not preinstalled on macOS runners.
if: ${{ matrix.os == 'macos-latest' }}
run: npx playwright install msedge
- name: Build
run: npm run build
- name: Run tests
run: npm test
# test:
# strategy:
# fail-fast: false
# matrix:
# os: [ubuntu-latest, macos-15, windows-latest]
# runs-on: ${{ matrix.os }}
# steps:
# - uses: actions/checkout@v4
# - name: Use Node.js 20
# uses: actions/setup-node@v4
# with:
# node-version: '20'
# cache: 'npm'
# - name: Install dependencies
# run: npm ci
# - name: Playwright install
# run: npx playwright install --with-deps
# - name: Install MS Edge
# # MS Edge is not preinstalled on macOS runners.
# if: ${{ matrix.os == 'macos-latest' }}
# run: npx playwright install msedge
# - name: Build
# run: npm run build
# - name: Run tests
# run: npm test

test_docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Playwright install
run: npx playwright install --with-deps chromium
- name: Build
run: npm run build
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
tags: playwright-mcp-dev:latest
cache-from: type=gha
cache-to: type=gha,mode=max
load: true
- name: Run tests
shell: bash
run: |
# Used for the Docker tests to share the test-results folder with the container.
umask 0000
npm run test -- --project=chromium-docker
env:
MCP_IN_DOCKER: 1
# test_docker:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Use Node.js 20
# uses: actions/setup-node@v4
# with:
# node-version: '20'
# cache: 'npm'
# - name: Install dependencies
# run: npm ci
# - name: Playwright install
# run: npx playwright install --with-deps chromium
# - name: Build
# run: npm run build
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v3
# - name: Build and push
# uses: docker/build-push-action@v6
# with:
# tags: playwright-mcp-dev:latest
# cache-from: type=gha
# cache-to: type=gha,mode=max
# load: true
# - name: Run tests
# shell: bash
# run: |
# # Used for the Docker tests to share the test-results folder with the container.
# umask 0000
# npm run test -- --project=chromium-docker
# env:
# MCP_IN_DOCKER: 1

test_extension:
strategy:
fail-fast: false
runs-on: macos-latest
defaults:
run:
working-directory: ./extension
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20' # crypto.randomUUID(); stalls in v18.20.8
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build extension
run: npm run build
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: extension
path: ./extension/dist
retention-days: 7
- name: Install and build MCP server
run: |
cd ..
npm ci
npm run build
npx playwright install chromium
- name: Run tests
run: |
if [[ "$(uname)" == "Linux" ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test
else
npm run test
fi
shell: bash
# test_extension:
# strategy:
# fail-fast: false
# runs-on: macos-latest
# defaults:
# run:
# working-directory: ./extension
# steps:
# - uses: actions/checkout@v4
# - name: Use Node.js 20
# uses: actions/setup-node@v4
# with:
# node-version: '20' # crypto.randomUUID(); stalls in v18.20.8
# cache: 'npm'
# - name: Install dependencies
# run: npm ci
# - name: Build extension
# run: npm run build
# - name: Upload artifact
# uses: actions/upload-artifact@v4
# with:
# name: extension
# path: ./extension/dist
# retention-days: 7
# - name: Install and build MCP server
# run: |
# cd ..
# npm ci
# npm run build
# npx playwright install chromium
# - name: Run tests
# run: |
# if [[ "$(uname)" == "Linux" ]]; then
# xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test
# else
# npm run test
# fi
# shell: bash
2 changes: 2 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ LICENSE
!cli.js
!index.*
!config.d.ts
!context.d.ts
!tab.d.ts
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Playwright MCP server supports following arguments. They can be provided in the
<!--- Options generated by update-readme.js -->

```
> npx @playwright/mcp@latest --help
> npx asteroid-playwright-mcp@latest --help
--allowed-origins <origins> semicolon-separated list of origins to allow the
browser to request. Default is to allow all.
--blocked-origins <origins> semicolon-separated list of origins to block the
Expand Down
149 changes: 149 additions & 0 deletions context.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type * as playwright from 'playwright';
import type {
ImageContent,
TextContent,
} from '@modelcontextprotocol/sdk/types.js';
import type { Tab } from './tab.js';

/**
* Tool capability types
*/
export type ToolCapability =
| 'core'
| 'tabs'
| 'pdf'
| 'history'
| 'wait'
| 'files'
| 'install'
| 'testing';

/**
* Configuration for the MCP server
*/
export type FullConfig = {
browser: {
browserAgent?: string;
browserName: 'chromium' | 'firefox' | 'webkit';
isolated?: boolean;
userDataDir?: string;
launchOptions?: playwright.LaunchOptions;
contextOptions?: playwright.BrowserContextOptions;
cdpEndpoint?: string;
remoteEndpoint?: string;
};
server?: {
port?: number;
host?: string;
};
capabilities?: ToolCapability[];
vision?: boolean;
saveTrace?: boolean;
outputDir?: string;
network?: {
allowedOrigins?: string[];
blockedOrigins?: string[];
};
imageResponses?: 'allow' | 'omit' | 'auto';
};

/**
* Modal state types for handling dialogs and file choosers
*/
export type FileUploadModalState = {
type: 'fileChooser';
description: string;
fileChooser: playwright.FileChooser;
};

export type DialogModalState = {
type: 'dialog';
description: string;
dialog: playwright.Dialog;
};

export type ModalState = FileUploadModalState | DialogModalState;

/**
* Tool action result type
*/
export type ToolActionResult =
| { content?: (ImageContent | TextContent)[] }
| undefined
| void;

/**
* Tool result type
*/
export type ToolResult = {
code: string[];
action?: () => Promise<ToolActionResult>;
captureSnapshot: boolean;
waitForNetwork: boolean;
resultOverride?: ToolActionResult;
};

/**
* Tool schema type
*/
export type ToolSchema<Input = any> = {
name: string;
title: string;
description: string;
inputSchema: Input;
type: 'readOnly' | 'destructive';
};

/**
* Tool type definition
*/
export type Tool<Input = any> = {
capability: ToolCapability;
schema: ToolSchema<Input>;
clearsModalState?: ModalState['type'];
handle: (context: Context, params: any) => Promise<ToolResult>;
};

/**
* Context class type definition
*/
export type Context = {
readonly tools: Tool[];
readonly config: FullConfig;
clientVersion?: { name: string; version: string };

clientSupportsImages(): boolean;
modalStates(): ModalState[];
setModalState(modalState: ModalState, inTab: Tab): void;
clearModalState(modalState: ModalState): void;
modalStatesMarkdown(): string[];
tabs(): Tab[];
currentTabOrDie(): Tab;
newTab(): Promise<Tab>;
selectTab(index: number): Promise<void>;
ensureTab(): Promise<Tab>;
listTabsMarkdown(): Promise<string>;
closeTab(index: number | undefined): Promise<string>;
run(
tool: Tool,
params: Record<string, unknown> | undefined
): Promise<{ content: (ImageContent | TextContent)[] }>;
waitForTimeout(time: number): Promise<void>;
close(): Promise<void>;
};
8 changes: 7 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@
* limitations under the License.
*/

import { Context } from './context.js';
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
import type { Config } from './config.js';
import type { BrowserContext } from 'playwright';

export declare function createConnection(config?: Config, contextGetter?: () => Promise<BrowserContext>): Promise<Server>;
export interface Connection {
server: Server;
context: Context;
}

export declare function createConnection(config?: Config, contextGetter?: () => Promise<BrowserContext>): Promise<Connection>;
export {};
Loading