mcpengine/servers/datadog/src/client/datadog-client.ts
Jake Shore e4a40298e4 Full cleanup: 65 servers compile clean, 15 new builds, TSC fixes across all existing servers
- Built from scratch: apollo, chargebee, datadog, greenhouse, lever, loom, pandadoc, salesloft, sendgrid, supabase, typeform, webflow, zoho-crm, twilio, reonomy
- TSC fixes: brevo, google-console, housecall-pro, meta-ads, rippling, bamboohr, close, fieldedge, freshdesk, helpscout, toast, touchbistro, hubspot, notion, quickbooks, airtable, gusto, intercom, linear, monday, salesforce, shopify, square, wave, xero
- Entry points added: close, touchbistro
- All 65 active servers compile with 0 TypeScript errors
- 4 specialty servers skipped (competitor-research, compliance-grc, n8n-apps, product-analytics)
2026-02-14 04:37:01 -05:00

111 lines
3.3 KiB
TypeScript

/**
* Datadog API Client
* Handles authentication, rate limiting, and API requests
*/
import axios, { AxiosInstance, AxiosError } from 'axios';
import Bottleneck from 'bottleneck';
import type { DatadogConfig } from '../types/index.js';
export class DatadogClient {
private client: AxiosInstance;
private limiter: Bottleneck;
private apiKey: string;
private appKey: string;
constructor(config: DatadogConfig) {
this.apiKey = config.apiKey;
this.appKey = config.appKey;
// Initialize rate limiter
this.limiter = new Bottleneck({
maxConcurrent: config.rateLimit?.maxConcurrent || 10,
minTime: config.rateLimit?.minTime || 100,
});
// Initialize axios client
const site = config.site || 'datadoghq.com';
this.client = axios.create({
baseURL: `https://api.${site}/api`,
headers: {
'Content-Type': 'application/json',
'DD-API-KEY': this.apiKey,
'DD-APPLICATION-KEY': this.appKey,
},
});
// Add response interceptor for error handling
this.client.interceptors.response.use(
(response) => response,
(error: AxiosError) => {
return Promise.reject(this.handleError(error));
}
);
}
private handleError(error: AxiosError): Error {
if (error.response) {
const status = error.response.status;
const data = error.response.data as any;
switch (status) {
case 400:
return new Error(`Datadog API bad request: ${JSON.stringify(data)}`);
case 401:
return new Error('Datadog API authentication failed. Check your API key.');
case 403:
return new Error('Datadog API access forbidden. Check your application key permissions.');
case 404:
return new Error('Datadog API resource not found.');
case 429:
return new Error('Datadog API rate limit exceeded. Please retry later.');
case 500:
case 502:
case 503:
return new Error('Datadog API server error. Please retry later.');
default:
return new Error(`Datadog API error (${status}): ${JSON.stringify(data)}`);
}
} else if (error.request) {
return new Error('Datadog API request failed. No response received.');
} else {
return new Error(`Datadog API error: ${error.message}`);
}
}
async get<T>(path: string, params?: Record<string, any>): Promise<T> {
return this.limiter.schedule(async () => {
const response = await this.client.get<T>(path, { params });
return response.data;
});
}
async post<T>(path: string, data?: any): Promise<T> {
return this.limiter.schedule(async () => {
const response = await this.client.post<T>(path, data);
return response.data;
});
}
async put<T>(path: string, data?: any): Promise<T> {
return this.limiter.schedule(async () => {
const response = await this.client.put<T>(path, data);
return response.data;
});
}
async patch<T>(path: string, data?: any): Promise<T> {
return this.limiter.schedule(async () => {
const response = await this.client.patch<T>(path, data);
return response.data;
});
}
async delete<T>(path: string): Promise<T> {
return this.limiter.schedule(async () => {
const response = await this.client.delete<T>(path);
return response.data;
});
}
}