#!/usr/bin/env node
/**
* Claude Desktop Proxy for Umbrella MCP
* Automatically handles authentication for SAOLA account
*/
const http = require('http');
const crypto = require('crypto');
const { spawn } = require('child_process');
// SAOLA account credentials
const CREDENTIALS = {
username: 'david+saola@umbrellacost.com',
password: 'Dsamsung1!'
};
const SERVER_PORT = 3000;
let sessionToken = null;
let authPromise = null;
// Authenticate with server
async function authenticate() {
if (authPromise) return authPromise;
authPromise = new Promise((resolve, reject) => {
const data = JSON.stringify(CREDENTIALS);
const options = {
hostname: 'localhost',
port: SERVER_PORT,
path: '/auth',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', chunk => responseData += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(responseData);
if (parsed.success) {
sessionToken = parsed.sessionToken;
console.error(`✅ Authenticated as ${CREDENTIALS.username}`);
resolve(sessionToken);
} else {
reject(new Error(parsed.error || 'Authentication failed'));
}
} catch (e) {
reject(new Error('Invalid response from server'));
}
});
});
req.on('error', (err) => {
reject(new Error(`Connection failed: ${err.message}`));
});
req.write(data);
req.end();
});
return authPromise;
}
// Handle incoming MCP requests from Claude Desktop
async function handleRequest(request) {
try {
// Ensure we're authenticated
if (!sessionToken) {
await authenticate();
}
return new Promise((resolve, reject) => {
const data = JSON.stringify(request);
const options = {
hostname: 'localhost',
port: SERVER_PORT,
path: `/sse?token=${sessionToken}`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', chunk => responseData += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(responseData);
resolve(parsed);
} catch (e) {
reject(new Error('Invalid response from server'));
}
});
});
req.on('error', reject);
req.write(data);
req.end();
});
} catch (error) {
return {
jsonrpc: '2.0',
id: request.id,
error: {
code: -32603,
message: error.message
}
};
}
}
// Main proxy loop
async function runProxy() {
console.error('🚀 Claude Desktop Proxy for Umbrella MCP');
console.error('📡 Connecting to server at localhost:' + SERVER_PORT);
// First authenticate
try {
await authenticate();
} catch (error) {
console.error('❌ Authentication failed:', error.message);
console.error('Make sure the server is running at localhost:' + SERVER_PORT);
process.exit(1);
}
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
// Process each line of input from Claude Desktop
rl.on('line', async (line) => {
try {
const request = JSON.parse(line);
const response = await handleRequest(request);
console.log(JSON.stringify(response));
} catch (error) {
console.log(JSON.stringify({
jsonrpc: '2.0',
error: {
code: -32700,
message: 'Parse error: ' + error.message
}
}));
}
});
// Handle shutdown
process.on('SIGINT', () => {
console.error('\\n👋 Proxy shutting down');
process.exit(0);
});
}
// Start the proxy
runProxy();