Skip to content

Commit 7912ca4

Browse files
wolfibbrowser-automation-botOrKoNbcfmtolgahan
authored
chore: Make in-page tools work with pageId routing (#1781)
This moves the stored `ToolGroup` from `McpContext` to `McpPage`, where per-page state should be stored in order for pageId-based routing to work correctly. When appending the list of in-page tools to a response, the list now corresponds to the response's `McpPage`, and only falls back to the selected `McpPage` for tools which are not page-specific. --------- Co-authored-by: browser-automation-bot <133232582+browser-automation-bot@users.noreply.github.com> Co-authored-by: Alex Rudenko <alexrudenko@chromium.org> Co-authored-by: Tolgahan Demirbaş <49946947+bcfmtolgahan@users.noreply.github.com>
1 parent c7c8f50 commit 7912ca4

6 files changed

Lines changed: 19 additions & 17 deletions

File tree

src/McpContext.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import type {
3131
} from './third_party/index.js';
3232
import {Locator} from './third_party/index.js';
3333
import {PredefinedNetworkConditions} from './third_party/index.js';
34-
import type {ToolGroup, ToolDefinition} from './tools/inPage.js';
3534
import {listPages} from './tools/pages.js';
3635
import {CLOSE_PAGE_ERROR} from './tools/ToolDefinition.js';
3736
import type {Context, DevToolsData} from './tools/ToolDefinition.js';
@@ -85,7 +84,6 @@ export class McpContext implements Context {
8584
#screenRecorderData: {recorder: ScreenRecorder; filePath: string} | null =
8685
null;
8786

88-
#inPageTools?: ToolGroup<ToolDefinition>;
8987
#nextPageId = 1;
9088
#extensionPages = new WeakMap<Target, Page>();
9189

@@ -449,14 +447,6 @@ export class McpContext implements Context {
449447
this.#updateSelectedPageTimeouts();
450448
}
451449

452-
setInPageTools(toolGroup?: ToolGroup<ToolDefinition>) {
453-
this.#inPageTools = toolGroup;
454-
}
455-
456-
getInPageTools(): ToolGroup<ToolDefinition> | undefined {
457-
return this.#inPageTools;
458-
}
459-
460450
#updateSelectedPageTimeouts() {
461451
const page = this.#getSelectedMcpPage();
462452
// For waiters 5sec timeout should be sufficient.

src/McpPage.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
Page,
1111
Viewport,
1212
} from './third_party/index.js';
13+
import type {ToolGroup, ToolDefinition} from './tools/inPage.js';
1314
import {takeSnapshot} from './tools/snapshot.js';
1415
import type {ContextPage} from './tools/ToolDefinition.js';
1516
import type {
@@ -50,6 +51,8 @@ export class McpPage implements ContextPage {
5051
#dialog?: Dialog;
5152
#dialogHandler: (dialog: Dialog) => void;
5253

54+
inPageTools: ToolGroup<ToolDefinition> | undefined;
55+
5356
constructor(page: Page, id: number) {
5457
this.pptrPage = page;
5558
this.id = id;
@@ -71,6 +74,10 @@ export class McpPage implements ContextPage {
7174
this.#dialog = undefined;
7275
}
7376

77+
getInPageTools(): ToolGroup<ToolDefinition> | undefined {
78+
return this.inPageTools;
79+
}
80+
7481
get networkConditions(): string | null {
7582
return this.emulationSettings.networkConditions ?? null;
7683
}

src/McpResponse.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,9 @@ export class McpResponse implements Response {
421421

422422
let inPageTools: ToolGroup<ToolDefinition> | undefined;
423423
if (this.#listInPageTools) {
424-
inPageTools = await getToolGroup(context.getSelectedMcpPage());
425-
context.setInPageTools(inPageTools);
424+
const page = this.#page ?? context.getSelectedMcpPage();
425+
inPageTools = await getToolGroup(page);
426+
page.inPageTools = inPageTools;
426427
}
427428

428429
let consoleMessages: Array<ConsoleFormatter | IssueFormatter> | undefined;

src/tools/ToolDefinition.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,6 @@ export type Context = Readonly<{
194194
triggerExtensionAction(id: string): Promise<void>;
195195
listExtensions(): InstalledExtension[];
196196
getExtension(id: string): InstalledExtension | undefined;
197-
getInPageTools(): ToolGroup<InPageToolDefinition> | undefined;
198197
getSelectedMcpPage(): McpPage;
199198
getExtensionServiceWorkers(): ExtensionServiceWorker[];
200199
getExtensionServiceWorkerId(
@@ -213,6 +212,7 @@ export type ContextPage = Readonly<{
213212
action: () => Promise<unknown>,
214213
options?: {timeout?: number},
215214
): Promise<void>;
215+
getInPageTools(): ToolGroup<InPageToolDefinition> | undefined;
216216
}>;
217217

218218
export function defineTool<Schema extends zod.ZodRawShape>(

src/tools/inPage.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ export const executeInPageTool = definePageTool({
7070
.optional()
7171
.describe('The JSON-stringified parameters to pass to the tool'),
7272
},
73-
handler: async (request, response, context) => {
74-
const page = request.page;
73+
handler: async (request, response) => {
7574
const toolName = request.params.toolName;
7675
let params: Record<string, unknown> = {};
7776
if (request.params.params) {
@@ -88,7 +87,7 @@ export const executeInPageTool = definePageTool({
8887
}
8988
}
9089

91-
const toolGroup = context.getInPageTools();
90+
const toolGroup = request.page.getInPageTools();
9291
const tool = toolGroup?.tools.find(t => t.name === toolName);
9392
if (!tool) {
9493
throw new Error(`Tool ${toolName} not found`);
@@ -102,7 +101,7 @@ export const executeInPageTool = definePageTool({
102101
);
103102
}
104103

105-
const result = await page.pptrPage.evaluate(
104+
const result = await request.page.pptrPage.evaluate(
106105
async (name, args) => {
107106
if (!window.__dtmcp?.executeTool) {
108107
throw new Error('No tools found on the page');

tests/tools/inPage.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ describe('inPage', () => {
2020
await withMcpContext(
2121
async (response, context) => {
2222
const page = await context.newPage();
23+
response.setPage(page);
2324

2425
await page.pptrPage.evaluate(() => {
2526
window.__dtmcp = {
@@ -76,6 +77,7 @@ describe('inPage', () => {
7677
await withMcpContext(
7778
async (response, context) => {
7879
const page = await context.newPage();
80+
response.setPage(page);
7981
await page.pptrPage.evaluate(() => {
8082
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
8183
// @ts-expect-error Event has `respondWith`
@@ -105,6 +107,7 @@ describe('inPage', () => {
105107
await withMcpContext(
106108
async (response, context) => {
107109
const page = await context.newPage();
110+
response.setPage(page);
108111
await page.pptrPage.evaluate(() => {
109112
window.addEventListener('devtoolstooldiscovery', () => {
110113
// do nothing
@@ -133,6 +136,7 @@ describe('inPage', () => {
133136
await withMcpContext(
134137
async (response, context) => {
135138
const page = await context.newPage();
139+
response.setPage(page);
136140
await listInPageTools.handler({params: {}, page}, response, context);
137141

138142
const result = await response.handle('list_in_page_tools', context);
@@ -155,6 +159,7 @@ describe('inPage', () => {
155159
evaluateFn: () => void,
156160
) {
157161
const page = await context.newPage();
162+
response.setPage(page);
158163
await page.pptrPage.evaluate(evaluateFn);
159164
await listInPageTools.handler({params: {}, page}, response, context);
160165
await response.handle('list_in_page_tools', context);

0 commit comments

Comments
 (0)