Skip to content
Merged
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
8 changes: 8 additions & 0 deletions src/McpPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ export class McpPage implements ContextPage {
this.#dialog = undefined;
}

throwIfDialogOpen(): void {
if (this.#dialog) {
throw new Error(
`A dialog is open (${this.#dialog.type()}: ${this.#dialog.message()}).`,
Comment thread
samiyac marked this conversation as resolved.
);
}
}

getInPageTools(): ToolGroup<ToolDefinition> | undefined {
return this.inPageTools;
}
Expand Down
17 changes: 10 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,17 @@ export async function createMcpServer(

response.setRedactNetworkHeaders(serverArgs.redactNetworkHeaders);
try {
const page =
serverArgs.experimentalPageIdRouting &&
params.pageId &&
!serverArgs.slim
? context.getPageById(params.pageId)
: context.getSelectedMcpPage();
response.setPage(page);
if (tool.blockedByDialog) {
Comment thread
samiyac marked this conversation as resolved.
page.throwIfDialogOpen();
}
if ('pageScoped' in tool && tool.pageScoped) {
const page =
serverArgs.experimentalPageIdRouting &&
params.pageId &&
!serverArgs.slim
? context.getPageById(params.pageId)
: context.getSelectedMcpPage();
response.setPage(page);
await tool.handler(
{
params,
Expand Down
2 changes: 2 additions & 0 deletions src/tools/ToolDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface BaseToolDefinition<
conditions?: string[];
};
schema: Schema;
blockedByDialog: boolean;
}

export interface ToolDefinition<
Expand Down Expand Up @@ -255,6 +256,7 @@ export type ContextPage = Readonly<{

getDialog(): Dialog | undefined;
clearDialog(): void;
throwIfDialogOpen(): void;
waitForEventsAfterAction(
action: () => Promise<unknown>,
options?: {timeout?: number; handleDialog?: 'accept' | 'dismiss' | string},
Expand Down
2 changes: 2 additions & 0 deletions src/tools/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const listConsoleMessages = definePageTool(cliArgs => {
'Set to true to return the preserved messages over the last 3 navigations.',
),
},
blockedByDialog: false,
handler: async (request, response) => {
response.setIncludeConsoleData(true, {
pageSize: request.params.pageSize,
Expand All @@ -103,6 +104,7 @@ export const getConsoleMessage = definePageTool({
'The msgid of a console message on the page from the listed console messages',
),
},
blockedByDialog: false,
handler: async (request, response) => {
response.attachConsoleMessage(request.params.msgid);
},
Expand Down
1 change: 1 addition & 0 deletions src/tools/emulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const emulate = definePageTool({
`Emulate device viewports '<width>x<height>x<devicePixelRatio>[,mobile][,touch][,landscape]'. 'touch' and 'mobile' to emulate mobile devices. 'landscape' to emulate landscape mode.`,
),
},
blockedByDialog: true,
handler: async (request, _response, context) => {
const page = request.page;
await context.emulate(request.params, page.pptrPage);
Expand Down
5 changes: 5 additions & 0 deletions src/tools/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const installExtension = defineTool({
.string()
.describe('Absolute path to the unpacked extension folder.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
const {path} = request.params;
const id = await context.installExtension(path);
Expand All @@ -38,6 +39,7 @@ export const uninstallExtension = defineTool({
schema: {
id: zod.string().describe('ID of the extension to uninstall.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
const {id} = request.params;
await context.uninstallExtension(id);
Expand All @@ -54,6 +56,7 @@ export const listExtensions = defineTool({
readOnlyHint: true,
},
schema: {},
blockedByDialog: false,
handler: async (_request, response, _context) => {
response.setListExtensions();
},
Expand All @@ -69,6 +72,7 @@ export const reloadExtension = defineTool({
schema: {
id: zod.string().describe('ID of the extension to reload.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
const {id} = request.params;
const extension = await context.getExtension(id);
Expand All @@ -90,6 +94,7 @@ export const triggerExtensionAction = defineTool({
schema: {
id: zod.string().describe('ID of the extension to trigger the action for.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
const {id} = request.params;
await context.triggerExtensionAction(id);
Expand Down
2 changes: 2 additions & 0 deletions src/tools/inPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const listInPageTools = definePageTool({
conditions: ['inPageTools'],
},
schema: {},
blockedByDialog: false,
handler: async (_request, response, _context) => {
response.setListInPageTools();
},
Expand All @@ -71,6 +72,7 @@ export const executeInPageTool = definePageTool({
.optional()
.describe('The JSON-stringified parameters to pass to the tool'),
},
blockedByDialog: false,
handler: async (request, response) => {
const toolName = request.params.toolName;
let params: Record<string, unknown> = {};
Expand Down
9 changes: 9 additions & 0 deletions src/tools/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const click = definePageTool({
dblClick: dblClickSchema,
includeSnapshot: includeSnapshotSchema,
},
blockedByDialog: true,
handler: async (request, response) => {
const uid = request.params.uid;
const handle = await request.page.getElementByUid(uid);
Expand Down Expand Up @@ -97,6 +98,7 @@ export const clickAt = definePageTool({
dblClick: dblClickSchema,
includeSnapshot: includeSnapshotSchema,
},
blockedByDialog: true,
handler: async (request, response) => {
const page = request.page;
await page.waitForEventsAfterAction(async () => {
Expand Down Expand Up @@ -130,6 +132,7 @@ export const hover = definePageTool({
),
includeSnapshot: includeSnapshotSchema,
},
blockedByDialog: true,
handler: async (request, response) => {
const uid = request.params.uid;
const handle = await request.page.getElementByUid(uid);
Expand Down Expand Up @@ -233,6 +236,7 @@ export const fill = definePageTool({
value: zod.string().describe('The value to fill in'),
includeSnapshot: includeSnapshotSchema,
},
blockedByDialog: true,
handler: async (request, response, context) => {
const page = request.page;
await page.waitForEventsAfterAction(async () => {
Expand Down Expand Up @@ -261,6 +265,7 @@ export const typeText = definePageTool({
text: zod.string().describe('The text to type'),
submitKey: submitKeySchema,
},
blockedByDialog: true,
handler: async (request, response) => {
const page = request.page;
await page.waitForEventsAfterAction(async () => {
Expand Down Expand Up @@ -289,6 +294,7 @@ export const drag = definePageTool({
to_uid: zod.string().describe('The uid of the element to drop into'),
includeSnapshot: includeSnapshotSchema,
},
blockedByDialog: true,
handler: async (request, response) => {
const fromHandle = await request.page.getElementByUid(
request.params.from_uid,
Expand Down Expand Up @@ -330,6 +336,7 @@ export const fillForm = definePageTool({
.describe('Elements from snapshot to fill out.'),
includeSnapshot: includeSnapshotSchema,
},
blockedByDialog: true,
handler: async (request, response, context) => {
const page = request.page;
for (const element of request.params.elements) {
Expand Down Expand Up @@ -365,6 +372,7 @@ export const uploadFile = definePageTool({
filePath: zod.string().describe('The local path of the file to upload'),
includeSnapshot: includeSnapshotSchema,
},
blockedByDialog: true,
handler: async (request, response, context) => {
const {uid, filePath} = request.params;
context.validatePath(filePath);
Expand Down Expand Up @@ -415,6 +423,7 @@ export const pressKey = definePageTool({
),
includeSnapshot: includeSnapshotSchema,
},
blockedByDialog: true,
handler: async (request, response) => {
const page = request.page;
const tokens = parseKey(request.params.key);
Expand Down
1 change: 1 addition & 0 deletions src/tools/lighthouse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const lighthouseAudit = definePageTool({
.optional()
.describe('Directory for reports. If omitted, uses temporary files.'),
},
blockedByDialog: true,
handler: async (request, response, context) => {
const page = request.page;
const categories = ['accessibility', 'seo', 'best-practices'];
Expand Down
4 changes: 4 additions & 0 deletions src/tools/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const takeMemorySnapshot = definePageTool({
.string()
.describe('A path to a .heapsnapshot file to save the heapsnapshot to.'),
},
blockedByDialog: true,
handler: async (request, response, context) => {
const page = request.page;
context.validatePath(request.params.filePath);
Expand All @@ -48,6 +49,7 @@ export const exploreMemorySnapshot = defineTool({
schema: {
filePath: zod.string().describe('A path to a .heapsnapshot file to read.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
context.validatePath(request.params.filePath);
const stats = await context.getHeapSnapshotStats(request.params.filePath);
Expand Down Expand Up @@ -79,6 +81,7 @@ export const getMemorySnapshotDetails = defineTool({
.optional()
.describe('The page size for pagination of aggregates.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
context.validatePath(request.params.filePath);
const aggregates = await context.getHeapSnapshotAggregates(
Expand Down Expand Up @@ -111,6 +114,7 @@ export const getNodesByClass = defineTool({
pageIdx: zod.number().optional().describe('The page index for pagination.'),
pageSize: zod.number().optional().describe('The page size for pagination.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
context.validatePath(request.params.filePath);
const nodes = await context.getHeapSnapshotNodesByUid(
Expand Down
2 changes: 2 additions & 0 deletions src/tools/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const listNetworkRequests = definePageTool({
'Set to true to return the preserved requests over the last 3 navigations.',
),
},
blockedByDialog: false,
handler: async (request, response, context) => {
const data = await request.page.getDevToolsData();
response.attachDevToolsData(data);
Expand Down Expand Up @@ -113,6 +114,7 @@ export const getNetworkRequest = definePageTool({
'The absolute or relative path to a .network-response file to save the response body to. If omitted, the body is returned inline.',
),
},
blockedByDialog: true,
handler: async (request, response, context) => {
context.validatePath(request.params.requestFilePath);
context.validatePath(request.params.responseFilePath);
Expand Down
8 changes: 8 additions & 0 deletions src/tools/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const listPages = defineTool(args => {
readOnlyHint: true,
},
schema: {},
blockedByDialog: false,
handler: async (_request, response) => {
response.setIncludePages(true);
response.setListInPageTools();
Expand All @@ -110,6 +111,7 @@ export const selectPage = defineTool({
.optional()
.describe('Whether to focus the page and bring it to the top.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
const page = context.getPageById(request.params.pageId);
context.selectPage(page);
Expand All @@ -134,6 +136,7 @@ export const closePage = defineTool({
.number()
.describe('The ID of the page to close. Call list_pages to list pages.'),
},
blockedByDialog: false,
handler: async (request, response, context) => {
try {
await context.closePage(request.params.pageId);
Expand Down Expand Up @@ -185,6 +188,7 @@ export const newPage = defineTool(args => {
: {}),
...timeoutSchema,
},
blockedByDialog: false,
handler: async (request, response, context) => {
const page = await context.newPage(
request.params.background,
Expand Down Expand Up @@ -251,6 +255,7 @@ export const navigatePage = definePageTool(args => {
: {}),
...timeoutSchema,
},
blockedByDialog: false,
handler: async (request, response) => {
const page = request.page;
const options = {
Expand Down Expand Up @@ -385,6 +390,7 @@ export const resizePage = definePageTool({
width: zod.number().describe('Page width'),
height: zod.number().describe('Page height'),
},
blockedByDialog: false,
handler: async (request, response, _context) => {
const page = request.page;

Expand Down Expand Up @@ -429,6 +435,7 @@ export const handleDialog = definePageTool({
.optional()
.describe('Optional prompt text to enter into the dialog.'),
},
blockedByDialog: false,
handler: async (request, response, _context) => {
const page = request.page;
const dialog = page.getDialog();
Expand Down Expand Up @@ -479,6 +486,7 @@ export const getTabId = definePageTool({
`The ID of the page to get the tab ID for. Call ${listPages().name} to get available pages.`,
),
},
blockedByDialog: false,
handler: async (request, response, context) => {
const page = context.getPageById(request.params.pageId);
const tabId = (page.pptrPage as unknown as CdpPage)._tabId;
Expand Down
3 changes: 3 additions & 0 deletions src/tools/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const startTrace = definePageTool({
),
filePath: filePathSchema,
},
blockedByDialog: true,
handler: async (request, response, context) => {
context.validatePath(request.params.filePath);
if (context.isRunningPerformanceTrace()) {
Expand Down Expand Up @@ -126,6 +127,7 @@ export const stopTrace = definePageTool({
schema: {
filePath: filePathSchema,
},
blockedByDialog: true,
handler: async (request, response, context) => {
context.validatePath(request.params.filePath);
if (!context.isRunningPerformanceTrace()) {
Expand Down Expand Up @@ -161,6 +163,7 @@ export const analyzeInsight = definePageTool({
'The name of the Insight you want more information on. For example: "DocumentLatency" or "LCPBreakdown"',
),
},
blockedByDialog: false,
handler: async (request, response, context) => {
const lastRecording = context.recordedTraces().at(-1);
if (!lastRecording) {
Expand Down
3 changes: 2 additions & 1 deletion src/tools/screencast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export const startScreencast = definePageTool(args => ({
annotations: {
category: ToolCategory.DEBUGGING,
readOnlyHint: false,

conditions: ['screencast'],
},
schema: {
Expand All @@ -39,6 +38,7 @@ export const startScreencast = definePageTool(args => ({
`Output file path (${supportedExtensions.join(',')} are supported). Uses mkdtemp to generate a unique path if not provided.`,
),
},
blockedByDialog: false,
handler: async (request, response, context) => {
context.validatePath(request.params.filePath);
if (context.getScreenRecorder() !== null) {
Expand Down Expand Up @@ -102,6 +102,7 @@ export const stopScreencast = definePageTool({
conditions: ['screencast'],
},
schema: {},
blockedByDialog: false,
handler: async (_request, response, context) => {
const data = context.getScreenRecorder();
if (!data) {
Expand Down
1 change: 1 addition & 0 deletions src/tools/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const screenshot = definePageTool({
'The absolute path, or a path relative to the current working directory, to save the screenshot to instead of attaching it to the response.',
),
},
blockedByDialog: true,
handler: async (request, response, context) => {
context.validatePath(request.params.filePath);
if (request.params.uid && request.params.fullPage) {
Expand Down
1 change: 1 addition & 0 deletions src/tools/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Example with arguments: \`(el) => {
}
: {}),
},
blockedByDialog: true,
handler: async (request, response, context) => {
const {
serviceWorkerId,
Expand Down
Loading
Loading