chore: merge tabs tool into one (#933)

This commit is contained in:
Pavel Feldman
2025-08-22 13:46:52 -07:00
committed by GitHub
parent fb28e99fa4
commit 2521a67b2f
3 changed files with 55 additions and 103 deletions

View File

@@ -627,39 +627,14 @@ http.createServer(async (req, res) => {
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_tab_close**
- Title: Close a tab
- Description: Close a tab
- **browser_tabs**
- Title: Manage tabs
- Description: List, create, close, or select a browser tab.
- Parameters:
- `index` (number, optional): The index of the tab to close. Closes current tab if not provided.
- `action` (string): Operation to perform
- `index` (number, optional): Tab index, used for close/select. If omitted for close, current tab is closed.
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_tab_list**
- Title: List tabs
- Description: List browser tabs
- Parameters: None
- Read-only: **true**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_tab_new**
- Title: Open a new tab
- Description: Open a new tab
- Parameters:
- `url` (string, optional): The URL to navigate to in the new tab. If not provided, the new tab will be blank.
- Read-only: **true**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_tab_select**
- Title: Select a tab
- Description: Select a tab by index
- Parameters:
- `index` (number): The index of the tab to select
- Read-only: **true**
</details>
<details>

View File

@@ -17,85 +17,48 @@
import { z } from 'zod';
import { defineTool } from './tool.js';
const listTabs = defineTool({
const browserTabs = defineTool({
capability: 'core-tabs',
schema: {
name: 'browser_tab_list',
title: 'List tabs',
description: 'List browser tabs',
inputSchema: z.object({}),
type: 'readOnly',
},
handle: async (context, params, response) => {
await context.ensureTab();
response.setIncludeTabs();
},
});
const selectTab = defineTool({
capability: 'core-tabs',
schema: {
name: 'browser_tab_select',
title: 'Select a tab',
description: 'Select a tab by index',
name: 'browser_tabs',
title: 'Manage tabs',
description: 'List, create, close, or select a browser tab.',
inputSchema: z.object({
index: z.number().describe('The index of the tab to select'),
}),
type: 'readOnly',
},
handle: async (context, params, response) => {
await context.selectTab(params.index);
response.setIncludeSnapshot();
},
});
const newTab = defineTool({
capability: 'core-tabs',
schema: {
name: 'browser_tab_new',
title: 'Open a new tab',
description: 'Open a new tab',
inputSchema: z.object({
url: z.string().optional().describe('The URL to navigate to in the new tab. If not provided, the new tab will be blank.'),
}),
type: 'readOnly',
},
handle: async (context, params, response) => {
const tab = await context.newTab();
if (params.url)
await tab.navigate(params.url);
response.setIncludeSnapshot();
},
});
const closeTab = defineTool({
capability: 'core-tabs',
schema: {
name: 'browser_tab_close',
title: 'Close a tab',
description: 'Close a tab',
inputSchema: z.object({
index: z.number().optional().describe('The index of the tab to close. Closes current tab if not provided.'),
action: z.enum(['list', 'new', 'close', 'select']).describe('Operation to perform'),
index: z.number().optional().describe('Tab index, used for close/select. If omitted for close, current tab is closed.'),
}),
type: 'destructive',
},
handle: async (context, params, response) => {
await context.closeTab(params.index);
response.setIncludeSnapshot();
switch (params.action) {
case 'list': {
await context.ensureTab();
response.setIncludeTabs();
return;
}
case 'new': {
await context.newTab();
response.setIncludeTabs();
return;
}
case 'close': {
await context.closeTab(params.index);
response.setIncludeSnapshot();
return;
}
case 'select': {
if (!params.index)
throw new Error('Tab index is required');
await context.selectTab(params.index);
response.setIncludeSnapshot();
return;
}
}
},
});
export default [
listTabs,
newTab,
selectTab,
closeTab,
browserTabs,
];

View File

@@ -19,8 +19,14 @@ import { test, expect } from './fixtures.js';
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
async function createTab(client: Client, title: string, body: string) {
await client.callTool({
name: 'browser_tabs',
arguments: {
action: 'new',
},
});
return await client.callTool({
name: 'browser_tab_new',
name: 'browser_navigate',
arguments: {
url: `data:text/html,<title>${title}</title><body>${body}</body>`,
},
@@ -29,7 +35,10 @@ async function createTab(client: Client, title: string, body: string) {
test('list initial tabs', async ({ client }) => {
expect(await client.callTool({
name: 'browser_tab_list',
name: 'browser_tabs',
arguments: {
action: 'list',
},
})).toHaveResponse({
tabs: `- 0: (current) [] (about:blank)`,
});
@@ -38,7 +47,10 @@ test('list initial tabs', async ({ client }) => {
test('list first tab', async ({ client }) => {
await createTab(client, 'Tab one', 'Body one');
expect(await client.callTool({
name: 'browser_tab_list',
name: 'browser_tabs',
arguments: {
action: 'list',
},
})).toHaveResponse({
tabs: `- 0: [] (about:blank)
- 1: (current) [Tab one] (data:text/html,<title>Tab one</title><body>Body one</body>)`,
@@ -75,8 +87,9 @@ test('select tab', async ({ client }) => {
await createTab(client, 'Tab two', 'Body two');
expect(await client.callTool({
name: 'browser_tab_select',
name: 'browser_tabs',
arguments: {
action: 'select',
index: 1,
},
})).toHaveResponse({
@@ -97,8 +110,9 @@ test('close tab', async ({ client }) => {
await createTab(client, 'Tab two', 'Body two');
expect(await client.callTool({
name: 'browser_tab_close',
name: 'browser_tabs',
arguments: {
action: 'close',
index: 2,
},
})).toHaveResponse({