Skip to main content
Glama
shell-tools.ts5.45 kB
import * as vscode from 'vscode'; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from 'zod'; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; /** * Waits briefly for shell integration to become available * @param terminal The terminal to wait for * @param timeout Maximum time to wait in milliseconds * @returns Promise that resolves to true if shell integration became available */ async function waitForShellIntegration(terminal: vscode.Terminal, timeout = 1000): Promise<boolean> { if (terminal.shellIntegration) { return true; } return new Promise<boolean>(resolve => { const timeoutId = setTimeout(() => { disposable.dispose(); resolve(false); }, timeout); const disposable = vscode.window.onDidChangeTerminalShellIntegration(e => { if (e.terminal === terminal && terminal.shellIntegration) { clearTimeout(timeoutId); disposable.dispose(); resolve(true); } }); }); } /** * Executes a shell command using terminal shell integration * @param terminal The terminal with shell integration * @param command The command to execute * @param cwd Optional working directory for the command * @param timeout Command timeout in milliseconds (default: 10000) * @returns Promise that resolves with the command output */ export async function executeShellCommand( terminal: vscode.Terminal, command: string, cwd?: string, timeout: number = 10000 ): Promise<{ output: string }> { terminal.show(); // Build full command including cd if cwd is specified let fullCommand = command; if (cwd) { if (cwd === '.' || cwd === './') { fullCommand = `${command}`; } else { const quotedPath = cwd.includes(' ') ? `"${cwd}"` : cwd; fullCommand = `cd ${quotedPath} && ${command}`; } } // Create timeout promise const timeoutPromise = new Promise<never>((_, reject) => { setTimeout(() => reject(new Error(`Command timed out after ${timeout}ms`)), timeout); }); // Create execution promise const executionPromise = async (): Promise<{ output: string }> => { // Execute the command using shell integration API const execution = terminal.shellIntegration!.executeCommand(fullCommand); // Capture output using the stream let output = ''; try { // Access the read stream (handling possible API differences) const outputStream = (execution as any).read(); for await (const data of outputStream) { output += data; } } catch (error) { throw new Error(`Failed to read command output: ${error}`); } return { output }; }; // Race between execution and timeout return Promise.race([executionPromise(), timeoutPromise]); } /** * Registers MCP shell-related tools with the server * @param server MCP server instance * @param terminal The terminal to use for command execution */ export function registerShellTools(server: McpServer, terminal?: vscode.Terminal): void { // Add execute_shell_command tool server.tool( 'execute_shell_command_code', `Executes shell commands in VS Code integrated terminal. WHEN TO USE: Running CLI commands, builds, git operations, npm/pip installs. Working directory: Use cwd to run commands in specific directories. Defaults to workspace root. If you get unexpected results, ensure the cwd is correct. Timeout: Commands must complete within specified time (default 10s) or the tool will return a timeout error, but the command may still be running in the terminal.`, { command: z.string().describe('The shell command to execute'), cwd: z.string().optional().default('.').describe('Optional working directory for the command'), timeout: z.number().optional().default(10000).describe('Command timeout in milliseconds (default: 10000)') }, async ({ command, cwd, timeout = 10000 }): Promise<CallToolResult> => { try { if (!terminal) { throw new Error('Terminal not available'); } // Check for shell integration - wait briefly if not available if (!terminal.shellIntegration) { const shellIntegrationAvailable = await waitForShellIntegration(terminal); if (!shellIntegrationAvailable) { throw new Error('Shell integration not available in terminal'); } } const { output } = await executeShellCommand(terminal, command, cwd, timeout); const result: CallToolResult = { content: [ { type: 'text', text: `Command: ${command}\n\nOutput:\n${output}` } ] }; return result; } catch (error) { console.error('[execute_shell_command] Error in tool:', error); throw error; } } ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/juehang/vscode-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server