mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-11-04 15:00:11 +00:00
feat: support verbose snapshots (#388)
As an option allow verbose snapshots https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/363 --------- Co-authored-by: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com>
This commit is contained in:
1 parent
579819b5e7
commit
d47aaa96ff
7 files changed
+62
-17
No files matched your search
@@ -320,9 +320,11 @@ so returned values have to JSON-serializable.
|
||||
|
||||
### `take_snapshot`
|
||||
|
||||
**Description:** Take a text snapshot of the currently selected page. The snapshot lists page elements along with a unique
|
||||
**Description:** Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique
|
||||
identifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot.
|
||||
|
||||
**Parameters:** None
|
||||
**Parameters:**
|
||||
|
||||
- **verbose** (boolean) _(optional)_: Whether to include all possible information available in the full a11y tree. Default is false.
|
||||
|
||||
---
|
||||
+2
-1
@@ -304,10 +304,11 @@ export class McpContext implements Context {
|
||||
/**
|
||||
* Creates a text snapshot of a page.
|
||||
*/
|
||||
async createTextSnapshot(): Promise<void> {
|
||||
async createTextSnapshot(verbose = false): Promise<void> {
|
||||
const page = this.getSelectedPage();
|
||||
const rootNode = await page.accessibility.snapshot({
|
||||
includeIframes: true,
|
||||
interestingOnly: !verbose,
|
||||
});
|
||||
if (!rootNode) {
|
||||
return;
|
||||
|
||||
+8
-2
@@ -32,6 +32,7 @@ interface NetworkRequestData {
|
||||
export class McpResponse implements Response {
|
||||
#includePages = false;
|
||||
#includeSnapshot = false;
|
||||
#includeVerboseSnapshot = false;
|
||||
#attachedNetworkRequestData?: NetworkRequestData;
|
||||
#includeConsoleData = false;
|
||||
#textResponseLines: string[] = [];
|
||||
@@ -47,8 +48,9 @@ export class McpResponse implements Response {
|
||||
this.#includePages = value;
|
||||
}
|
||||
|
||||
setIncludeSnapshot(value: boolean): void {
|
||||
setIncludeSnapshot(value: boolean, verbose = false): void {
|
||||
this.#includeSnapshot = value;
|
||||
this.#includeVerboseSnapshot = verbose;
|
||||
}
|
||||
|
||||
setIncludeNetworkRequests(
|
||||
@@ -125,6 +127,10 @@ export class McpResponse implements Response {
|
||||
return this.#includeSnapshot;
|
||||
}
|
||||
|
||||
get includeVersboseSnapshot(): boolean {
|
||||
return this.#includeVerboseSnapshot;
|
||||
}
|
||||
|
||||
async handle(
|
||||
toolName: string,
|
||||
context: McpContext,
|
||||
@@ -133,7 +139,7 @@ export class McpResponse implements Response {
|
||||
await context.createPagesSnapshot();
|
||||
}
|
||||
if (this.#includeSnapshot) {
|
||||
await context.createTextSnapshot();
|
||||
await context.createTextSnapshot(this.#includeVerboseSnapshot);
|
||||
}
|
||||
|
||||
let formattedConsoleMessages: string[];
|
||||
|
||||
@@ -22,11 +22,18 @@ export function formatA11ySnapshot(
|
||||
}
|
||||
|
||||
function getAttributes(serializedAXNodeRoot: TextSnapshotNode): string[] {
|
||||
const attributes = [
|
||||
`uid=${serializedAXNodeRoot.id}`,
|
||||
serializedAXNodeRoot.role,
|
||||
`"${serializedAXNodeRoot.name || ''}"`, // Corrected: Added quotes around name
|
||||
];
|
||||
const attributes = [`uid=${serializedAXNodeRoot.id}`];
|
||||
if (serializedAXNodeRoot.role) {
|
||||
// To match representation in DevTools.
|
||||
attributes.push(
|
||||
serializedAXNodeRoot.role === 'none'
|
||||
? 'ignored'
|
||||
: serializedAXNodeRoot.role,
|
||||
);
|
||||
}
|
||||
if (serializedAXNodeRoot.name) {
|
||||
attributes.push(`"${serializedAXNodeRoot.name}"`);
|
||||
}
|
||||
|
||||
const excluded = new Set(['id', 'role', 'name', 'elementHandle', 'children']);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export interface Response {
|
||||
options?: {pageSize?: number; pageIdx?: number; resourceTypes?: string[]},
|
||||
): void;
|
||||
setIncludeConsoleData(value: boolean): void;
|
||||
setIncludeSnapshot(value: boolean): void;
|
||||
setIncludeSnapshot(value: boolean, verbose?: boolean): void;
|
||||
attachImage(value: ImageContentData): void;
|
||||
attachNetworkRequest(reqid: number): void;
|
||||
}
|
||||
|
||||
+11
-4
@@ -12,15 +12,22 @@ import {defineTool, timeoutSchema} from './ToolDefinition.js';
|
||||
|
||||
export const takeSnapshot = defineTool({
|
||||
name: 'take_snapshot',
|
||||
description: `Take a text snapshot of the currently selected page. The snapshot lists page elements along with a unique
|
||||
description: `Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique
|
||||
identifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot.`,
|
||||
annotations: {
|
||||
category: ToolCategories.DEBUGGING,
|
||||
readOnlyHint: true,
|
||||
},
|
||||
schema: {},
|
||||
handler: async (_request, response) => {
|
||||
response.setIncludeSnapshot(true);
|
||||
schema: {
|
||||
verbose: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe(
|
||||
'Whether to include all possible information available in the full a11y tree. Default is false.',
|
||||
),
|
||||
},
|
||||
handler: async (request, response) => {
|
||||
response.setIncludeSnapshot(true, request.params.verbose ?? false);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -61,9 +61,9 @@ Testing 2`,
|
||||
result[0].text,
|
||||
`# test response
|
||||
## Page content
|
||||
uid=1_0 RootWebArea ""
|
||||
uid=1_0 RootWebArea
|
||||
uid=1_1 button "Click me" focusable focused
|
||||
uid=1_2 textbox "" value="Input"
|
||||
uid=1_2 textbox value="Input"
|
||||
`,
|
||||
);
|
||||
});
|
||||
@@ -95,6 +95,28 @@ uid=1_0 RootWebArea "My test page"
|
||||
});
|
||||
});
|
||||
|
||||
it('returns verbose snapshot', async () => {
|
||||
await withBrowser(async (response, context) => {
|
||||
const page = context.getSelectedPage();
|
||||
await page.setContent(html`<aside>test</aside>`);
|
||||
response.setIncludeSnapshot(true, true);
|
||||
const result = await response.handle('test', context);
|
||||
assert.equal(result[0].type, 'text');
|
||||
assert.strictEqual(
|
||||
result[0].text,
|
||||
`# test response
|
||||
## Page content
|
||||
uid=1_0 RootWebArea "My test page"
|
||||
uid=1_1 ignored
|
||||
uid=1_2 ignored
|
||||
uid=1_3 complementary
|
||||
uid=1_4 StaticText "test"
|
||||
uid=1_5 InlineTextBox "test"
|
||||
`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('adds throttling setting when it is not null', async () => {
|
||||
await withBrowser(async (response, context) => {
|
||||
context.setNetworkConditions('Slow 3G');
|
||||
|
||||
Reference in new issue
Block a user