Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 4 additions & 2 deletions docs/tool-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---
3 changes: 2 additions & 1 deletion src/McpContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 8 additions & 2 deletions src/McpResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ interface NetworkRequestData {
export class McpResponse implements Response {
#includePages = false;
#includeSnapshot = false;
#includeVerboseSnapshot = false;
#attachedNetworkRequestData?: NetworkRequestData;
#includeConsoleData = false;
#textResponseLines: string[] = [];
Expand All @@ -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(
Expand Down Expand Up @@ -125,6 +127,10 @@ export class McpResponse implements Response {
return this.#includeSnapshot;
}

get includeVersboseSnapshot(): boolean {
return this.#includeVerboseSnapshot;
}

async handle(
toolName: string,
context: McpContext,
Expand All @@ -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[];
Expand Down
17 changes: 12 additions & 5 deletions src/formatters/snapshotFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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']);

Expand Down
2 changes: 1 addition & 1 deletion src/tools/ToolDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
15 changes: 11 additions & 4 deletions src/tools/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
});

Expand Down
26 changes: 24 additions & 2 deletions tests/McpResponse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
`,
);
});
Expand Down Expand Up @@ -95,6 +95,28 @@ uid=1_0 RootWebArea "My test page"
});
});

it.only('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');
Expand Down