UNPKG

vscode-mcp-comprehensive

Version:

Comprehensive MCP server exposing all VSCode features to AI agents with 101 tools including advanced debugging and console access

435 lines 19.4 kB
import * as vscode from 'vscode'; export class LanguageTools { constructor(server) { this.server = server; this.registerTools(); } registerTools() { // Get completions this.server.registerTool('language_get_completions', 'Get IntelliSense completions', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI' }, position: { type: 'object', description: 'Position for completions', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, triggerCharacter: { type: 'string', description: 'Trigger character (optional)' }, }, required: ['uri', 'position'], }, this.getCompletions.bind(this)); // Get hover information this.server.registerTool('language_get_hover', 'Get hover information', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI' }, position: { type: 'object', description: 'Position for hover', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, }, required: ['uri', 'position'], }, this.getHover.bind(this)); // Get signature help this.server.registerTool('language_get_signature_help', 'Get function signatures', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI' }, position: { type: 'object', description: 'Position for signature help', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, }, required: ['uri', 'position'], }, this.getSignatureHelp.bind(this)); // Go to definition this.server.registerTool('language_get_definition', 'Go to definition', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI' }, position: { type: 'object', description: 'Position to find definition for', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, }, required: ['uri', 'position'], }, this.getDefinition.bind(this)); // Find references this.server.registerTool('language_get_references', 'Find all references', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI' }, position: { type: 'object', description: 'Position to find references for', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, includeDeclaration: { type: 'boolean', description: 'Include declaration in results', default: true }, }, required: ['uri', 'position'], }, this.getReferences.bind(this)); // Get document symbols this.server.registerTool('language_get_symbols', 'Get document symbols', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI' }, query: { type: 'string', description: 'Symbol query (optional)' }, }, required: ['uri'], }, this.getSymbols.bind(this)); // Get diagnostics this.server.registerTool('language_get_diagnostics', 'Get errors/warnings', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI (optional, gets all if not provided)' }, severity: { type: 'string', description: 'Filter by severity (error/warning/info/hint)' }, }, }, this.getDiagnostics.bind(this)); // Get code actions this.server.registerTool('language_get_code_actions', 'Get available code actions', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI' }, range: { type: 'object', description: 'Range for code actions', properties: { start: { type: 'object', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, end: { type: 'object', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, }, required: ['start', 'end'], }, only: { type: 'array', items: { type: 'string' }, description: 'Filter by code action kind (quickfix/refactor/source)' }, }, required: ['uri', 'range'], }, this.getCodeActions.bind(this)); // Apply code action this.server.registerTool('language_apply_code_action', 'Apply code fix/refactor', { type: 'object', properties: { uri: { type: 'string', description: 'Document URI' }, range: { type: 'object', description: 'Range for code action', properties: { start: { type: 'object', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, end: { type: 'object', properties: { line: { type: 'number' }, character: { type: 'number' }, }, required: ['line', 'character'], }, }, required: ['start', 'end'], }, actionTitle: { type: 'string', description: 'Title of the code action to apply' }, actionKind: { type: 'string', description: 'Kind of code action (optional)' }, }, required: ['uri', 'range', 'actionTitle'], }, this.applyCodeAction.bind(this)); } async getCompletions(args) { try { this.server.validateRequiredParams(args, ['uri', 'position']); const uri = vscode.Uri.parse(args.uri); const document = await vscode.workspace.openTextDocument(uri); const position = this.server.toVSCodePosition(args.position); const completions = await vscode.commands.executeCommand('vscode.executeCompletionItemProvider', uri, position, args.triggerCharacter); if (!completions) { return this.server.createSuccessResponse([], 'No completions available'); } const completionItems = completions.items.map(item => ({ label: typeof item.label === 'string' ? item.label : item.label.label, kind: item.kind || 0, detail: item.detail, documentation: typeof item.documentation === 'string' ? item.documentation : item.documentation?.value, insertText: typeof item.insertText === 'string' ? item.insertText : item.insertText?.value, range: item.range ? this.server.convertRange(item.range) : undefined, })); return this.server.createSuccessResponse({ items: completionItems, isIncomplete: completions.isIncomplete, }); } catch (error) { return this.server.createErrorResponse(error); } } async getHover(args) { try { this.server.validateRequiredParams(args, ['uri', 'position']); const uri = vscode.Uri.parse(args.uri); const position = this.server.toVSCodePosition(args.position); const hover = await vscode.commands.executeCommand('vscode.executeHoverProvider', uri, position); if (!hover || hover.length === 0) { return this.server.createSuccessResponse(null, 'No hover information available'); } const hoverInfo = hover[0]; const contents = hoverInfo.contents.map(content => { if (typeof content === 'string') { return content; } else if (content instanceof vscode.MarkdownString) { return content.value; } else { return content.value; } }); return this.server.createSuccessResponse({ contents, range: hoverInfo.range ? this.server.convertRange(hoverInfo.range) : undefined, }); } catch (error) { return this.server.createErrorResponse(error); } } async getSignatureHelp(args) { try { this.server.validateRequiredParams(args, ['uri', 'position']); const uri = vscode.Uri.parse(args.uri); const position = this.server.toVSCodePosition(args.position); const signatureHelp = await vscode.commands.executeCommand('vscode.executeSignatureHelpProvider', uri, position); if (!signatureHelp) { return this.server.createSuccessResponse(null, 'No signature help available'); } const signatures = signatureHelp.signatures.map(sig => ({ label: sig.label, documentation: typeof sig.documentation === 'string' ? sig.documentation : sig.documentation?.value, parameters: sig.parameters?.map(param => ({ label: typeof param.label === 'string' ? param.label : param.label.join(''), documentation: typeof param.documentation === 'string' ? param.documentation : param.documentation?.value, })), })); return this.server.createSuccessResponse({ signatures, activeSignature: signatureHelp.activeSignature, activeParameter: signatureHelp.activeParameter, }); } catch (error) { return this.server.createErrorResponse(error); } } async getDefinition(args) { try { this.server.validateRequiredParams(args, ['uri', 'position']); const uri = vscode.Uri.parse(args.uri); const position = this.server.toVSCodePosition(args.position); const definitions = await vscode.commands.executeCommand('vscode.executeDefinitionProvider', uri, position); if (!definitions || definitions.length === 0) { return this.server.createSuccessResponse([], 'No definitions found'); } const definitionLocations = definitions.map(def => ({ uri: def.uri.toString(), range: this.server.convertRange(def.range), })); return this.server.createSuccessResponse(definitionLocations); } catch (error) { return this.server.createErrorResponse(error); } } async getReferences(args) { try { this.server.validateRequiredParams(args, ['uri', 'position']); const uri = vscode.Uri.parse(args.uri); const position = this.server.toVSCodePosition(args.position); const references = await vscode.commands.executeCommand('vscode.executeReferenceProvider', uri, position); if (!references || references.length === 0) { return this.server.createSuccessResponse([], 'No references found'); } const referenceLocations = references.map(ref => ({ uri: ref.uri.toString(), range: this.server.convertRange(ref.range), })); return this.server.createSuccessResponse(referenceLocations); } catch (error) { return this.server.createErrorResponse(error); } } async getSymbols(args) { try { this.server.validateRequiredParams(args, ['uri']); const uri = vscode.Uri.parse(args.uri); const symbols = await vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', uri); if (!symbols || symbols.length === 0) { return this.server.createSuccessResponse([], 'No symbols found'); } const symbolInfo = this.flattenSymbols(symbols, uri.toString()); let filteredSymbols = symbolInfo; if (args.query) { const query = args.query.toLowerCase(); filteredSymbols = symbolInfo.filter(symbol => symbol.name.toLowerCase().includes(query)); } return this.server.createSuccessResponse(filteredSymbols); } catch (error) { return this.server.createErrorResponse(error); } } flattenSymbols(symbols, uri, containerName) { const result = []; for (const symbol of symbols) { result.push({ name: symbol.name, kind: symbol.kind, location: { uri, range: this.server.convertRange(symbol.range), }, containerName, }); if (symbol.children && symbol.children.length > 0) { result.push(...this.flattenSymbols(symbol.children, uri, symbol.name)); } } return result; } async getDiagnostics(args) { try { const diagnostics = vscode.languages.getDiagnostics(); let allDiagnostics = []; for (const [docUri, diagnosticArray] of diagnostics) { if (args.uri && docUri.toString() !== args.uri) { continue; } const filteredDiagnostics = diagnosticArray .filter(diag => { if (args.severity) { const severityMap = { 'error': vscode.DiagnosticSeverity.Error, 'warning': vscode.DiagnosticSeverity.Warning, 'info': vscode.DiagnosticSeverity.Information, 'hint': vscode.DiagnosticSeverity.Hint, }; return diag.severity === severityMap[args.severity]; } return true; }) .map(diag => ({ message: diag.message, severity: diag.severity || 0, range: this.server.convertRange(diag.range), source: diag.source, code: typeof diag.code === 'string' || typeof diag.code === 'number' ? diag.code : undefined, })); allDiagnostics.push(...filteredDiagnostics); } return this.server.createSuccessResponse({ diagnostics: allDiagnostics, count: allDiagnostics.length, }); } catch (error) { return this.server.createErrorResponse(error); } } async getCodeActions(args) { try { this.server.validateRequiredParams(args, ['uri', 'range']); const uri = vscode.Uri.parse(args.uri); const range = this.server.toVSCodeRange(args.range); const codeActions = await vscode.commands.executeCommand('vscode.executeCodeActionProvider', uri, range, args.only?.join(',')); if (!codeActions || codeActions.length === 0) { return this.server.createSuccessResponse([], 'No code actions available'); } const actions = codeActions.map(action => ({ title: action.title, kind: action.kind?.value, isPreferred: action.isPreferred, disabled: action.disabled?.reason, edit: action.edit ? { hasChanges: true, size: 1, } : undefined, })); return this.server.createSuccessResponse(actions); } catch (error) { return this.server.createErrorResponse(error); } } async applyCodeAction(args) { try { this.server.validateRequiredParams(args, ['uri', 'range', 'actionTitle']); const uri = vscode.Uri.parse(args.uri); const range = this.server.toVSCodeRange(args.range); // First get available code actions const codeActions = await vscode.commands.executeCommand('vscode.executeCodeActionProvider', uri, range, args.actionKind); if (!codeActions || codeActions.length === 0) { return this.server.createErrorResponse('No code actions available'); } // Find the action by title const action = codeActions.find(a => a.title === args.actionTitle); if (!action) { return this.server.createErrorResponse(`Code action '${args.actionTitle}' not found`); } // Apply the action if (action.edit) { await vscode.workspace.applyEdit(action.edit); } if (action.command) { await vscode.commands.executeCommand(action.command.command, ...(action.command.arguments || [])); } return this.server.createSuccessResponse({ success: true }, `Code action '${args.actionTitle}' applied`); } catch (error) { return this.server.createErrorResponse(error); } } } //# sourceMappingURL=languageTools.js.map