Skip to main content
Glama
claude-desktop-proxy.js4.11 kB
#!/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();

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/daviddraiumbrella/invoice-monitoring'

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