mcp-doppler-server
Version:
Model Context Protocol server for Doppler secret management
204 lines • 7.48 kB
JavaScript
;
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