Path: blob/main/test/mcp/src/automationTools/terminal.ts
3520 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';6import { ApplicationService } from '../application';7import { z } from 'zod';89/**10* Terminal Management Tools11*/12export function applyTerminalTools(server: McpServer, appService: ApplicationService): RegisteredTool[] {13const tools: RegisteredTool[] = [];14tools.push(server.tool(15'vscode_automation_terminal_create',16'Create a new terminal',17{18expectedLocation: z.enum(['editor', 'panel']).optional().describe('Expected location of terminal (editor or panel)')19},20async (args) => {21const { expectedLocation } = args;22const app = await appService.getOrCreateApplication();23await app.workbench.terminal.createTerminal(expectedLocation);24return {25content: [{26type: 'text' as const,27text: `Created new terminal${expectedLocation ? ` in ${expectedLocation}` : ''}`28}]29};30}31));3233tools.push(server.tool(34'vscode_automation_terminal_run_command',35'Run a command in the terminal',36{37command: z.string().describe('Command to run in the terminal'),38skipEnter: z.boolean().optional().describe('Skip pressing enter after typing command')39},40async (args) => {41const { command, skipEnter } = args;42const app = await appService.getOrCreateApplication();43await app.workbench.terminal.runCommandInTerminal(command, skipEnter);44return {45content: [{46type: 'text' as const,47text: `Ran command in terminal: "${command}"`48}]49};50}51));5253// Playwright can probably figure this out54// server.tool(55// 'vscode_automation_terminal_wait_for_text',56// 'Wait for specific text to appear in terminal output',57// {58// acceptFunction: z.string().describe('JavaScript function body that takes buffer array and returns boolean'),59// message: z.string().optional().describe('Optional message for waiting'),60// splitIndex: z.number().optional().describe('Split terminal index (0 or 1)')61// },62// async (args) => {63// const { acceptFunction, message, splitIndex } = args;64// // Create function from string65// const acceptFn = new Function('buffer', acceptFunction) as (buffer: string[]) => boolean;66// const terminalSplitIndex = splitIndex === 0 ? 0 : splitIndex === 1 ? 1 : undefined;67// await app.workbench.terminal.waitForTerminalText(acceptFn, message, terminalSplitIndex);68// return {69// content: [{70// type: 'text' as const,71// text: `Terminal text condition met: ${message || 'custom condition'}`72// }]73// };74// }75// );7677tools.push(server.tool(78'vscode_automation_terminal_get_groups',79'Get current terminal groups information',80async () => {81const app = await appService.getOrCreateApplication();82const groups = await app.workbench.terminal.getTerminalGroups();83return {84content: [{85type: 'text' as const,86text: `Terminal groups:\n${JSON.stringify(groups, null, 2)}`87}]88};89}90));9192// Seems too niche and redundant with runCommand tool93// server.tool(94// 'vscode_automation_terminal_run_command_by_id',95// 'Run a terminal command by ID',96// {97// commandId: z.enum([98// 'workbench.action.terminal.split',99// 'workbench.action.terminal.killAll',100// 'workbench.action.terminal.unsplit',101// 'workbench.action.terminal.join',102// 'workbench.action.terminal.toggleTerminal',103// 'workbench.action.createTerminalEditor',104// 'workbench.action.createTerminalEditorSide',105// 'workbench.action.terminal.moveToTerminalPanel',106// 'workbench.action.terminal.moveToEditor',107// 'workbench.action.terminal.newWithProfile',108// 'workbench.action.terminal.selectDefaultShell',109// 'workbench.action.terminal.detachSession',110// 'workbench.action.terminal.new'111// ]).describe('Terminal command ID to execute'),112// expectedLocation: z.enum(['editor', 'panel']).optional().describe('Expected location after command')113// },114// async (args) => {115// const { commandId, expectedLocation } = args;116// await app.workbench.terminal.runCommand(commandId as any, expectedLocation);117// return {118// content: [{119// type: 'text' as const,120// text: `Executed terminal command: ${commandId}`121// }]122// };123// }124// );125126// Playwright can probably figure this out127// server.tool(128// 'vscode_automation_terminal_split',129// 'Split the current terminal',130// async () => {131// await app.workbench.terminal.clickSplitButton();132// return {133// content: [{134// type: 'text' as const,135// text: 'Split terminal'136// }]137// };138// }139// );140141return tools;142}143144145