dd-mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,110 @@
1
+ import { z } from "zod";
2
+ import { getClient } from "../datadog/client.js";
3
+
4
+ export const searchLogsSchema = z.object({
5
+ query: z.string().describe("Datadog logs query string (e.g., 'service:my-app status:error')"),
6
+ from: z.string().describe("Start time in ISO 8601 format or relative time (e.g., 'now-1h')"),
7
+ to: z.string().describe("End time in ISO 8601 format or relative time (e.g., 'now')"),
8
+ limit: z.number().optional().default(50).describe("Maximum number of logs to return (default: 50, max: 1000)"),
9
+ sort: z.enum(["timestamp", "-timestamp"]).optional().default("-timestamp").describe("Sort order: 'timestamp' (oldest first) or '-timestamp' (newest first)"),
10
+ index: z.string().optional().describe("Log index to search (optional)"),
11
+ });
12
+
13
+ export type SearchLogsInput = z.infer<typeof searchLogsSchema>;
14
+
15
+ interface LogsSearchResponse {
16
+ data: Array<{
17
+ id: string;
18
+ type: string;
19
+ attributes: {
20
+ timestamp: string;
21
+ message: string;
22
+ status: string;
23
+ service: string;
24
+ host: string;
25
+ tags: string[];
26
+ attributes: Record<string, unknown>;
27
+ };
28
+ }>;
29
+ meta?: {
30
+ page?: {
31
+ after?: string;
32
+ };
33
+ };
34
+ }
35
+
36
+ export async function searchLogs(input: SearchLogsInput): Promise<string> {
37
+ const client = getClient();
38
+
39
+ const body = {
40
+ filter: {
41
+ query: input.query,
42
+ from: input.from,
43
+ to: input.to,
44
+ ...(input.index && { indexes: [input.index] }),
45
+ },
46
+ sort: input.sort,
47
+ page: {
48
+ limit: Math.min(input.limit, 1000),
49
+ },
50
+ };
51
+
52
+ const response = await client.post<LogsSearchResponse>(
53
+ "/api/v2/logs/events/search",
54
+ body
55
+ );
56
+
57
+ const logs = response.data.map((log) => ({
58
+ id: log.id,
59
+ timestamp: log.attributes.timestamp,
60
+ message: log.attributes.message,
61
+ status: log.attributes.status,
62
+ service: log.attributes.service,
63
+ host: log.attributes.host,
64
+ tags: log.attributes.tags,
65
+ }));
66
+
67
+ return JSON.stringify({ logs, count: logs.length }, null, 2);
68
+ }
69
+
70
+ export const getLogSchema = z.object({
71
+ logId: z.string().describe("The unique ID of the log to retrieve"),
72
+ });
73
+
74
+ export type GetLogInput = z.infer<typeof getLogSchema>;
75
+
76
+ interface LogResponse {
77
+ data: {
78
+ id: string;
79
+ type: string;
80
+ attributes: {
81
+ timestamp: string;
82
+ message: string;
83
+ status: string;
84
+ service: string;
85
+ host: string;
86
+ tags: string[];
87
+ attributes: Record<string, unknown>;
88
+ };
89
+ };
90
+ }
91
+
92
+ export async function getLog(input: GetLogInput): Promise<string> {
93
+ const client = getClient();
94
+
95
+ const response = await client.get<LogResponse>(
96
+ `/api/v2/logs/events/${input.logId}`
97
+ );
98
+
99
+ const log = response.data;
100
+ return JSON.stringify({
101
+ id: log.id,
102
+ timestamp: log.attributes.timestamp,
103
+ message: log.attributes.message,
104
+ status: log.attributes.status,
105
+ service: log.attributes.service,
106
+ host: log.attributes.host,
107
+ tags: log.attributes.tags,
108
+ attributes: log.attributes.attributes,
109
+ }, null, 2);
110
+ }
@@ -0,0 +1,252 @@
1
+ import { z } from "zod";
2
+ import { getClient } from "../datadog/client.js";
3
+
4
+ interface Monitor {
5
+ id: number;
6
+ name: string;
7
+ type: string;
8
+ query: string;
9
+ message: string;
10
+ tags: string[];
11
+ overall_state: string;
12
+ created: string;
13
+ modified: string;
14
+ options?: Record<string, unknown>;
15
+ }
16
+
17
+ export const listMonitorsSchema = z.object({
18
+ name: z.string().optional().describe("Filter monitors by name (partial match)"),
19
+ tags: z.string().optional().describe("Comma-separated list of tags to filter by"),
20
+ monitorTags: z.string().optional().describe("Comma-separated list of monitor tags to filter by"),
21
+ });
22
+
23
+ export type ListMonitorsInput = z.infer<typeof listMonitorsSchema>;
24
+
25
+ export async function listMonitors(input: ListMonitorsInput): Promise<string> {
26
+ const client = getClient();
27
+
28
+ const params = new URLSearchParams();
29
+ if (input.name) params.append("name", input.name);
30
+ if (input.tags) params.append("tags", input.tags);
31
+ if (input.monitorTags) params.append("monitor_tags", input.monitorTags);
32
+
33
+ const queryString = params.toString();
34
+ const path = `/api/v1/monitor${queryString ? `?${queryString}` : ""}`;
35
+
36
+ const response = await client.get<Monitor[]>(path);
37
+
38
+ const monitors = response.map((m) => ({
39
+ id: m.id,
40
+ name: m.name,
41
+ type: m.type,
42
+ state: m.overall_state,
43
+ tags: m.tags,
44
+ }));
45
+
46
+ return JSON.stringify({ monitors, count: monitors.length }, null, 2);
47
+ }
48
+
49
+ export const getMonitorSchema = z.object({
50
+ monitorId: z.number().describe("The ID of the monitor to retrieve"),
51
+ });
52
+
53
+ export type GetMonitorInput = z.infer<typeof getMonitorSchema>;
54
+
55
+ export async function getMonitor(input: GetMonitorInput): Promise<string> {
56
+ const client = getClient();
57
+ const response = await client.get<Monitor>(`/api/v1/monitor/${input.monitorId}`);
58
+
59
+ return JSON.stringify({
60
+ id: response.id,
61
+ name: response.name,
62
+ type: response.type,
63
+ query: response.query,
64
+ message: response.message,
65
+ tags: response.tags,
66
+ state: response.overall_state,
67
+ created: response.created,
68
+ modified: response.modified,
69
+ options: response.options,
70
+ }, null, 2);
71
+ }
72
+
73
+ export const createMonitorSchema = z.object({
74
+ name: z.string().describe("Name of the monitor"),
75
+ type: z.enum([
76
+ "metric alert",
77
+ "service check",
78
+ "event alert",
79
+ "query alert",
80
+ "composite",
81
+ "log alert",
82
+ "process alert",
83
+ "rum alert",
84
+ "trace-analytics alert",
85
+ "slo alert",
86
+ "event-v2 alert",
87
+ "audit alert",
88
+ "ci-pipelines alert",
89
+ "ci-tests alert",
90
+ "error-tracking alert",
91
+ ]).describe("Type of the monitor"),
92
+ query: z.string().describe("The monitor query"),
93
+ message: z.string().describe("Message to include with notifications"),
94
+ tags: z.array(z.string()).optional().describe("Tags to associate with the monitor"),
95
+ priority: z.number().optional().describe("Priority of the monitor (1-5)"),
96
+ options: z.object({
97
+ thresholds: z.object({
98
+ critical: z.number().optional(),
99
+ warning: z.number().optional(),
100
+ ok: z.number().optional(),
101
+ }).optional(),
102
+ notifyNoData: z.boolean().optional(),
103
+ noDataTimeframe: z.number().optional(),
104
+ renotifyInterval: z.number().optional(),
105
+ }).optional().describe("Monitor options"),
106
+ });
107
+
108
+ export type CreateMonitorInput = z.infer<typeof createMonitorSchema>;
109
+
110
+ export async function createMonitor(input: CreateMonitorInput): Promise<string> {
111
+ const client = getClient();
112
+
113
+ const body = {
114
+ name: input.name,
115
+ type: input.type,
116
+ query: input.query,
117
+ message: input.message,
118
+ tags: input.tags || [],
119
+ priority: input.priority,
120
+ options: input.options ? {
121
+ thresholds: input.options.thresholds,
122
+ notify_no_data: input.options.notifyNoData,
123
+ no_data_timeframe: input.options.noDataTimeframe,
124
+ renotify_interval: input.options.renotifyInterval,
125
+ } : undefined,
126
+ };
127
+
128
+ const response = await client.post<Monitor>("/api/v1/monitor", body);
129
+
130
+ return JSON.stringify({
131
+ id: response.id,
132
+ name: response.name,
133
+ type: response.type,
134
+ message: "Monitor created successfully",
135
+ }, null, 2);
136
+ }
137
+
138
+ export const updateMonitorSchema = z.object({
139
+ monitorId: z.number().describe("The ID of the monitor to update"),
140
+ name: z.string().optional().describe("New name for the monitor"),
141
+ query: z.string().optional().describe("New query for the monitor"),
142
+ message: z.string().optional().describe("New message for notifications"),
143
+ tags: z.array(z.string()).optional().describe("New tags for the monitor"),
144
+ priority: z.number().optional().describe("New priority (1-5)"),
145
+ options: z.object({
146
+ thresholds: z.object({
147
+ critical: z.number().optional(),
148
+ warning: z.number().optional(),
149
+ ok: z.number().optional(),
150
+ }).optional(),
151
+ notifyNoData: z.boolean().optional(),
152
+ noDataTimeframe: z.number().optional(),
153
+ renotifyInterval: z.number().optional(),
154
+ }).optional().describe("Updated monitor options"),
155
+ });
156
+
157
+ export type UpdateMonitorInput = z.infer<typeof updateMonitorSchema>;
158
+
159
+ export async function updateMonitor(input: UpdateMonitorInput): Promise<string> {
160
+ const client = getClient();
161
+
162
+ const body: Record<string, unknown> = {};
163
+ if (input.name) body.name = input.name;
164
+ if (input.query) body.query = input.query;
165
+ if (input.message) body.message = input.message;
166
+ if (input.tags) body.tags = input.tags;
167
+ if (input.priority) body.priority = input.priority;
168
+ if (input.options) {
169
+ body.options = {
170
+ thresholds: input.options.thresholds,
171
+ notify_no_data: input.options.notifyNoData,
172
+ no_data_timeframe: input.options.noDataTimeframe,
173
+ renotify_interval: input.options.renotifyInterval,
174
+ };
175
+ }
176
+
177
+ const response = await client.put<Monitor>(
178
+ `/api/v1/monitor/${input.monitorId}`,
179
+ body
180
+ );
181
+
182
+ return JSON.stringify({
183
+ id: response.id,
184
+ name: response.name,
185
+ message: "Monitor updated successfully",
186
+ }, null, 2);
187
+ }
188
+
189
+ export const deleteMonitorSchema = z.object({
190
+ monitorId: z.number().describe("The ID of the monitor to delete"),
191
+ });
192
+
193
+ export type DeleteMonitorInput = z.infer<typeof deleteMonitorSchema>;
194
+
195
+ export async function deleteMonitor(input: DeleteMonitorInput): Promise<string> {
196
+ const client = getClient();
197
+ await client.delete(`/api/v1/monitor/${input.monitorId}`);
198
+
199
+ return JSON.stringify({
200
+ monitorId: input.monitorId,
201
+ message: "Monitor deleted successfully",
202
+ }, null, 2);
203
+ }
204
+
205
+ export const muteMonitorSchema = z.object({
206
+ monitorId: z.number().describe("The ID of the monitor to mute"),
207
+ scope: z.string().optional().describe("Scope to apply the mute to (e.g., 'host:myhost')"),
208
+ end: z.number().optional().describe("POSIX timestamp when the mute should end"),
209
+ });
210
+
211
+ export type MuteMonitorInput = z.infer<typeof muteMonitorSchema>;
212
+
213
+ export async function muteMonitor(input: MuteMonitorInput): Promise<string> {
214
+ const client = getClient();
215
+
216
+ const body: Record<string, unknown> = {};
217
+ if (input.scope) body.scope = input.scope;
218
+ if (input.end) body.end = input.end;
219
+
220
+ await client.post(`/api/v1/monitor/${input.monitorId}/mute`, body);
221
+
222
+ return JSON.stringify({
223
+ monitorId: input.monitorId,
224
+ message: "Monitor muted successfully",
225
+ }, null, 2);
226
+ }
227
+
228
+ export const unmuteMonitorSchema = z.object({
229
+ monitorId: z.number().describe("The ID of the monitor to unmute"),
230
+ scope: z.string().optional().describe("Scope to unmute (e.g., 'host:myhost')"),
231
+ allScopes: z.boolean().optional().describe("If true, unmute all scopes"),
232
+ });
233
+
234
+ export type UnmuteMonitorInput = z.infer<typeof unmuteMonitorSchema>;
235
+
236
+ export async function unmuteMonitor(input: UnmuteMonitorInput): Promise<string> {
237
+ const client = getClient();
238
+
239
+ const params = new URLSearchParams();
240
+ if (input.scope) params.append("scope", input.scope);
241
+ if (input.allScopes) params.append("all_scopes", "true");
242
+
243
+ const queryString = params.toString();
244
+ const path = `/api/v1/monitor/${input.monitorId}/unmute${queryString ? `?${queryString}` : ""}`;
245
+
246
+ await client.post(path, {});
247
+
248
+ return JSON.stringify({
249
+ monitorId: input.monitorId,
250
+ message: "Monitor unmuted successfully",
251
+ }, null, 2);
252
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }