Skip to main content
Glama

VSCode Language Server MCP Extension

by aaddrick
mcpServer.ts11.2 kB
import * as http from 'http'; import { Logger } from './logger'; import { LanguageServerTools } from './languageServerTools'; interface MCPRequest { jsonrpc: '2.0'; id: string | number; method: string; params?: any; } interface MCPResponse { jsonrpc: '2.0'; id: string | number; result?: any; error?: { code: number; message: string; data?: any; }; } export class MCPServer { private httpServer: http.Server | undefined; private running = false; private tools: LanguageServerTools; constructor( private port: number, private logger: Logger ) { this.tools = new LanguageServerTools(logger); } start() { if (this.running) { this.logger.warn('MCP server already running'); return; } this.httpServer = http.createServer(async (req, res) => { // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // Handle preflight if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); return; } // Handle GET for health check if (req.method === 'GET') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ name: 'vscode-mcp-language-server', version: '0.1.0', status: 'running', transport: 'http' })); return; } // Handle POST for MCP requests if (req.method === 'POST') { let body = ''; req.on('data', (chunk) => { body += chunk.toString(); }); req.on('end', async () => { try { const request: MCPRequest = JSON.parse(body); this.logger.debug('Received request:', request.method); const response = await this.handleRequest(request); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response)); } catch (error) { this.logger.error('Error handling request:', error); const errorResponse: MCPResponse = { jsonrpc: '2.0', id: null as any, error: { code: -32700, message: 'Parse error', data: String(error) } }; res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(errorResponse)); } }); return; } // Method not allowed res.writeHead(405, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Method not allowed' })); }); this.httpServer.listen(this.port, () => { this.running = true; this.logger.info(`MCP HTTP server listening on port ${this.port}`); }); } stop() { if (!this.running) { return; } this.httpServer?.close(); this.running = false; this.logger.info('MCP server stopped'); } isRunning(): boolean { return this.running; } private async handleRequest(request: MCPRequest): Promise<MCPResponse> { try { const { method, params } = request; let result: any; switch (method) { case 'initialize': result = this.handleInitialize(); break; case 'tools/list': result = this.handleToolsList(); break; case 'tools/call': result = await this.handleToolCall(params); break; default: throw new Error(`Unknown method: ${method}`); } return { jsonrpc: '2.0', id: request.id, result }; } catch (error) { this.logger.error('Error handling request:', error); return { jsonrpc: '2.0', id: request.id, error: { code: -32603, message: 'Internal error', data: String(error) } }; } } private handleInitialize() { return { protocolVersion: '2024-11-05', serverInfo: { name: 'vscode-mcp-language-server', version: '0.1.0' }, capabilities: { tools: {} } }; } private handleToolsList() { return { tools: [ { name: 'vscode_ls_get_symbols', description: 'Get document symbol outline from VSCode Language Server', inputSchema: { type: 'object', properties: { uri: { type: 'string', description: 'File URI (e.g., file:///path/to/file.js)' } }, required: ['uri'] } }, { name: 'vscode_ls_find_references', description: 'Find all references to a symbol at a position', inputSchema: { type: 'object', properties: { uri: { type: 'string', description: 'File URI' }, line: { type: 'number', description: 'Line number (0-indexed)' }, character: { type: 'number', description: 'Character offset (0-indexed)' } }, required: ['uri', 'line', 'character'] } }, { name: 'vscode_ls_rename', description: 'Rename a symbol at a position with reference tracking', inputSchema: { type: 'object', properties: { uri: { type: 'string', description: 'File URI' }, line: { type: 'number', description: 'Line number (0-indexed)' }, character: { type: 'number', description: 'Character offset (0-indexed)' }, newName: { type: 'string', description: 'New name for the symbol' } }, required: ['uri', 'line', 'character', 'newName'] } }, { name: 'vscode_ls_get_definition', description: 'Get definition location for a symbol', inputSchema: { type: 'object', properties: { uri: { type: 'string', description: 'File URI' }, line: { type: 'number', description: 'Line number (0-indexed)' }, character: { type: 'number', description: 'Character offset (0-indexed)' } }, required: ['uri', 'line', 'character'] } }, { name: 'vscode_ls_get_hover', description: 'Get hover information (type, docs) for a symbol', inputSchema: { type: 'object', properties: { uri: { type: 'string', description: 'File URI' }, line: { type: 'number', description: 'Line number (0-indexed)' }, character: { type: 'number', description: 'Character offset (0-indexed)' } }, required: ['uri', 'line', 'character'] } } ] }; } private async handleToolCall(params: any): Promise<any> { const { name, arguments: args } = params; switch (name) { case 'vscode_ls_get_symbols': return await this.tools.getSymbols(args.uri); case 'vscode_ls_find_references': return await this.tools.findReferences( args.uri, args.line, args.character ); case 'vscode_ls_rename': return await this.tools.rename( args.uri, args.line, args.character, args.newName ); case 'vscode_ls_get_definition': return await this.tools.getDefinition( args.uri, args.line, args.character ); case 'vscode_ls_get_hover': return await this.tools.getHover( args.uri, args.line, args.character ); default: throw new Error(`Unknown tool: ${name}`); } } }

Latest Blog Posts

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/aaddrick/vscode-mcp-language-server'

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