UNPKG

dddvchang-mcp-proxy

Version:

Smart MCP proxy with automatic JetBrains IDE discovery, WebSocket support, and intelligent connection naming

170 lines (169 loc) • 5.71 kB
#!/usr/bin/env node import * as http from 'http'; import { execSync } from 'child_process'; /** * Check if Claude CLI is installed */ function isClaudeCLIInstalled() { try { execSync('claude --version', { stdio: 'ignore' }); return true; } catch { return false; } } /** * Get IDE info from MCP server */ async function getIDEInfo(port) { return new Promise((resolve) => { // First try to get IDE info from a special endpoint const options = { hostname: '127.0.0.1', port: port, path: '/api/mcp/info', method: 'GET', timeout: 2000 }; const req = http.request(options, (res) => { let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => { if (res.statusCode === 200) { try { const response = JSON.parse(data); let ideInfo; // Handle both direct JSON and nested status format if (response.status) { ideInfo = JSON.parse(response.status); } else { ideInfo = response; } resolve({ port, ideName: ideInfo.ideName || ideInfo.name || `JetBrains-${port}`, projectName: ideInfo.projectName, projectPath: ideInfo.projectPath }); } catch { // If parsing fails, just return basic info resolve({ port, ideName: `JetBrains-${port}` }); } } else { // Fallback to basic port check resolve({ port, ideName: `JetBrains-${port}` }); } }); }); req.on('error', () => { // Try basic port check as fallback checkBasicPort(port).then(resolve); }); req.on('timeout', () => { req.destroy(); checkBasicPort(port).then(resolve); }); req.end(); }); } /** * Basic port check */ async function checkBasicPort(port) { return new Promise((resolve) => { const options = { hostname: '127.0.0.1', port: port, path: '/api/mcp', method: 'GET', timeout: 500 }; const req = http.request(options, (res) => { if (res.statusCode === 200 || res.statusCode === 404) { resolve({ port, ideName: `JetBrains-${port}` }); } else { resolve(null); } }); req.on('error', () => resolve(null)); req.on('timeout', () => { req.destroy(); resolve(null); }); req.end(); }); } /** * Scan port range for MCP servers */ async function scanPorts(startPort = 63320, endPort = 63340) { const servers = []; const promises = []; for (let port = startPort; port <= endPort; port++) { promises.push(getIDEInfo(port)); } const results = await Promise.all(promises); for (const result of results) { if (result) { servers.push(result); } } return servers; } /** * Main scan function */ export async function scanForMCPServers() { console.log('šŸ” Scanning for JetBrains MCP servers (ports 63320-63340)...\n'); const servers = await scanPorts(); if (servers.length === 0) { console.log('āŒ No MCP servers found.\n'); console.log('šŸ’” Make sure:'); console.log(' 1. JetBrains IDE is running'); console.log(' 2. MCP Server Plugin is installed and enabled'); console.log(' 3. The IDE has a project open\n'); return; } console.log(`āœ… Found ${servers.length} MCP server(s):\n`); servers.forEach((server) => { console.log(` • Port ${server.port}: ${server.ideName}`); }); console.log('\nšŸ“‹ To add these servers to Claude, run:\n'); const claudeInstalled = isClaudeCLIInstalled(); servers.forEach((server, index) => { // Create a clean name from IDE name let name = server.ideName || `jetbrains-${server.port}`; // Clean up the name for use as identifier name = name.toLowerCase() .replace(/[^a-z0-9-]/g, '-') .replace(/-+/g, '-') .replace(/^-|-$/g, ''); // Generate WebSocket proxy configuration if (claudeInstalled) { console.log(`claude mcp add proxy --name "${name}" --proxy-command "npx" --proxy-args "@dddvchang/mcp-proxy" --proxy-env "MCP_SERVER_URL=ws://127.0.0.1:${server.port}/api/mcp-ws/"`); } else { // Show config format for manual addition if (index === 0) { console.log('Add to your Claude MCP config file:'); console.log('```json'); } console.log(`"${name}": {`); console.log(` "command": "npx",`); console.log(` "args": ["-y", "@dddvchang/mcp-proxy"],`); console.log(` "env": {`); console.log(` "MCP_SERVER_URL": "ws://127.0.0.1:${server.port}/api/mcp-ws/"`); console.log(` }`); console.log(`}${index < servers.length - 1 ? ',' : ''}`); } }); if (!claudeInstalled) { console.log('```'); } console.log('\n✨ Done!'); }