UNPKG

twenty-mcp-server

Version:

Easy-to-install Model Context Protocol server for Twenty CRM. Try instantly with 'npx twenty-mcp-server setup' or install globally for permanent use.

131 lines 4.94 kB
import { getKeyStorageService } from '../auth/key-storage.js'; /** * API routes for managing user API keys */ export class ApiKeyRoutes { keyStorage = getKeyStorageService(); /** * Handle API key management requests */ async handle(req, res) { // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type'); // Must be authenticated if (!req.auth) { res.writeHead(401, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'unauthorized', error_description: 'Authentication required' })); return; } const url = new URL(req.url, `http://localhost`); const path = url.pathname; // Route to appropriate handler if (path === '/api/keys' && req.method === 'GET') { await this.getKeyMetadata(req, res); } else if (path === '/api/keys' && req.method === 'POST') { await this.storeKey(req, res); } else if (path === '/api/keys' && req.method === 'DELETE') { await this.deleteKey(req, res); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not found' })); } } /** * Get API key metadata (without revealing the key) */ async getKeyMetadata(req, res) { try { const metadata = await this.keyStorage.getApiKeyMetadata(req.auth.userId); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ hasKey: metadata.hasKey, updatedAt: metadata.updatedAt, baseUrl: metadata.baseUrl, })); } catch (error) { console.error('Error getting key metadata:', error); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'internal_error', error_description: 'Failed to retrieve key metadata' })); } } /** * Store a new API key */ async storeKey(req, res) { try { // Parse request body const chunks = []; req.on('data', (chunk) => chunks.push(chunk)); req.on('end', async () => { try { const body = JSON.parse(Buffer.concat(chunks).toString()); if (!body.apiKey) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'invalid_request', error_description: 'API key is required' })); return; } // Store the key await this.keyStorage.storeApiKey(req.auth.userId, body.apiKey, body.baseUrl); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'API key stored successfully' })); } catch (error) { console.error('Error parsing request:', error); res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'invalid_request', error_description: 'Invalid JSON body' })); } }); } catch (error) { console.error('Error storing key:', error); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'internal_error', error_description: 'Failed to store API key' })); } } /** * Delete the stored API key */ async deleteKey(req, res) { try { await this.keyStorage.deleteApiKey(req.auth.userId); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'API key deleted successfully' })); } catch (error) { console.error('Error deleting key:', error); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'internal_error', error_description: 'Failed to delete API key' })); } } } //# sourceMappingURL=api-keys.js.map