chore: convert console resource to tool (#193)

This commit is contained in:
Pavel Feldman 2025-04-15 18:01:59 -07:00 committed by GitHub
parent e4331313f9
commit 5c2e11017d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 66 additions and 61 deletions

View File

@ -298,6 +298,12 @@ server.connect(transport);
- Parameters:
- `key` (string): Name of the key to press or a character to generate, such as `ArrowLeft` or `a`
### Console
- **browser_console_messages**
- Description: Returns all console messages
- Parameters: None
### Files and Media
- **browser_file_upload**

View File

@ -111,18 +111,21 @@ export class Context {
if (this._currentTab === tab)
this._currentTab = this._tabs[Math.min(index, this._tabs.length - 1)];
const browser = this._browser;
if (this._browserContext && !this._tabs.length) {
void this._browserContext.close().then(() => browser?.close()).catch(() => {});
this._browser = undefined;
this._browserContext = undefined;
}
if (this._browserContext && !this._tabs.length)
void this.close();
}
async close() {
if (!this._browserContext)
return;
await this._browserContext.close();
const browserContext = this._browserContext;
const browser = this._browser;
this._browserContext = undefined;
this._browser = undefined;
await browserContext?.close().then(async () => {
await browser?.close();
}).catch(() => {});
}
private async _ensureBrowserContext() {

View File

@ -20,6 +20,7 @@ import fs from 'fs';
import { createServerWithTools } from './server';
import common from './tools/common';
import console from './tools/console';
import files from './tools/files';
import install from './tools/install';
import keyboard from './tools/keyboard';
@ -28,15 +29,14 @@ import pdf from './tools/pdf';
import snapshot from './tools/snapshot';
import tabs from './tools/tabs';
import screen from './tools/screen';
import { console as consoleResource } from './resources/console';
import type { Tool, ToolCapability } from './tools/tool';
import type { Resource } from './resources/resource';
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
import type { LaunchOptions } from 'playwright';
const snapshotTools: Tool[] = [
...common(true),
...console,
...files(true),
...install,
...keyboard(true),
@ -48,6 +48,7 @@ const snapshotTools: Tool[] = [
const screenshotTools: Tool[] = [
...common(false),
...console,
...files(false),
...install,
...keyboard(false),
@ -57,10 +58,6 @@ const screenshotTools: Tool[] = [
...tabs(false),
];
const resources: Resource[] = [
consoleResource,
];
type Options = {
browser?: string;
userDataDir?: string;
@ -115,7 +112,7 @@ export async function createServer(options?: Options): Promise<Server> {
name: 'Playwright',
version: packageJSON.version,
tools,
resources,
resources: [],
browserName,
userDataDir,
launchOptions,

View File

@ -14,22 +14,32 @@
* limitations under the License.
*/
import type { Resource } from './resource';
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
export const console: Resource = {
import type { Tool } from './tool';
const consoleSchema = z.object({});
const console: Tool = {
capability: 'core',
schema: {
uri: 'browser://console',
name: 'Page console',
mimeType: 'text/plain',
name: 'browser_console_messages',
description: 'Returns all console messages',
inputSchema: zodToJsonSchema(consoleSchema),
},
read: async (context, uri) => {
handle: async context => {
const messages = await context.currentTab().console();
const log = messages.map(message => `[${message.type().toUpperCase()}] ${message.text()}`).join('\n');
return [{
uri,
mimeType: 'text/plain',
text: log
}];
return {
content: [{
type: 'text',
text: log
}],
};
},
};
export default [
console,
];

View File

@ -211,14 +211,10 @@ test('browser_type', async ({ client }) => {
submit: true,
},
});
const resource = await client.readResource({
uri: 'browser://console',
});
expect(resource.contents).toEqual([{
uri: 'browser://console',
mimeType: 'text/plain',
text: '[LOG] Key pressed: Enter , Text: Hi!',
}]);
expect(await client.callTool({
name: 'browser_console_messages',
arguments: {},
})).toHaveTextContent('[LOG] Key pressed: Enter , Text: Hi!');
});
test('browser_type (slowly)', async ({ client }) => {
@ -238,19 +234,15 @@ test('browser_type (slowly)', async ({ client }) => {
slowly: true,
},
});
const resource = await client.readResource({
uri: 'browser://console',
});
expect(resource.contents).toEqual([{
uri: 'browser://console',
mimeType: 'text/plain',
text: [
'[LOG] Key pressed: H Text: ',
'[LOG] Key pressed: i Text: H',
'[LOG] Key pressed: ! Text: Hi',
'[LOG] Key pressed: Enter Text: Hi!',
].join('\n'),
}]);
expect(await client.callTool({
name: 'browser_console_messages',
arguments: {},
})).toHaveTextContent([
'[LOG] Key pressed: H Text: ',
'[LOG] Key pressed: i Text: H',
'[LOG] Key pressed: ! Text: Hi',
'[LOG] Key pressed: Enter Text: Hi!',
].join('\n'));
});
test('browser_resize', async ({ client }) => {

View File

@ -20,6 +20,7 @@ test('test snapshot tool list', async ({ client }) => {
const { tools } = await client.listTools();
expect(new Set(tools.map(t => t.name))).toEqual(new Set([
'browser_click',
'browser_console_messages',
'browser_drag',
'browser_file_upload',
'browser_hover',
@ -47,6 +48,7 @@ test('test vision tool list', async ({ visionClient }) => {
const { tools: visionTools } = await visionClient.listTools();
expect(new Set(visionTools.map(t => t.name))).toEqual(new Set([
'browser_close',
'browser_console_messages',
'browser_file_upload',
'browser_install',
'browser_navigate_back',
@ -70,12 +72,7 @@ test('test vision tool list', async ({ visionClient }) => {
test('test resources list', async ({ client }) => {
const { resources } = await client.listResources();
expect(resources).toEqual([
expect.objectContaining({
uri: 'browser://console',
mimeType: 'text/plain',
}),
]);
expect(resources).toEqual([]);
});
test('test capabilities', async ({ startClient }) => {

View File

@ -16,7 +16,7 @@
import { test, expect } from './fixtures';
test('browser://console', async ({ client }) => {
test('browser_console_messages', async ({ client }) => {
await client.callTool({
name: 'browser_navigate',
arguments: {
@ -24,12 +24,12 @@ test('browser://console', async ({ client }) => {
},
});
const resource = await client.readResource({
uri: 'browser://console',
const resource = await client.callTool({
name: 'browser_console_messages',
arguments: {},
});
expect(resource.contents).toEqual([{
uri: 'browser://console',
mimeType: 'text/plain',
text: '[LOG] Hello, world!\n[ERROR] Error',
}]);
expect(resource).toHaveTextContent([
'[LOG] Hello, world!',
'[ERROR] Error',
].join('\n'));
});