chore: merge tabs tool into one (#933)
This commit is contained in:
35
README.md
35
README.md
@@ -627,39 +627,14 @@ http.createServer(async (req, res) => {
|
|||||||
|
|
||||||
<!-- NOTE: This has been generated via update-readme.js -->
|
<!-- NOTE: This has been generated via update-readme.js -->
|
||||||
|
|
||||||
- **browser_tab_close**
|
- **browser_tabs**
|
||||||
- Title: Close a tab
|
- Title: Manage tabs
|
||||||
- Description: Close a tab
|
- Description: List, create, close, or select a browser tab.
|
||||||
- Parameters:
|
- 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**
|
- 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>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|||||||
@@ -17,85 +17,48 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { defineTool } from './tool.js';
|
import { defineTool } from './tool.js';
|
||||||
|
|
||||||
const listTabs = defineTool({
|
const browserTabs = defineTool({
|
||||||
capability: 'core-tabs',
|
capability: 'core-tabs',
|
||||||
|
|
||||||
schema: {
|
schema: {
|
||||||
name: 'browser_tab_list',
|
name: 'browser_tabs',
|
||||||
title: 'List tabs',
|
title: 'Manage tabs',
|
||||||
description: 'List browser tabs',
|
description: 'List, create, close, or select a browser tab.',
|
||||||
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',
|
|
||||||
inputSchema: z.object({
|
inputSchema: z.object({
|
||||||
index: z.number().describe('The index of the tab to select'),
|
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: '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.'),
|
|
||||||
}),
|
}),
|
||||||
type: 'destructive',
|
type: 'destructive',
|
||||||
},
|
},
|
||||||
|
|
||||||
handle: async (context, params, response) => {
|
handle: async (context, params, response) => {
|
||||||
await context.closeTab(params.index);
|
switch (params.action) {
|
||||||
response.setIncludeSnapshot();
|
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 [
|
export default [
|
||||||
listTabs,
|
browserTabs,
|
||||||
newTab,
|
|
||||||
selectTab,
|
|
||||||
closeTab,
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -19,8 +19,14 @@ import { test, expect } from './fixtures.js';
|
|||||||
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||||
|
|
||||||
async function createTab(client: Client, title: string, body: string) {
|
async function createTab(client: Client, title: string, body: string) {
|
||||||
|
await client.callTool({
|
||||||
|
name: 'browser_tabs',
|
||||||
|
arguments: {
|
||||||
|
action: 'new',
|
||||||
|
},
|
||||||
|
});
|
||||||
return await client.callTool({
|
return await client.callTool({
|
||||||
name: 'browser_tab_new',
|
name: 'browser_navigate',
|
||||||
arguments: {
|
arguments: {
|
||||||
url: `data:text/html,<title>${title}</title><body>${body}</body>`,
|
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 }) => {
|
test('list initial tabs', async ({ client }) => {
|
||||||
expect(await client.callTool({
|
expect(await client.callTool({
|
||||||
name: 'browser_tab_list',
|
name: 'browser_tabs',
|
||||||
|
arguments: {
|
||||||
|
action: 'list',
|
||||||
|
},
|
||||||
})).toHaveResponse({
|
})).toHaveResponse({
|
||||||
tabs: `- 0: (current) [] (about:blank)`,
|
tabs: `- 0: (current) [] (about:blank)`,
|
||||||
});
|
});
|
||||||
@@ -38,7 +47,10 @@ test('list initial tabs', async ({ client }) => {
|
|||||||
test('list first tab', async ({ client }) => {
|
test('list first tab', async ({ client }) => {
|
||||||
await createTab(client, 'Tab one', 'Body one');
|
await createTab(client, 'Tab one', 'Body one');
|
||||||
expect(await client.callTool({
|
expect(await client.callTool({
|
||||||
name: 'browser_tab_list',
|
name: 'browser_tabs',
|
||||||
|
arguments: {
|
||||||
|
action: 'list',
|
||||||
|
},
|
||||||
})).toHaveResponse({
|
})).toHaveResponse({
|
||||||
tabs: `- 0: [] (about:blank)
|
tabs: `- 0: [] (about:blank)
|
||||||
- 1: (current) [Tab one] (data:text/html,<title>Tab one</title><body>Body one</body>)`,
|
- 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');
|
await createTab(client, 'Tab two', 'Body two');
|
||||||
|
|
||||||
expect(await client.callTool({
|
expect(await client.callTool({
|
||||||
name: 'browser_tab_select',
|
name: 'browser_tabs',
|
||||||
arguments: {
|
arguments: {
|
||||||
|
action: 'select',
|
||||||
index: 1,
|
index: 1,
|
||||||
},
|
},
|
||||||
})).toHaveResponse({
|
})).toHaveResponse({
|
||||||
@@ -97,8 +110,9 @@ test('close tab', async ({ client }) => {
|
|||||||
await createTab(client, 'Tab two', 'Body two');
|
await createTab(client, 'Tab two', 'Body two');
|
||||||
|
|
||||||
expect(await client.callTool({
|
expect(await client.callTool({
|
||||||
name: 'browser_tab_close',
|
name: 'browser_tabs',
|
||||||
arguments: {
|
arguments: {
|
||||||
|
action: 'close',
|
||||||
index: 2,
|
index: 2,
|
||||||
},
|
},
|
||||||
})).toHaveResponse({
|
})).toHaveResponse({
|
||||||
|
|||||||
Reference in New Issue
Block a user