UNPKG

mcp-doppler-server

Version:

Model Context Protocol server for Doppler secret management

204 lines 7.48 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DopplerClient = void 0; const axios_1 = __importDefault(require("axios")); const logger_js_1 = require("./logger.js"); class DopplerClient { axios; constructor(token) { this.axios = axios_1.default.create({ baseURL: 'https://api.doppler.com/v3', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, timeout: 30000, }); // Add request/response interceptors for logging this.axios.interceptors.request.use((config) => { logger_js_1.logger.debug(`API Request: ${config.method?.toUpperCase()} ${config.url}`); return config; }, (error) => { logger_js_1.logger.error('Request error', error); return Promise.reject(error); }); this.axios.interceptors.response.use((response) => { logger_js_1.logger.debug(`API Response: ${response.status} ${response.config.url}`); return response; }, (error) => { if (error.response) { logger_js_1.logger.error(`API Error: ${error.response.status} ${error.response.config.url}`, { data: error.response.data, }); } else { logger_js_1.logger.error('API Error', error.message); } return Promise.reject(error); }); } async listProjects() { try { const response = await this.axios.get('/projects', { params: { per_page: 100 }, }); return response.data.projects || []; } catch (error) { logger_js_1.logger.error('Failed to list projects', error); throw new Error('Failed to list projects'); } } async listConfigs(project) { try { const response = await this.axios.get('/configs', { params: { project, per_page: 100 }, }); return response.data.configs || []; } catch (error) { logger_js_1.logger.error(`Failed to list configs for project ${project}`, error); throw new Error(`Failed to list configs for project ${project}`); } } async listSecrets(project, config) { try { const response = await this.axios.get('/configs/config/secrets/names', { params: { project, config }, }); return response.data.names || []; } catch (error) { logger_js_1.logger.error(`Failed to list secrets for ${project}/${config}`, error); throw new Error(`Failed to list secrets for ${project}/${config}`); } } async getSecret(project, config, name) { try { const response = await this.axios.get('/configs/config/secrets', { params: { project, config, name }, }); const secrets = response.data.secrets || {}; return { name, value: secrets[name], }; } catch (error) { logger_js_1.logger.error(`Failed to get secret ${name} from ${project}/${config}`, error); throw new Error(`Failed to get secret ${name}`); } } async setSecret(project, config, name, value) { try { const response = await this.axios.post('/configs/config/secrets', { project, config, secrets: { [name]: value, }, }); // Check if secret was created or updated const created = response.data.secrets?.[name]?.created || false; return { created }; } catch (error) { logger_js_1.logger.error(`Failed to set secret ${name} in ${project}/${config}`, error); throw new Error(`Failed to set secret ${name}`); } } async deleteSecrets(project, config, secrets) { try { await this.axios.delete('/configs/config/secrets', { data: { project, config, secrets, }, }); } catch (error) { logger_js_1.logger.error(`Failed to delete secrets from ${project}/${config}`, error); throw new Error('Failed to delete secrets'); } } async promoteSecrets(project, sourceConfig, targetConfig, excludeKeys) { try { // First, get all secrets from source config const response = await this.axios.get('/configs/config/secrets/download', { params: { project, config: sourceConfig, format: 'json', }, }); const sourceSecrets = response.data || {}; // Filter out excluded keys const secretsToPromote = {}; let count = 0; for (const [key, value] of Object.entries(sourceSecrets)) { if (!excludeKeys || !excludeKeys.includes(key)) { secretsToPromote[key] = value; count++; } } // Update target config with filtered secrets if (count > 0) { await this.axios.post('/configs/config/secrets', { project, config: targetConfig, secrets: secretsToPromote, }); } return { count }; } catch (error) { logger_js_1.logger.error(`Failed to promote secrets from ${sourceConfig} to ${targetConfig}`, error); throw new Error('Failed to promote secrets'); } } async createServiceToken(project, config, name, access = 'read') { try { const response = await this.axios.post('/configs/config/tokens', { project, config, name, access, }); return response.data.token; } catch (error) { logger_js_1.logger.error(`Failed to create service token for ${project}/${config}`, error); throw new Error('Failed to create service token'); } } async getActivityLogs(project, page = 1, perPage = 20) { try { const params = { page, per_page: perPage }; if (project) { params.project = project; } const response = await this.axios.get('/logs', { params }); return response.data.logs || []; } catch (error) { logger_js_1.logger.error('Failed to get activity logs', error); throw new Error('Failed to get activity logs'); } } async validateConnection() { try { await this.axios.get('/me'); return true; } catch (error) { logger_js_1.logger.error('Failed to validate Doppler connection', error); return false; } } } exports.DopplerClient = DopplerClient; //# sourceMappingURL=doppler-client.js.map