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
5 changes: 5 additions & 0 deletions src/tools/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const listPages = defineTool(args => {
schema: {},
handler: async (_request, response) => {
response.setIncludePages(true);
response.setListInPageTools();
},
};
});
Expand All @@ -53,6 +54,7 @@ export const selectPage = defineTool({
const page = context.getPageById(request.params.pageId);
context.selectPage(page);
response.setIncludePages(true);
response.setListInPageTools();
if (request.params.bringToFront) {
await page.pptrPage.bringToFront();
}
Expand Down Expand Up @@ -82,6 +84,7 @@ export const closePage = defineTool({
}
}
response.setIncludePages(true);
response.setListInPageTools();
},
});

Expand Down Expand Up @@ -126,6 +129,7 @@ export const newPage = defineTool({
);

response.setIncludePages(true);
response.setListInPageTools();
},
});

Expand Down Expand Up @@ -275,6 +279,7 @@ export const navigatePage = definePageTool({
}

response.setIncludePages(true);
response.setListInPageTools();
},
});

Expand Down
113 changes: 113 additions & 0 deletions tests/McpResponse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ import {describe, it} from 'node:test';
import sinon from 'sinon';

import type {ParsedArguments} from '../src/bin/chrome-devtools-mcp-cli-options.js';
import type {McpContext} from '../src/McpContext.js';
import type {McpResponse} from '../src/McpResponse.js';
import {
closePage,
listPages,
navigatePage,
newPage,
selectPage,
} from '../src/tools/pages.js';
import type {InsightName} from '../src/trace-processing/parse.js';
import {
parseRawTraceBuffer,
Expand Down Expand Up @@ -1091,4 +1100,108 @@ describe('inPage tools', () => {
{categoryInPageTools: true} as ParsedArguments,
);
});

async function testIncludesInPageTools(
handlerAction: (
response: McpResponse,
context: McpContext,
) => Promise<void>,
toolName: string,
) {
await withMcpContext(
async (response, context) => {
const mcpPage = context.getSelectedMcpPage();
stubToolDiscovery(mcpPage.pptrPage);

const initScript = `
window.__dtmcp = {
toolGroup: {
name: 'In-Page group',
description: 'Test tools',
tools: [
{
name: 'inPageTool',
description: 'A test tool',
inputSchema: {
type: 'object',
properties: {},
},
execute: () => 'result',
},
],
},
};
window.addEventListener('devtoolstooldiscovery', (e) => {
e.respondWith(window.__dtmcp?.toolGroup);
});
`;
await mcpPage.pptrPage.evaluateOnNewDocument(initScript);
await mcpPage.pptrPage.evaluate(initScript);

await handlerAction(response, context);

const {content} = await response.handle(toolName, context);
const responseText = getTextContent(content[0]);
assert.ok(
responseText.includes('inPageTool'),
`Should include in-page tool name in the ${toolName} response`,
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
);
}

it('includes in-page tools in list_pages response', async () => {
await testIncludesInPageTools(async (response, context) => {
const listPagesDef = listPages({
categoryInPageTools: true,
} as ParsedArguments);
await listPagesDef.handler({params: {}}, response, context);
}, 'list_pages');
});

it('includes in-page tools in select_page response', async () => {
await testIncludesInPageTools(async (response, context) => {
const pageId =
context.getPageId(context.getSelectedMcpPage().pptrPage) ?? 1;
await selectPage.handler({params: {pageId}}, response, context);
}, 'select_page');
});

it('includes in-page tools in close_page response', async () => {
await testIncludesInPageTools(async (response, context) => {
const pageId =
context.getPageId(context.getSelectedMcpPage().pptrPage) ?? 1;
await closePage.handler({params: {pageId}}, response, context);
}, 'close_page');
});

it('includes in-page tools in navigate_page response', async () => {
await testIncludesInPageTools(async (response, context) => {
await navigatePage.handler(
{
params: {type: 'url', url: 'about:blank'},
page: context.getSelectedMcpPage(),
},
response,
context,
);
}, 'navigate_page');
});

it('includes in-page tools in new_page response', async () => {
await testIncludesInPageTools(async (response, context) => {
// Workaround to ensure the test environment's new page contain in-page tools
sinon.stub(context, 'newPage').resolves(context.getSelectedMcpPage());

await newPage.handler(
{
params: {url: 'about:blank'},
},
response,
context,
);
}, 'new_page');
});
});
13 changes: 11 additions & 2 deletions tests/tools/inPage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import assert from 'node:assert';
import {describe, it} from 'node:test';

import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js';
import type {ToolGroup, ToolDefinition} from '../../src/tools/inPage.js';
import {listInPageTools} from '../../src/tools/inPage.js';
import {withMcpContext} from '../utils.js';

Expand Down Expand Up @@ -85,7 +86,11 @@ describe('inPage', () => {
const result = await response.handle('list_in_page_tools', context);
assert.ok('inPageTools' in result.structuredContent);
assert.deepEqual(
(result.structuredContent as {inPageTools: undefined}).inPageTools,
(
result.structuredContent as {
inPageTools: ToolGroup<ToolDefinition>;
}
).inPageTools,
{},
);
},
Expand All @@ -109,7 +114,11 @@ describe('inPage', () => {
const result = await response.handle('list_in_page_tools', context);
assert.ok('inPageTools' in result.structuredContent);
assert.strictEqual(
(result.structuredContent as {inPageTools: undefined}).inPageTools,
(
result.structuredContent as {
inPageTools: ToolGroup<ToolDefinition>;
}
).inPageTools,
undefined,
);
},
Expand Down
Loading