vscode-mcp-comprehensive
Version:
Comprehensive MCP server exposing all VSCode features to AI agents with 101 tools including advanced debugging and console access
282 lines • 11.9 kB
JavaScript
import * as vscode from 'vscode';
export class TerminalTools {
constructor(server) {
this.server = server;
this.terminals = new Map();
this.registerTools();
this.setupTerminalTracking();
}
setupTerminalTracking() {
// Track terminal creation and disposal
vscode.window.onDidOpenTerminal(terminal => {
this.terminals.set(terminal.name, terminal);
});
vscode.window.onDidCloseTerminal(terminal => {
// Find and remove the terminal from our map
for (const [name, term] of this.terminals.entries()) {
if (term === terminal) {
this.terminals.delete(name);
break;
}
}
});
// Initialize with existing terminals
vscode.window.terminals.forEach(terminal => {
this.terminals.set(terminal.name, terminal);
});
}
registerTools() {
// Create terminal
this.server.registerTool('terminal_create', 'Create new terminal', {
type: 'object',
properties: {
name: { type: 'string', description: 'Terminal name' },
shellPath: { type: 'string', description: 'Shell executable path' },
shellArgs: {
type: 'array',
items: { type: 'string' },
description: 'Shell arguments'
},
cwd: { type: 'string', description: 'Working directory' },
env: {
type: 'object',
description: 'Environment variables',
additionalProperties: { type: 'string' }
},
hideFromUser: { type: 'boolean', description: 'Hide from user', default: false },
message: { type: 'string', description: 'Welcome message' },
},
}, this.createTerminal.bind(this));
// Get all terminals
this.server.registerTool('terminal_get_all', 'Get all terminals', {
type: 'object',
properties: {},
}, this.getAllTerminals.bind(this));
// Send text to terminal
this.server.registerTool('terminal_send_text', 'Send command to terminal', {
type: 'object',
properties: {
terminalName: { type: 'string', description: 'Terminal name (optional, uses active if not provided)' },
text: { type: 'string', description: 'Text to send' },
addNewLine: { type: 'boolean', description: 'Add newline after text', default: true },
},
required: ['text'],
}, this.sendText.bind(this));
// Show terminal
this.server.registerTool('terminal_show', 'Show terminal panel', {
type: 'object',
properties: {
terminalName: { type: 'string', description: 'Terminal name (optional, shows active if not provided)' },
preserveFocus: { type: 'boolean', description: 'Preserve editor focus', default: false },
},
}, this.showTerminal.bind(this));
// Hide terminal
this.server.registerTool('terminal_hide', 'Hide terminal panel', {
type: 'object',
properties: {},
}, this.hideTerminal.bind(this));
// Dispose terminal
this.server.registerTool('terminal_dispose', 'Close terminal', {
type: 'object',
properties: {
terminalName: { type: 'string', description: 'Terminal name to close' },
},
required: ['terminalName'],
}, this.disposeTerminal.bind(this));
// Get terminal info
this.server.registerTool('terminal_get_info', 'Get terminal information', {
type: 'object',
properties: {
terminalName: { type: 'string', description: 'Terminal name (optional, uses active if not provided)' },
},
}, this.getTerminalInfo.bind(this));
// Execute command and wait
this.server.registerTool('terminal_execute_command', 'Execute command and optionally wait for completion', {
type: 'object',
properties: {
command: { type: 'string', description: 'Command to execute' },
terminalName: { type: 'string', description: 'Terminal name (optional, uses active if not provided)' },
waitForCompletion: { type: 'boolean', description: 'Wait for command completion', default: false },
timeout: { type: 'number', description: 'Timeout in milliseconds for waiting', default: 30000 },
},
required: ['command'],
}, this.executeCommand.bind(this));
// Clear terminal
this.server.registerTool('terminal_clear', 'Clear terminal content', {
type: 'object',
properties: {
terminalName: { type: 'string', description: 'Terminal name (optional, uses active if not provided)' },
},
}, this.clearTerminal.bind(this));
}
getTerminal(name) {
if (name) {
return this.terminals.get(name) || vscode.window.terminals.find(t => t.name === name);
}
return vscode.window.activeTerminal;
}
async createTerminal(args) {
try {
const options = {};
if (args.name)
options.name = args.name;
if (args.shellPath)
options.shellPath = args.shellPath;
if (args.shellArgs)
options.shellArgs = args.shellArgs;
if (args.cwd)
options.cwd = args.cwd;
if (args.env)
options.env = args.env;
if (args.hideFromUser)
options.hideFromUser = args.hideFromUser;
if (args.message)
options.message = args.message;
const terminal = vscode.window.createTerminal(options);
const terminalName = terminal.name;
this.terminals.set(terminalName, terminal);
return this.server.createSuccessResponse({
name: terminalName,
processId: await terminal.processId,
}, `Terminal '${terminalName}' created`);
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
async getAllTerminals() {
try {
const terminals = await Promise.all(vscode.window.terminals.map(async (terminal) => ({
name: terminal.name,
processId: await terminal.processId,
creationOptions: terminal.creationOptions,
})));
return this.server.createSuccessResponse(terminals);
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
async sendText(args) {
try {
this.server.validateRequiredParams(args, ['text']);
const terminal = this.getTerminal(args.terminalName);
if (!terminal) {
return this.server.createErrorResponse('No terminal found');
}
terminal.sendText(args.text, args.addNewLine !== false);
return this.server.createSuccessResponse({ success: true }, `Text sent to terminal '${terminal.name}'`);
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
async showTerminal(args) {
try {
const terminal = this.getTerminal(args.terminalName);
if (!terminal) {
return this.server.createErrorResponse('No terminal found');
}
terminal.show(args.preserveFocus || false);
return this.server.createSuccessResponse({ success: true }, `Terminal '${terminal.name}' shown`);
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
async hideTerminal() {
try {
await vscode.commands.executeCommand('workbench.action.terminal.toggleTerminal');
return this.server.createSuccessResponse({ success: true }, 'Terminal panel hidden');
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
async disposeTerminal(args) {
try {
this.server.validateRequiredParams(args, ['terminalName']);
const terminal = this.getTerminal(args.terminalName);
if (!terminal) {
return this.server.createErrorResponse(`Terminal '${args.terminalName}' not found`);
}
terminal.dispose();
this.terminals.delete(args.terminalName);
return this.server.createSuccessResponse({ success: true }, `Terminal '${args.terminalName}' closed`);
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
async getTerminalInfo(args) {
try {
const terminal = this.getTerminal(args.terminalName);
if (!terminal) {
return this.server.createErrorResponse('No terminal found');
}
const terminalInfo = {
name: terminal.name,
processId: await terminal.processId,
creationOptions: terminal.creationOptions,
};
return this.server.createSuccessResponse(terminalInfo);
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
async executeCommand(args) {
try {
this.server.validateRequiredParams(args, ['command']);
const terminal = this.getTerminal(args.terminalName);
if (!terminal) {
return this.server.createErrorResponse('No terminal found');
}
terminal.sendText(args.command, true);
if (args.waitForCompletion) {
// Note: VSCode doesn't provide direct access to terminal output
// This would need to be implemented through custom shell integration
// For now, we'll simulate waiting with a timeout
await new Promise(resolve => setTimeout(resolve, Math.min(args.timeout || 30000, 1000)));
return this.server.createSuccessResponse({
success: true,
command: args.command,
waited: true,
note: 'Command executed. Note: Output capture requires custom shell integration.'
}, `Command executed in terminal '${terminal.name}'`);
}
else {
return this.server.createSuccessResponse({
success: true,
command: args.command,
waited: false
}, `Command sent to terminal '${terminal.name}'`);
}
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
async clearTerminal(args) {
try {
const terminal = this.getTerminal(args.terminalName);
if (!terminal) {
return this.server.createErrorResponse('No terminal found');
}
// Send clear command (works on most shells)
terminal.sendText('clear', true);
return this.server.createSuccessResponse({ success: true }, `Terminal '${terminal.name}' cleared`);
}
catch (error) {
return this.server.createErrorResponse(error);
}
}
dispose() {
// Dispose all tracked terminals
for (const terminal of this.terminals.values()) {
terminal.dispose();
}
this.terminals.clear();
}
}
//# sourceMappingURL=terminalTools.js.map