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
JavaScript
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!');
}