mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-09-14 19:45:30 +08:00
fix: do not use getSelectedMcpPage (#2039)
Drive-by: clean up formatting and arg use. Refs: https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2033
This commit is contained in:
+60
-49
@@ -100,7 +100,7 @@ export function replaceHtmlElementsWithUids(schema: JSONSchema7Definition) {
|
||||
|
||||
async function getToolGroup(
|
||||
page: McpPage,
|
||||
): Promise<ToolGroup<ToolDefinition> | undefined> {
|
||||
): Promise<ToolGroup<ToolDefinition> | undefined | null> {
|
||||
// Check if there is a `devtoolstooldiscovery` event listener
|
||||
const windowHandle = await page.pptrPage.evaluateHandle(() => window);
|
||||
// @ts-expect-error internal API
|
||||
@@ -114,39 +114,41 @@ async function getToolGroup(
|
||||
}
|
||||
|
||||
const toolGroup = await page.pptrPage.evaluate(() => {
|
||||
return new Promise<ToolGroup<ToolDefinition> | undefined>(resolve => {
|
||||
const event = new CustomEvent('devtoolstooldiscovery');
|
||||
// @ts-expect-error Adding custom property
|
||||
event.respondWith = (toolGroup: ToolGroup) => {
|
||||
if (!window.__dtmcp) {
|
||||
window.__dtmcp = {};
|
||||
}
|
||||
window.__dtmcp.toolGroup = toolGroup;
|
||||
return new Promise<ToolGroup<ToolDefinition> | undefined | null>(
|
||||
resolve => {
|
||||
const event = new CustomEvent('devtoolstooldiscovery');
|
||||
// @ts-expect-error Adding custom property
|
||||
event.respondWith = (toolGroup: ToolGroup) => {
|
||||
if (!window.__dtmcp) {
|
||||
window.__dtmcp = {};
|
||||
}
|
||||
window.__dtmcp.toolGroup = toolGroup;
|
||||
|
||||
// When receiving a toolGroup for the first time, expose a simple execution helper
|
||||
if (!window.__dtmcp.executeTool) {
|
||||
window.__dtmcp.executeTool = async (toolName, args) => {
|
||||
if (!window.__dtmcp?.toolGroup) {
|
||||
throw new Error('No tools found on the page');
|
||||
}
|
||||
const tool = window.__dtmcp.toolGroup.tools.find(
|
||||
t => t.name === toolName,
|
||||
);
|
||||
if (!tool) {
|
||||
throw new Error(`Tool ${toolName} not found`);
|
||||
}
|
||||
return await tool.execute(args);
|
||||
};
|
||||
}
|
||||
// When receiving a toolGroup for the first time, expose a simple execution helper
|
||||
if (!window.__dtmcp.executeTool) {
|
||||
window.__dtmcp.executeTool = async (toolName, args) => {
|
||||
if (!window.__dtmcp?.toolGroup) {
|
||||
throw new Error('No tools found on the page');
|
||||
}
|
||||
const tool = window.__dtmcp.toolGroup.tools.find(
|
||||
t => t.name === toolName,
|
||||
);
|
||||
if (!tool) {
|
||||
throw new Error(`Tool ${toolName} not found`);
|
||||
}
|
||||
return await tool.execute(args);
|
||||
};
|
||||
}
|
||||
|
||||
resolve(toolGroup);
|
||||
};
|
||||
window.dispatchEvent(event);
|
||||
// If the page does not synchronously call `event.respondWith`, return instead of timing out
|
||||
setTimeout(() => {
|
||||
resolve(undefined);
|
||||
}, 0);
|
||||
});
|
||||
resolve(toolGroup);
|
||||
};
|
||||
window.dispatchEvent(event);
|
||||
// If the page does not synchronously call `event.respondWith`, return instead of timing out
|
||||
setTimeout(() => {
|
||||
resolve(null);
|
||||
}, 0);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
for (const tool of toolGroup?.tools ?? []) {
|
||||
@@ -245,9 +247,7 @@ export class McpResponse implements Response {
|
||||
}
|
||||
|
||||
setListThirdPartyDeveloperTools(): void {
|
||||
if (this.#args.categoryExperimentalThirdParty) {
|
||||
this.#listThirdPartyDeveloperTools = true;
|
||||
}
|
||||
this.#listThirdPartyDeveloperTools = true;
|
||||
}
|
||||
|
||||
setListWebMcpTools(): void {
|
||||
@@ -552,17 +552,26 @@ export class McpResponse implements Response {
|
||||
extensions = await context.listExtensions();
|
||||
}
|
||||
|
||||
let thirdPartyDeveloperTools: ToolGroup<ToolDefinition> | undefined;
|
||||
if (this.#listThirdPartyDeveloperTools) {
|
||||
const page = this.#page ?? context.getSelectedMcpPage();
|
||||
thirdPartyDeveloperTools = await getToolGroup(page);
|
||||
page.thirdPartyDeveloperTools = thirdPartyDeveloperTools;
|
||||
// Null indicates no tools.
|
||||
let thirdPartyDeveloperTools: ToolGroup<ToolDefinition> | undefined | null;
|
||||
if (
|
||||
this.#args.categoryExperimentalThirdParty &&
|
||||
this.#listThirdPartyDeveloperTools &&
|
||||
this.#page
|
||||
) {
|
||||
thirdPartyDeveloperTools = await getToolGroup(this.#page);
|
||||
if (thirdPartyDeveloperTools) {
|
||||
this.#page.thirdPartyDeveloperTools = thirdPartyDeveloperTools;
|
||||
}
|
||||
}
|
||||
|
||||
let webmcpTools: WebMCPTool[] | undefined;
|
||||
if (this.#listWebMcpTools && this.#args.categoryExperimentalWebmcp) {
|
||||
const page = this.#page ?? context.getSelectedMcpPage();
|
||||
webmcpTools = page.getWebMcpTools();
|
||||
if (
|
||||
this.#args.categoryExperimentalWebmcp &&
|
||||
this.#listWebMcpTools &&
|
||||
this.#page
|
||||
) {
|
||||
webmcpTools = this.#page.getWebMcpTools();
|
||||
}
|
||||
|
||||
let consoleMessages: Array<ConsoleFormatter | IssueFormatter> | undefined;
|
||||
@@ -688,7 +697,7 @@ export class McpResponse implements Response {
|
||||
traceInsight?: TraceInsightData;
|
||||
extensions?: Map<string, Extension>;
|
||||
lighthouseResult?: LighthouseData;
|
||||
thirdPartyDeveloperTools?: ToolGroup<ToolDefinition>;
|
||||
thirdPartyDeveloperTools?: ToolGroup<ToolDefinition> | null;
|
||||
webmcpTools?: WebMCPTool[];
|
||||
errorMessage?: string;
|
||||
},
|
||||
@@ -1004,13 +1013,15 @@ Call ${handleDialog.name} to handle it before continuing.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.#listThirdPartyDeveloperTools) {
|
||||
structuredContent.thirdPartyDeveloperTools =
|
||||
data.thirdPartyDeveloperTools ?? undefined;
|
||||
if (data.thirdPartyDeveloperTools !== undefined) {
|
||||
if (data.thirdPartyDeveloperTools) {
|
||||
structuredContent.thirdPartyDeveloperTools =
|
||||
data.thirdPartyDeveloperTools;
|
||||
}
|
||||
response.push('## Third-party developer tools');
|
||||
if (
|
||||
!data.thirdPartyDeveloperTools ||
|
||||
!data.thirdPartyDeveloperTools.tools
|
||||
data.thirdPartyDeveloperTools === null ||
|
||||
!data.thirdPartyDeveloperTools?.tools
|
||||
) {
|
||||
response.push('No third-party developer tools available.');
|
||||
} else {
|
||||
|
||||
@@ -1070,15 +1070,6 @@ describe('third-party developer tools', () => {
|
||||
it('lists third-party developer tools', async t => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
response.setListThirdPartyDeveloperTools();
|
||||
const emptyResult = await response.handle('test', context);
|
||||
const emptyText = getTextContent(emptyResult.content[0]);
|
||||
assert.ok(
|
||||
emptyText.includes('No third-party developer tools available.'),
|
||||
'Should show message for empty third-party developer tools',
|
||||
);
|
||||
|
||||
response.resetResponseLineForTesting();
|
||||
const mcpPage = context.getSelectedMcpPage();
|
||||
stubToolDiscovery(mcpPage.pptrPage);
|
||||
sinon.stub(mcpPage.pptrPage, 'evaluate').resolves({
|
||||
|
||||
@@ -147,7 +147,6 @@ describe('thirdPartyDeveloperTools', () => {
|
||||
'list_3p_developer_tools',
|
||||
context,
|
||||
);
|
||||
assert.ok('thirdPartyDeveloperTools' in result.structuredContent);
|
||||
assert.strictEqual(
|
||||
(
|
||||
result.structuredContent as {
|
||||
@@ -177,7 +176,6 @@ describe('thirdPartyDeveloperTools', () => {
|
||||
'list_3p_developer_tools',
|
||||
context,
|
||||
);
|
||||
assert.ok('thirdPartyDeveloperTools' in result.structuredContent);
|
||||
assert.strictEqual(
|
||||
(result.structuredContent as {thirdPartyDeveloperTools: undefined})
|
||||
.thirdPartyDeveloperTools,
|
||||
|
||||
Reference in New Issue
Block a user