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
JavaScript
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