#!/usr/bin/env node
import 'dotenv/config';
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import axios from "axios";
// Zod schemas for tool inputs
const GetDashboardsSchema = z.object({
limit: z.number().optional().default(10),
author: z.string().optional(),
filterDeleted: z.boolean().optional(),
});
const GetMetricsSchema = z.object({
query: z.string().optional(),
limit: z.number().optional().default(100),
});
const GetMonitorsSchema = z.object({
limit: z.number().optional().default(10),
groupStates: z.array(z.string()).optional(),
tags: z.string().optional(),
});
const SearchLogsSchema = z.object({
query: z.string(),
timeFrom: z.string().optional().default("now-15m"),
timeTo: z.string().optional().default("now"),
limit: z.number().optional().default(100),
});
const GetEventsSchema = z.object({
start: z.number(),
end: z.number(),
priority: z.enum(["normal", "low"]).optional(),
sources: z.string().optional(),
tags: z.string().optional(),
});
// APM and Infrastructure schemas
const GetHostsSchema = z.object({
filter: z.string().optional(),
sortField: z.string().optional(),
sortDir: z.enum(["asc", "desc"]).optional(),
start: z.number().optional(),
end: z.number().optional(),
});
const GetIncidentsSchema = z.object({
include: z.array(z.string()).optional(),
pageSize: z.number().optional().default(20),
query: z.string().optional(),
});
const QueryMetricsSchema = z.object({
query: z.string(),
from: z.number(),
to: z.number(),
});
const GetSyntheticsTestsSchema = z.object({
pageSize: z.number().optional().default(20),
pageNumber: z.number().optional().default(0),
});
const GetUsageSchema = z.object({
startHr: z.string(),
endHr: z.string().optional(),
});
const GetSLOsSchema = z.object({
ids: z.string().optional(),
query: z.string().optional(),
tagsQuery: z.string().optional(),
});
const GetRUMApplicationsSchema = z.object({
pageSize: z.number().optional().default(20),
pageNumber: z.number().optional().default(0),
});
const SearchRUMEventsSchema = z.object({
query: z.string().optional().default("*"),
timeFrom: z.string().optional().default("now-15m"),
timeTo: z.string().optional().default("now"),
limit: z.number().optional().default(100),
});
const GetSecurityRulesSchema = z.object({
pageSize: z.number().optional().default(20),
pageNumber: z.number().optional().default(0),
});
const AggregateLogsSchema = z.object({
query: z.string().optional().default("*"),
timeFrom: z.string().optional().default("now-15m"),
timeTo: z.string().optional().default("now"),
compute: z.array(z.object({
aggregation: z.string(),
facet: z.string().optional(),
interval: z.string().optional(),
})).optional(),
groupBy: z.array(z.object({
facet: z.string(),
limit: z.number().optional().default(10),
})).optional(),
});
const GetContainersSchema = z.object({
filterTags: z.string().optional(),
groupBy: z.string().optional(),
sort: z.string().optional(),
pageSize: z.number().optional().default(20),
});
const GetProcessesSchema = z.object({
search: z.string().optional(),
tags: z.string().optional(),
pageSize: z.number().optional().default(20),
pageNumber: z.number().optional().default(0),
});
const GetAuditLogsSchema = z.object({
filterQuery: z.string().optional(),
filterFrom: z.string().optional().default("now-15m"),
filterTo: z.string().optional().default("now"),
sort: z.string().optional().default("-timestamp"),
pageLimit: z.number().optional().default(100),
});
const GetNotebooksSchema = z.object({
authorHandle: z.string().optional(),
excludeAuthorHandle: z.string().optional(),
start: z.number().optional(),
count: z.number().optional().default(20),
});
const GetDowntimeSchema = z.object({
currentOnly: z.boolean().optional(),
withCreator: z.boolean().optional(),
});
const GetServiceMapSchema = z.object({
env: z.string(),
serviceName: z.string().optional(),
start: z.number().optional(),
end: z.number().optional(),
});
// Tool names enum - Extended with comprehensive Datadog API tools
const ToolName = {
// Dashboard Management
GET_DASHBOARDS: "get_dashboards",
CREATE_DASHBOARD: "create_dashboard",
UPDATE_DASHBOARD: "update_dashboard",
DELETE_DASHBOARD: "delete_dashboard",
// Monitor Management
GET_MONITORS: "get_monitors",
CREATE_MONITOR: "create_monitor",
UPDATE_MONITOR: "update_monitor",
DELETE_MONITOR: "delete_monitor",
MUTE_MONITOR: "mute_monitor",
UNMUTE_MONITOR: "unmute_monitor",
// Metrics
GET_METRICS: "get_metrics",
QUERY_METRICS: "query_metrics",
SUBMIT_METRICS: "submit_metrics",
GET_METRIC_METADATA: "get_metric_metadata",
// Logs
SEARCH_LOGS: "search_logs",
AGGREGATE_LOGS: "aggregate_logs",
GET_LOG_INDEXES: "get_log_indexes",
GET_LOG_PIPELINES: "get_log_pipelines",
// Events
GET_EVENTS: "get_events",
CREATE_EVENT: "create_event",
// APM (Application Performance Monitoring)
GET_SERVICES: "get_services",
GET_SERVICE_MAP: "get_service_map",
GET_TRACES: "get_traces",
GET_SPANS: "get_spans",
// Infrastructure
GET_HOSTS: "get_hosts",
GET_HOST_TAGS: "get_host_tags",
GET_CONTAINERS: "get_containers",
GET_PROCESSES: "get_processes",
// RUM (Real User Monitoring)
GET_RUM_APPLICATIONS: "get_rum_applications",
SEARCH_RUM_EVENTS: "search_rum_events",
GET_RUM_APPLICATION_EVENTS: "get_rum_application_events",
// Synthetics
GET_SYNTHETICS_TESTS: "get_synthetics_tests",
GET_SYNTHETICS_TEST_RESULTS: "get_synthetics_test_results",
GET_SYNTHETICS_GLOBAL_VARIABLES: "get_synthetics_global_variables",
// Security Monitoring
GET_SECURITY_RULES: "get_security_rules",
GET_SECURITY_SIGNALS: "get_security_signals",
LIST_SECURITY_FINDINGS: "list_security_findings",
// Incident Management
GET_INCIDENTS: "get_incidents",
GET_INCIDENT_SERVICES: "get_incident_services",
GET_INCIDENT_TEAMS: "get_incident_teams",
// SLOs (Service Level Objectives)
GET_SLOS: "get_slos",
GET_SLO_HISTORY: "get_slo_history",
// Usage & Billing
GET_USAGE: "get_usage",
GET_USAGE_ATTRIBUTION: "get_usage_attribution",
GET_ESTIMATED_USAGE: "get_estimated_usage",
// User & Organization Management
GET_USERS: "get_users",
GET_ORGANIZATIONS: "get_organizations",
GET_ROLES: "get_roles",
// Audit
GET_AUDIT_LOGS: "get_audit_logs",
// Notebooks
GET_NOTEBOOKS: "get_notebooks",
// Downtimes
GET_DOWNTIMES: "get_downtimes",
SCHEDULE_DOWNTIME: "schedule_downtime",
// Integrations
GET_INTEGRATIONS: "get_integrations",
GET_AWS_INTEGRATION: "get_aws_integration",
GET_GCP_INTEGRATION: "get_gcp_integration",
GET_AZURE_INTEGRATION: "get_azure_integration",
};
class DatadogMCPServer {
constructor(apiKey, appKey, site = "datadoghq.com") {
this.apiKey = apiKey;
this.appKey = appKey;
this.site = site;
this.baseUrl = `https://api.${site}`;
this.server = new Server(
{
name: "datadog-mcp-server",
title: "Datadog MCP Server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
this.setupHandlers();
}
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
// Dashboard Management
{
name: ToolName.GET_DASHBOARDS,
description: "Get list of Datadog dashboards",
inputSchema: zodToJsonSchema(GetDashboardsSchema),
},
// Monitor Management
{
name: ToolName.GET_MONITORS,
description: "Get list of Datadog monitors",
inputSchema: zodToJsonSchema(GetMonitorsSchema),
},
// Metrics
{
name: ToolName.GET_METRICS,
description: "Search and list Datadog metrics",
inputSchema: zodToJsonSchema(GetMetricsSchema),
},
{
name: ToolName.QUERY_METRICS,
description: "Query metrics data over time",
inputSchema: zodToJsonSchema(QueryMetricsSchema),
},
// Logs
{
name: ToolName.SEARCH_LOGS,
description: "Search Datadog logs",
inputSchema: zodToJsonSchema(SearchLogsSchema),
},
{
name: ToolName.AGGREGATE_LOGS,
description: "Aggregate logs with grouping and metrics",
inputSchema: zodToJsonSchema(AggregateLogsSchema),
},
// Events
{
name: ToolName.GET_EVENTS,
description: "Get Datadog events within a time range",
inputSchema: zodToJsonSchema(GetEventsSchema),
},
// Infrastructure & Hosts
{
name: ToolName.GET_HOSTS,
description: "Get list of hosts and their metadata",
inputSchema: zodToJsonSchema(GetHostsSchema),
},
{
name: ToolName.GET_CONTAINERS,
description: "Get list of containers and their metrics",
inputSchema: zodToJsonSchema(GetContainersSchema),
},
{
name: ToolName.GET_PROCESSES,
description: "Get list of processes running on hosts",
inputSchema: zodToJsonSchema(GetProcessesSchema),
},
// RUM (Real User Monitoring)
{
name: ToolName.GET_RUM_APPLICATIONS,
description: "Get list of RUM applications",
inputSchema: zodToJsonSchema(GetRUMApplicationsSchema),
},
{
name: ToolName.SEARCH_RUM_EVENTS,
description: "Search RUM events and user sessions",
inputSchema: zodToJsonSchema(SearchRUMEventsSchema),
},
// APM (Application Performance Monitoring)
{
name: ToolName.GET_SERVICE_MAP,
description: "Get APM service map and dependencies",
inputSchema: zodToJsonSchema(GetServiceMapSchema),
},
// Synthetics
{
name: ToolName.GET_SYNTHETICS_TESTS,
description: "Get list of Synthetic tests",
inputSchema: zodToJsonSchema(GetSyntheticsTestsSchema),
},
// Security Monitoring
{
name: ToolName.GET_SECURITY_RULES,
description: "Get security monitoring rules",
inputSchema: zodToJsonSchema(GetSecurityRulesSchema),
},
// Incident Management
{
name: ToolName.GET_INCIDENTS,
description: "Get list of incidents",
inputSchema: zodToJsonSchema(GetIncidentsSchema),
},
// SLOs (Service Level Objectives)
{
name: ToolName.GET_SLOS,
description: "Get list of Service Level Objectives",
inputSchema: zodToJsonSchema(GetSLOsSchema),
},
// Usage & Billing
{
name: ToolName.GET_USAGE,
description: "Get usage and billing information",
inputSchema: zodToJsonSchema(GetUsageSchema),
},
// Audit
{
name: ToolName.GET_AUDIT_LOGS,
description: "Get audit logs for security and compliance",
inputSchema: zodToJsonSchema(GetAuditLogsSchema),
},
// Notebooks
{
name: ToolName.GET_NOTEBOOKS,
description: "Get list of Datadog notebooks",
inputSchema: zodToJsonSchema(GetNotebooksSchema),
},
// Downtimes
{
name: ToolName.GET_DOWNTIMES,
description: "Get scheduled downtimes",
inputSchema: zodToJsonSchema(GetDowntimeSchema),
},
],
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case ToolName.GET_DASHBOARDS: {
const validatedArgs = GetDashboardsSchema.parse(args);
const result = await this.getDashboards(validatedArgs);
return {
content: [{ type: "text", text: this.formatDashboardsOutput(result) }],
};
}
case ToolName.GET_METRICS: {
const validatedArgs = GetMetricsSchema.parse(args);
const result = await this.getMetrics(validatedArgs);
return {
content: [{ type: "text", text: this.formatMetricsOutput(result) }],
};
}
case ToolName.QUERY_METRICS: {
const validatedArgs = QueryMetricsSchema.parse(args);
const result = await this.queryMetrics(validatedArgs);
return {
content: [{ type: "text", text: this.formatMetricsQueryOutput(result) }],
};
}
case ToolName.GET_MONITORS: {
const validatedArgs = GetMonitorsSchema.parse(args);
const result = await this.getMonitors(validatedArgs);
return {
content: [{ type: "text", text: this.formatMonitorsOutput(result) }],
};
}
case ToolName.SEARCH_LOGS: {
const validatedArgs = SearchLogsSchema.parse(args);
const result = await this.searchLogs(validatedArgs);
return {
content: [{ type: "text", text: this.formatLogsOutput(result, validatedArgs) }],
};
}
case ToolName.AGGREGATE_LOGS: {
const validatedArgs = AggregateLogsSchema.parse(args);
const result = await this.aggregateLogs(validatedArgs);
return {
content: [{ type: "text", text: this.formatAggregateLogsOutput(result) }],
};
}
case ToolName.GET_EVENTS: {
const validatedArgs = GetEventsSchema.parse(args);
const result = await this.getEvents(validatedArgs);
return {
content: [{ type: "text", text: this.formatEventsOutput(result) }],
};
}
case ToolName.GET_HOSTS: {
const validatedArgs = GetHostsSchema.parse(args);
const result = await this.getHosts(validatedArgs);
return {
content: [{ type: "text", text: this.formatHostsOutput(result) }],
};
}
case ToolName.GET_CONTAINERS: {
const validatedArgs = GetContainersSchema.parse(args);
const result = await this.getContainers(validatedArgs);
return {
content: [{ type: "text", text: this.formatContainersOutput(result) }],
};
}
case ToolName.GET_PROCESSES: {
const validatedArgs = GetProcessesSchema.parse(args);
const result = await this.getProcesses(validatedArgs);
return {
content: [{ type: "text", text: this.formatProcessesOutput(result) }],
};
}
case ToolName.GET_RUM_APPLICATIONS: {
const validatedArgs = GetRUMApplicationsSchema.parse(args);
const result = await this.getRUMApplications(validatedArgs);
return {
content: [{ type: "text", text: this.formatRUMApplicationsOutput(result) }],
};
}
case ToolName.SEARCH_RUM_EVENTS: {
const validatedArgs = SearchRUMEventsSchema.parse(args);
const result = await this.searchRUMEvents(validatedArgs);
return {
content: [{ type: "text", text: this.formatRUMEventsOutput(result) }],
};
}
case ToolName.GET_SERVICE_MAP: {
const validatedArgs = GetServiceMapSchema.parse(args);
const result = await this.getServiceMap(validatedArgs);
return {
content: [{ type: "text", text: this.formatServiceMapOutput(result) }],
};
}
case ToolName.GET_SYNTHETICS_TESTS: {
const validatedArgs = GetSyntheticsTestsSchema.parse(args);
const result = await this.getSyntheticsTests(validatedArgs);
return {
content: [{ type: "text", text: this.formatSyntheticsTestsOutput(result) }],
};
}
case ToolName.GET_SECURITY_RULES: {
const validatedArgs = GetSecurityRulesSchema.parse(args);
const result = await this.getSecurityRules(validatedArgs);
return {
content: [{ type: "text", text: this.formatSecurityRulesOutput(result) }],
};
}
case ToolName.GET_INCIDENTS: {
const validatedArgs = GetIncidentsSchema.parse(args);
const result = await this.getIncidents(validatedArgs);
return {
content: [{ type: "text", text: this.formatIncidentsOutput(result) }],
};
}
case ToolName.GET_SLOS: {
const validatedArgs = GetSLOsSchema.parse(args);
const result = await this.getSLOs(validatedArgs);
return {
content: [{ type: "text", text: this.formatSLOsOutput(result) }],
};
}
case ToolName.GET_USAGE: {
const validatedArgs = GetUsageSchema.parse(args);
const result = await this.getUsage(validatedArgs);
return {
content: [{ type: "text", text: this.formatUsageOutput(result) }],
};
}
case ToolName.GET_AUDIT_LOGS: {
const validatedArgs = GetAuditLogsSchema.parse(args);
const result = await this.getAuditLogs(validatedArgs);
return {
content: [{ type: "text", text: this.formatAuditLogsOutput(result) }],
};
}
case ToolName.GET_NOTEBOOKS: {
const validatedArgs = GetNotebooksSchema.parse(args);
const result = await this.getNotebooks(validatedArgs);
return {
content: [{ type: "text", text: this.formatNotebooksOutput(result) }],
};
}
case ToolName.GET_DOWNTIMES: {
const validatedArgs = GetDowntimeSchema.parse(args);
const result = await this.getDowntimes(validatedArgs);
return {
content: [{ type: "text", text: this.formatDowntimesOutput(result) }],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: "text",
text: `# ❌ Error\n\n**Tool:** ${name}\n**Error:** ${error.message}`,
},
],
isError: true,
};
}
});
}
async makeRequest(endpoint, params = {}) {
const url = `${this.baseUrl}${endpoint}`;
const headers = {
"DD-API-KEY": this.apiKey,
"DD-APPLICATION-KEY": this.appKey,
"Content-Type": "application/json",
};
try {
const response = await axios.get(url, { headers, params });
return response.data;
} catch (error) {
if (error.response) {
throw new Error(
`HTTP ${error.response.status}: ${JSON.stringify(error.response.data)}`
);
}
throw error;
}
}
async getDashboards({ limit, author, filterDeleted }) {
const params = {};
if (author) params.author = author;
if (filterDeleted !== undefined) params.filter_deleted = filterDeleted;
const data = await this.makeRequest("/api/v1/dashboard", params);
// Apply limit if specified
if (limit && data.dashboards) {
data.dashboards = data.dashboards.slice(0, limit);
}
return data;
}
async getMetrics({ query, limit }) {
const params = {};
if (query) params.q = query;
const data = await this.makeRequest("/api/v1/search", params);
// Apply limit if specified and metrics exist
if (limit && data.results && data.results.metrics) {
data.results.metrics = data.results.metrics.slice(0, limit);
}
return data;
}
async getMonitors({ limit, groupStates, tags }) {
const params = {};
if (groupStates) params.group_states = groupStates.join(",");
if (tags) params.tags = tags;
const data = await this.makeRequest("/api/v1/monitor", params);
// Apply limit if specified
if (limit && Array.isArray(data)) {
return data.slice(0, limit);
}
return data;
}
async searchLogs({ query, timeFrom, timeTo, limit }) {
const requestBody = {
filter: {
query: query || "*",
from: timeFrom,
to: timeTo,
},
sort: "-timestamp",
page: {
limit: Math.min(limit || 100, 1000)
}
};
try {
const response = await axios.post(
`https://api.${this.site}/api/v2/logs/events/search`,
requestBody,
{
headers: {
"DD-API-KEY": this.apiKey,
"DD-APPLICATION-KEY": this.appKey,
"Content-Type": "application/json",
},
}
);
return response.data;
} catch (error) {
if (error.response) {
throw new Error(
`HTTP ${error.response.status}: ${JSON.stringify(error.response.data)}`
);
}
throw error;
}
}
async getEvents({ start, end, priority, sources, tags }) {
const params = { start, end };
if (priority) params.priority = priority;
if (sources) params.sources = sources;
if (tags) params.tags = tags;
return await this.makeRequest("/api/v1/events", params);
}
async queryMetrics({ query, from, to }) {
const params = { query, from, to };
return await this.makeRequest("/api/v1/query", params);
}
async aggregateLogs({ filter, compute, groupBy, options }) {
const requestBody = { filter, compute, groupBy, options };
try {
const response = await axios.post(
`https://api.${this.site}/api/v2/logs/analytics/aggregate`,
requestBody,
{
headers: {
"DD-API-KEY": this.apiKey,
"DD-APPLICATION-KEY": this.appKey,
"Content-Type": "application/json",
},
}
);
return response.data;
} catch (error) {
if (error.response) {
throw new Error(
`HTTP ${error.response.status}: ${JSON.stringify(error.response.data)}`
);
}
throw error;
}
}
async getHosts({ filter, sortField, sortDirection, count, start, includeHostsMetadata, includeMutedHostsData }) {
const params = {};
if (filter) params.filter = filter;
if (sortField) params.sort_field = sortField;
if (sortDirection) params.sort_dir = sortDirection;
if (count) params.count = count;
if (start) params.start = start;
if (includeHostsMetadata) params.include_hosts_metadata = includeHostsMetadata;
if (includeMutedHostsData) params.include_muted_hosts_data = includeMutedHostsData;
return await this.makeRequest("/api/v1/hosts", params);
}
async getContainers({ filter, sort, count, start, groupBy }) {
const params = {};
if (filter) params.filter = filter;
if (sort) params.sort = sort;
if (count) params.count = count;
if (start) params.start = start;
if (groupBy) params.group_by = groupBy;
return await this.makeRequest("/api/v2/containers", params);
}
async getProcesses({ search, tags, from, to, pageLimit, pageCursor }) {
const params = {};
if (search) params.search = search;
if (tags && tags.length > 0) params.tags = tags.join(",");
if (from) params.from = from;
if (to) params.to = to;
if (pageLimit) params.page_limit = pageLimit;
if (pageCursor) params.page_cursor = pageCursor;
return await this.makeRequest("/api/v2/processes", params);
}
async getRUMApplications({ pageSize, pageNumber, sort, filter }) {
const params = {};
if (pageSize) params.page_size = pageSize;
if (pageNumber) params.page_number = pageNumber;
if (sort) params.sort = sort;
if (filter) params.filter = filter;
return await this.makeRequest("/api/v2/rum/applications", params);
}
async searchRUMEvents({ filter, options, page, sort }) {
const requestBody = { filter, options, page, sort };
try {
const response = await axios.post(
`https://api.${this.site}/api/v2/rum/events/search`,
requestBody,
{
headers: {
"DD-API-KEY": this.apiKey,
"DD-APPLICATION-KEY": this.appKey,
"Content-Type": "application/json",
},
}
);
return response.data;
} catch (error) {
if (error.response) {
throw new Error(
`HTTP ${error.response.status}: ${JSON.stringify(error.response.data)}`
);
}
throw error;
}
}
async getServiceMap({ env, service, start, end }) {
const params = { env };
if (service) params.service = service;
if (start) params.start = start;
if (end) params.end = end;
return await this.makeRequest("/api/v1/apm/service-map", params);
}
async getSyntheticsTests({ pageSize, pageNumber, tags }) {
const params = {};
if (pageSize) params.page_size = pageSize;
if (pageNumber) params.page_number = pageNumber;
if (tags && tags.length > 0) params.tags = tags.join(",");
return await this.makeRequest("/api/v1/synthetics/tests", params);
}
async getSecurityRules({ pageSize, pageNumber, filter }) {
const params = {};
if (pageSize) params.page_size = pageSize;
if (pageNumber) params.page_number = pageNumber;
if (filter) params.filter = filter;
return await this.makeRequest("/api/v2/security_monitoring/rules", params);
}
async getIncidents({ includeArchived, pageSize, pageOffset, query, limit }) {
const params = {};
if (includeArchived !== undefined) params.include_archived = includeArchived;
if (pageSize) params.page_size = pageSize;
if (pageOffset) params.page_offset = pageOffset;
if (query) params.query = query;
if (limit) params.limit = limit;
return await this.makeRequest("/api/v2/incidents", params);
}
async getSLOs({ ids, query, tagsQuery, metricsQuery, limit, offset }) {
const params = {};
if (ids && ids.length > 0) params.ids = ids.join(",");
if (query) params.query = query;
if (tagsQuery) params.tags_query = tagsQuery;
if (metricsQuery) params.metrics_query = metricsQuery;
if (limit) params.limit = limit;
if (offset) params.offset = offset;
return await this.makeRequest("/api/v1/slo", params);
}
async getUsage({ startHr, endHr, includeOrgDetails }) {
const params = { start_hr: startHr };
if (endHr) params.end_hr = endHr;
if (includeOrgDetails !== undefined) params.include_org_details = includeOrgDetails;
return await this.makeRequest("/api/v1/usage/summary", params);
}
async getAuditLogs({ filter, sort, page }) {
const requestBody = { filter, sort, page };
try {
const response = await axios.post(
`https://api.${this.site}/api/v2/audit/events/search`,
requestBody,
{
headers: {
"DD-API-KEY": this.apiKey,
"DD-APPLICATION-KEY": this.appKey,
"Content-Type": "application/json",
},
}
);
return response.data;
} catch (error) {
if (error.response) {
throw new Error(
`HTTP ${error.response.status}: ${JSON.stringify(error.response.data)}`
);
}
throw error;
}
}
async getNotebooks({ authorHandle, excludeAuthorHandle, start, count, sortField, sortDirection, query, includeCells, isTemplate, type }) {
const params = {};
if (authorHandle) params.author_handle = authorHandle;
if (excludeAuthorHandle) params.exclude_author_handle = excludeAuthorHandle;
if (start) params.start = start;
if (count) params.count = count;
if (sortField) params.sort_field = sortField;
if (sortDirection) params.sort_dir = sortDirection;
if (query) params.query = query;
if (includeCells !== undefined) params.include_cells = includeCells;
if (isTemplate !== undefined) params.is_template = isTemplate;
if (type) params.type = type;
return await this.makeRequest("/api/v1/notebooks", params);
}
async getDowntimes({ currentOnly, withCreator }) {
const params = {};
if (currentOnly !== undefined) params.current_only = currentOnly;
if (withCreator !== undefined) params.with_creator = withCreator;
return await this.makeRequest("/api/v1/downtime", params);
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error("Datadog MCP Server running on stdio");
}
}
// Parse command line arguments
function parseArgs() {
const args = process.argv.slice(2);
const config = {
apiKey: process.env.DD_API_KEY,
appKey: process.env.DD_APP_KEY,
site: process.env.DD_SITE || "datadoghq.com",
};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
switch (arg) {
case "--apiKey":
config.apiKey = args[++i];
break;
case "--appKey":
config.appKey = args[++i];
break;
case "--site":
config.site = args[++i];
break;
case "--help":
console.log(`
Usage: datadog-mcp [options]
Options:
--apiKey <key> Datadog API Key (or set DD_API_KEY env var)
--appKey <key> Datadog Application Key (or set DD_APP_KEY env var)
--site <site> Datadog site (default: datadoghq.com)
--help Show this help message
Example:
datadog-mcp --apiKey your_api_key --appKey your_app_key
`);
process.exit(0);
break;
}
}
if (!config.apiKey) {
console.error("Error: DD_API_KEY is required.");
console.error("Please provide it via command line argument or .env file.");
console.error(" Command line: --apiKey=your_api_key");
process.exit(1);
}
if (!config.appKey) {
console.error("Error: DD_APP_KEY is required.");
console.error("Please provide it via command line argument or .env file.");
console.error(" Command line: --appKey=your_app_key");
process.exit(1);
}
return config;
}
// Main execution
async function main() {
try {
const config = parseArgs();
const server = new DatadogMCPServer(config.apiKey, config.appKey, config.site);
await server.run();
} catch (error) {
console.error("Fatal error running server:", error);
process.exit(1);
}
}
if (import.meta.url === `file://${process.argv[1]}`) {
main();
}