datadog-mcp 2.0.2 → 4.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.
- package/README.md +58 -6
- package/dist/index.js +206 -90
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -37,12 +37,12 @@ var configSchema = z.object({
|
|
|
37
37
|
host: z.string().default("localhost")
|
|
38
38
|
}).default({}),
|
|
39
39
|
limits: z.object({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
defaultLimit: z.number().default(50),
|
|
41
|
+
// Fallback when AI doesn't specify limit
|
|
42
|
+
defaultLogLines: z.number().default(200),
|
|
43
|
+
// Fallback when AI doesn't specify log limit
|
|
44
|
+
defaultMetricDataPoints: z.number().default(1e3),
|
|
45
|
+
// Fallback for timeseries data points
|
|
46
46
|
defaultTimeRangeHours: z.number().default(24)
|
|
47
47
|
}).default({}),
|
|
48
48
|
features: z.object({
|
|
@@ -115,9 +115,9 @@ function loadConfig() {
|
|
|
115
115
|
host: args.strings.host ?? process.env.MCP_HOST ?? "localhost"
|
|
116
116
|
},
|
|
117
117
|
limits: {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
defaultLimit: Number.parseInt(process.env.MCP_DEFAULT_LIMIT ?? "50", 10),
|
|
119
|
+
defaultLogLines: Number.parseInt(process.env.MCP_DEFAULT_LOG_LINES ?? "200", 10),
|
|
120
|
+
defaultMetricDataPoints: Number.parseInt(process.env.MCP_DEFAULT_METRIC_POINTS ?? "1000", 10),
|
|
121
121
|
defaultTimeRangeHours: Number.parseInt(process.env.MCP_DEFAULT_TIME_RANGE ?? "24", 10)
|
|
122
122
|
},
|
|
123
123
|
features: {
|
|
@@ -394,7 +394,7 @@ var InputSchema = {
|
|
|
394
394
|
groupStates: z2.array(z2.string()).optional().describe(
|
|
395
395
|
"Filter multi-alert monitors by group states (e.g., alert by host). Does NOT filter by overall monitor status. Values: alert, warn, no data, ok"
|
|
396
396
|
),
|
|
397
|
-
limit: z2.number().optional().describe("Maximum number of monitors to return"),
|
|
397
|
+
limit: z2.number().min(1).optional().describe("Maximum number of monitors to return (default: 50)"),
|
|
398
398
|
config: z2.record(z2.unknown()).optional().describe("Monitor configuration (for create/update)"),
|
|
399
399
|
message: z2.string().optional().describe("Mute message (for mute action)"),
|
|
400
400
|
end: z2.number().optional().describe("Mute end timestamp (for mute action)")
|
|
@@ -415,7 +415,7 @@ function formatMonitor(m, site = "datadoghq.com") {
|
|
|
415
415
|
};
|
|
416
416
|
}
|
|
417
417
|
async function listMonitors(api, params, limits, site) {
|
|
418
|
-
const effectiveLimit =
|
|
418
|
+
const effectiveLimit = params.limit ?? limits.defaultLimit;
|
|
419
419
|
const response = await api.listMonitors({
|
|
420
420
|
name: params.name,
|
|
421
421
|
tags: params.tags?.join(","),
|
|
@@ -451,7 +451,7 @@ async function getMonitor(api, id, site) {
|
|
|
451
451
|
}
|
|
452
452
|
async function searchMonitors(api, query, limits, site) {
|
|
453
453
|
const response = await api.searchMonitors({ query });
|
|
454
|
-
const monitors = (response.monitors ?? []).
|
|
454
|
+
const monitors = (response.monitors ?? []).map((m) => ({
|
|
455
455
|
id: m.id ?? 0,
|
|
456
456
|
name: m.name ?? "",
|
|
457
457
|
status: String(m.status ?? "unknown"),
|
|
@@ -632,7 +632,7 @@ var InputSchema2 = {
|
|
|
632
632
|
id: z3.string().optional().describe("Dashboard ID (required for get/update/delete)"),
|
|
633
633
|
name: z3.string().optional().describe("Filter by name"),
|
|
634
634
|
tags: z3.array(z3.string()).optional().describe("Filter by tags"),
|
|
635
|
-
limit: z3.number().optional().describe("Maximum number of dashboards to return"),
|
|
635
|
+
limit: z3.number().min(1).optional().describe("Maximum number of dashboards to return (default: 50)"),
|
|
636
636
|
config: z3.record(z3.unknown()).optional().describe("Dashboard configuration (for create/update)")
|
|
637
637
|
};
|
|
638
638
|
function formatDashboardSummary(d) {
|
|
@@ -648,7 +648,7 @@ function formatDashboardSummary(d) {
|
|
|
648
648
|
};
|
|
649
649
|
}
|
|
650
650
|
async function listDashboards(api, params, limits) {
|
|
651
|
-
const effectiveLimit =
|
|
651
|
+
const effectiveLimit = params.limit ?? limits.defaultLimit;
|
|
652
652
|
const response = await api.listDashboards({
|
|
653
653
|
filterShared: false
|
|
654
654
|
});
|
|
@@ -914,7 +914,7 @@ var InputSchema3 = {
|
|
|
914
914
|
host: z4.string().optional().describe("Filter by host"),
|
|
915
915
|
status: z4.enum(["error", "warn", "info", "debug"]).optional().describe("Filter by log status/level"),
|
|
916
916
|
indexes: z4.array(z4.string()).optional().describe("Log indexes to search"),
|
|
917
|
-
limit: z4.number().optional().describe("Maximum number of logs to return"),
|
|
917
|
+
limit: z4.number().min(1).optional().describe("Maximum number of logs to return (default: 200)"),
|
|
918
918
|
sort: z4.enum(["timestamp", "-timestamp"]).optional().describe("Sort order"),
|
|
919
919
|
sample: z4.enum(["first", "spread", "diverse"]).optional().describe(
|
|
920
920
|
"Sampling mode: first (chronological, default), spread (evenly across time range), diverse (distinct message patterns)"
|
|
@@ -1009,6 +1009,7 @@ function diverseSample(items, limit) {
|
|
|
1009
1009
|
patterns: seen.size
|
|
1010
1010
|
};
|
|
1011
1011
|
}
|
|
1012
|
+
var SAMPLE_DIVERSITY_MULTIPLIER = 4;
|
|
1012
1013
|
function buildLogQuery(params) {
|
|
1013
1014
|
const parts = [];
|
|
1014
1015
|
if (params.query) {
|
|
@@ -1050,10 +1051,10 @@ async function searchLogs(api, params, limits, site) {
|
|
|
1050
1051
|
host: params.host,
|
|
1051
1052
|
status: params.status
|
|
1052
1053
|
});
|
|
1053
|
-
const requestedLimit = params.limit ?? limits.
|
|
1054
|
+
const requestedLimit = params.limit ?? limits.defaultLogLines;
|
|
1054
1055
|
const sampleMode = params.sample ?? "first";
|
|
1055
|
-
const fetchMultiplier = sampleMode === "first" ? 1 :
|
|
1056
|
-
const fetchLimit =
|
|
1056
|
+
const fetchMultiplier = sampleMode === "first" ? 1 : SAMPLE_DIVERSITY_MULTIPLIER;
|
|
1057
|
+
const fetchLimit = requestedLimit * fetchMultiplier;
|
|
1057
1058
|
const body = {
|
|
1058
1059
|
filter: {
|
|
1059
1060
|
query: fullQuery,
|
|
@@ -1226,7 +1227,10 @@ var InputSchema4 = {
|
|
|
1226
1227
|
to: z5.string().optional().describe('End time (ONLY for query action). Same formats as "from".'),
|
|
1227
1228
|
metric: z5.string().optional().describe("Metric name (for metadata action)"),
|
|
1228
1229
|
tag: z5.string().optional().describe("Filter by tag"),
|
|
1229
|
-
limit: z5.number().optional().describe("Maximum number of results (for search/list)")
|
|
1230
|
+
limit: z5.number().min(1).optional().describe("Maximum number of results (for search/list, default: 50)"),
|
|
1231
|
+
pointLimit: z5.number().min(1).optional().describe(
|
|
1232
|
+
"Maximum data points per timeseries (for query action). AI controls resolution vs token usage (default: 1000)."
|
|
1233
|
+
)
|
|
1230
1234
|
};
|
|
1231
1235
|
async function queryMetrics(api, params, limits, site) {
|
|
1232
1236
|
const defaultFrom = hoursAgo(limits.defaultTimeRangeHours);
|
|
@@ -1242,7 +1246,7 @@ async function queryMetrics(api, params, limits, site) {
|
|
|
1242
1246
|
});
|
|
1243
1247
|
const series = (response.series ?? []).map((s) => ({
|
|
1244
1248
|
metric: s.metric ?? "",
|
|
1245
|
-
points: (s.pointlist ?? []).slice(0, limits.
|
|
1249
|
+
points: (s.pointlist ?? []).slice(0, params.pointLimit ?? limits.defaultMetricDataPoints).map((p) => ({
|
|
1246
1250
|
timestamp: p[0] ?? 0,
|
|
1247
1251
|
value: p[1] ?? 0
|
|
1248
1252
|
})),
|
|
@@ -1269,20 +1273,20 @@ async function searchMetrics(api, params, limits) {
|
|
|
1269
1273
|
});
|
|
1270
1274
|
const allMetrics = response.metrics ?? [];
|
|
1271
1275
|
const lowerQuery = params.query.toLowerCase();
|
|
1272
|
-
const filtered = allMetrics.filter((name) => name.toLowerCase().includes(lowerQuery)).slice(0, params.limit ?? limits.
|
|
1276
|
+
const filtered = allMetrics.filter((name) => name.toLowerCase().includes(lowerQuery)).slice(0, params.limit ?? limits.defaultLimit);
|
|
1273
1277
|
return {
|
|
1274
1278
|
metrics: filtered,
|
|
1275
1279
|
total: filtered.length,
|
|
1276
1280
|
searchedFrom: allMetrics.length
|
|
1277
1281
|
};
|
|
1278
1282
|
}
|
|
1279
|
-
async function listMetrics(api, params,
|
|
1283
|
+
async function listMetrics(api, params, _limits) {
|
|
1280
1284
|
const response = await api.listActiveMetrics({
|
|
1281
1285
|
from: hoursAgo(24),
|
|
1282
1286
|
host: void 0,
|
|
1283
1287
|
tagFilter: params.query
|
|
1284
1288
|
});
|
|
1285
|
-
const metrics =
|
|
1289
|
+
const metrics = response.metrics ?? [];
|
|
1286
1290
|
return {
|
|
1287
1291
|
metrics,
|
|
1288
1292
|
total: response.metrics?.length ?? 0
|
|
@@ -1315,7 +1319,7 @@ APM METRICS (auto-generated from traces):
|
|
|
1315
1319
|
- trace.{service}.duration - Latency (use avg:, p95:, max:)
|
|
1316
1320
|
Example: max:trace.{service}.request.duration{*}`,
|
|
1317
1321
|
InputSchema4,
|
|
1318
|
-
async ({ action, query, from, to, metric, limit }) => {
|
|
1322
|
+
async ({ action, query, from, to, metric, limit, pointLimit }) => {
|
|
1319
1323
|
try {
|
|
1320
1324
|
switch (action) {
|
|
1321
1325
|
case "query": {
|
|
@@ -1326,7 +1330,8 @@ Example: max:trace.{service}.request.duration{*}`,
|
|
|
1326
1330
|
{
|
|
1327
1331
|
query: metricsQuery,
|
|
1328
1332
|
from,
|
|
1329
|
-
to
|
|
1333
|
+
to,
|
|
1334
|
+
pointLimit
|
|
1330
1335
|
},
|
|
1331
1336
|
limits,
|
|
1332
1337
|
site
|
|
@@ -1401,7 +1406,7 @@ var InputSchema5 = {
|
|
|
1401
1406
|
),
|
|
1402
1407
|
errorType: z6.string().optional().describe('Filter by error type (grep-like). Example: "TimeoutError", "ConnectionRefused"'),
|
|
1403
1408
|
errorMessage: z6.string().optional().describe('Filter by error message (grep-like). Example: "timeout", "connection refused"'),
|
|
1404
|
-
limit: z6.number().optional().describe("Maximum number of results"),
|
|
1409
|
+
limit: z6.number().min(1).optional().describe("Maximum number of results (default: 50)"),
|
|
1405
1410
|
sort: z6.enum(["timestamp", "-timestamp"]).optional().describe("Sort order"),
|
|
1406
1411
|
groupBy: z6.array(z6.string()).optional().describe('Fields to group by (for aggregate). Example: ["resource_name", "status"]')
|
|
1407
1412
|
};
|
|
@@ -1541,7 +1546,7 @@ async function searchTraces(api, params, limits, site) {
|
|
|
1541
1546
|
},
|
|
1542
1547
|
sort: params.sort === "timestamp" ? "timestamp" : "-timestamp",
|
|
1543
1548
|
page: {
|
|
1544
|
-
limit:
|
|
1549
|
+
limit: params.limit ?? limits.defaultLimit
|
|
1545
1550
|
}
|
|
1546
1551
|
}
|
|
1547
1552
|
}
|
|
@@ -1633,7 +1638,7 @@ async function listApmServices(api, params, limits) {
|
|
|
1633
1638
|
groupBy: [
|
|
1634
1639
|
{
|
|
1635
1640
|
facet: "service",
|
|
1636
|
-
limit: limits.
|
|
1641
|
+
limit: limits.defaultLimit
|
|
1637
1642
|
}
|
|
1638
1643
|
]
|
|
1639
1644
|
}
|
|
@@ -1756,7 +1761,8 @@ var ActionSchema6 = z7.enum([
|
|
|
1756
1761
|
"aggregate",
|
|
1757
1762
|
"top",
|
|
1758
1763
|
"timeseries",
|
|
1759
|
-
"incidents"
|
|
1764
|
+
"incidents",
|
|
1765
|
+
"discover"
|
|
1760
1766
|
]);
|
|
1761
1767
|
var InputSchema6 = {
|
|
1762
1768
|
action: ActionSchema6.describe("Action to perform"),
|
|
@@ -1767,7 +1773,7 @@ var InputSchema6 = {
|
|
|
1767
1773
|
priority: z7.enum(["normal", "low"]).optional().describe("Event priority"),
|
|
1768
1774
|
sources: z7.array(z7.string()).optional().describe("Filter by sources"),
|
|
1769
1775
|
tags: z7.array(z7.string()).optional().describe("Filter by tags"),
|
|
1770
|
-
limit: z7.number().optional().describe("Maximum number of events to return"),
|
|
1776
|
+
limit: z7.number().min(1).optional().describe("Maximum number of events to return (default: 50)"),
|
|
1771
1777
|
title: z7.string().optional().describe("Event title (for create)"),
|
|
1772
1778
|
text: z7.string().optional().describe("Event text (for create)"),
|
|
1773
1779
|
alertType: z7.enum(["error", "warning", "info", "success"]).optional().describe("Alert type (for create)"),
|
|
@@ -1778,7 +1784,14 @@ var InputSchema6 = {
|
|
|
1778
1784
|
// Phase 2: Incidents deduplication
|
|
1779
1785
|
dedupeWindow: z7.string().optional().describe("Deduplication window for incidents: 5m, 15m, 1h (default: 5m)"),
|
|
1780
1786
|
// Phase 3: Monitor enrichment
|
|
1781
|
-
enrich: z7.boolean().optional().describe("Enrich events with monitor metadata (slower, adds monitor details)")
|
|
1787
|
+
enrich: z7.boolean().optional().describe("Enrich events with monitor metadata (slower, adds monitor details)"),
|
|
1788
|
+
// Context tag extraction for top action
|
|
1789
|
+
contextTags: z7.array(z7.string()).optional().describe(
|
|
1790
|
+
"Tag prefixes for context breakdown in top action (default: queue, service, ingress, pod_name, kube_namespace, kube_container_name)"
|
|
1791
|
+
),
|
|
1792
|
+
maxEvents: z7.number().min(1).max(1e4).optional().describe(
|
|
1793
|
+
"Maximum events to fetch for grouping in top action (default: 10000). Higher = more accurate but slower"
|
|
1794
|
+
)
|
|
1782
1795
|
};
|
|
1783
1796
|
function extractMonitorInfo(title) {
|
|
1784
1797
|
const priorityMatch = title.match(/^\[P(\d+)\]\s*/);
|
|
@@ -1901,8 +1914,50 @@ function formatEventV2(e) {
|
|
|
1901
1914
|
} : void 0
|
|
1902
1915
|
};
|
|
1903
1916
|
}
|
|
1917
|
+
function findFirstContextTag(tags, prefixes) {
|
|
1918
|
+
for (const tag of tags) {
|
|
1919
|
+
const colonIndex = tag.indexOf(":");
|
|
1920
|
+
if (colonIndex > 0) {
|
|
1921
|
+
const prefix = tag.substring(0, colonIndex);
|
|
1922
|
+
if (prefixes.has(prefix)) {
|
|
1923
|
+
return tag;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
return null;
|
|
1928
|
+
}
|
|
1929
|
+
async function discoverTagsV2(api, params, limits, site) {
|
|
1930
|
+
const result = await searchEventsV2(
|
|
1931
|
+
api,
|
|
1932
|
+
{
|
|
1933
|
+
...params,
|
|
1934
|
+
limit: 200
|
|
1935
|
+
},
|
|
1936
|
+
limits,
|
|
1937
|
+
site
|
|
1938
|
+
);
|
|
1939
|
+
const prefixSet = /* @__PURE__ */ new Set();
|
|
1940
|
+
for (const event of result.events) {
|
|
1941
|
+
for (const tag of event.tags) {
|
|
1942
|
+
if (tag.includes(":")) {
|
|
1943
|
+
const prefix = tag.split(":")[0];
|
|
1944
|
+
if (prefix) {
|
|
1945
|
+
prefixSet.add(prefix);
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
return {
|
|
1951
|
+
tagPrefixes: Array.from(prefixSet).sort((a, b) => a.localeCompare(b)),
|
|
1952
|
+
sampleSize: result.events.length,
|
|
1953
|
+
meta: {
|
|
1954
|
+
from: result.meta.from,
|
|
1955
|
+
to: result.meta.to
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1904
1959
|
async function listEventsV1(api, params, limits) {
|
|
1905
|
-
const effectiveLimit =
|
|
1960
|
+
const effectiveLimit = params.limit ?? limits.defaultLimit;
|
|
1906
1961
|
const defaultFrom = hoursAgo(limits.defaultTimeRangeHours);
|
|
1907
1962
|
const defaultTo = now();
|
|
1908
1963
|
const response = await api.listEvents({
|
|
@@ -1986,7 +2041,7 @@ async function searchEventsV2(api, params, limits, site) {
|
|
|
1986
2041
|
tags: params.tags,
|
|
1987
2042
|
priority: params.priority
|
|
1988
2043
|
});
|
|
1989
|
-
const effectiveLimit =
|
|
2044
|
+
const effectiveLimit = params.limit ?? limits.defaultLimit;
|
|
1990
2045
|
const body = {
|
|
1991
2046
|
filter: {
|
|
1992
2047
|
query: fullQuery,
|
|
@@ -2090,34 +2145,79 @@ async function aggregateEventsV2(api, params, limits, site) {
|
|
|
2090
2145
|
};
|
|
2091
2146
|
}
|
|
2092
2147
|
async function topEventsV2(api, params, limits, site) {
|
|
2148
|
+
if (params.contextTags !== void 0) {
|
|
2149
|
+
if (!Array.isArray(params.contextTags)) {
|
|
2150
|
+
throw new Error("contextTags must be an array");
|
|
2151
|
+
}
|
|
2152
|
+
if (params.contextTags.some((tag) => typeof tag !== "string" || tag.trim() === "")) {
|
|
2153
|
+
throw new Error("contextTags must be an array of non-empty strings");
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2093
2156
|
const effectiveQuery = params.query ?? "source:alert";
|
|
2094
2157
|
const effectiveTags = params.tags ?? ["source:alert"];
|
|
2095
|
-
const result = await
|
|
2158
|
+
const result = await searchEventsV2(
|
|
2096
2159
|
api,
|
|
2097
2160
|
{
|
|
2098
|
-
...params,
|
|
2099
2161
|
query: effectiveQuery,
|
|
2162
|
+
from: params.from,
|
|
2163
|
+
to: params.to,
|
|
2164
|
+
sources: params.sources,
|
|
2100
2165
|
tags: effectiveTags,
|
|
2101
|
-
|
|
2102
|
-
limit: params.limit ?? 10
|
|
2166
|
+
limit: params.maxEvents ?? 1e4
|
|
2103
2167
|
},
|
|
2104
2168
|
limits,
|
|
2105
2169
|
site
|
|
2106
2170
|
);
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2171
|
+
const monitorGroups = /* @__PURE__ */ new Map();
|
|
2172
|
+
for (const event of result.events) {
|
|
2173
|
+
const monitorName = event.monitorInfo?.name ?? event.title;
|
|
2174
|
+
const monitorId = event.monitorId ?? 0;
|
|
2175
|
+
const key = `${monitorId}|${monitorName}`;
|
|
2176
|
+
let monitorGroup = monitorGroups.get(key);
|
|
2177
|
+
if (!monitorGroup) {
|
|
2178
|
+
monitorGroup = { name: monitorName, monitorId, events: [] };
|
|
2179
|
+
monitorGroups.set(key, monitorGroup);
|
|
2180
|
+
}
|
|
2181
|
+
monitorGroup.events.push(event);
|
|
2182
|
+
}
|
|
2183
|
+
const contextPrefixes = new Set(
|
|
2184
|
+
params.contextTags ?? [
|
|
2185
|
+
"queue",
|
|
2186
|
+
"service",
|
|
2187
|
+
"ingress",
|
|
2188
|
+
"pod_name",
|
|
2189
|
+
"kube_namespace",
|
|
2190
|
+
"kube_container_name"
|
|
2191
|
+
]
|
|
2192
|
+
);
|
|
2193
|
+
const monitors = Array.from(monitorGroups.values()).map((monitor) => {
|
|
2194
|
+
const contextGroups = /* @__PURE__ */ new Map();
|
|
2195
|
+
for (const event of monitor.events) {
|
|
2196
|
+
const contextTag = findFirstContextTag(event.tags, contextPrefixes);
|
|
2197
|
+
if (contextTag) {
|
|
2198
|
+
contextGroups.set(contextTag, (contextGroups.get(contextTag) || 0) + 1);
|
|
2118
2199
|
}
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2200
|
+
}
|
|
2201
|
+
return {
|
|
2202
|
+
name: monitor.name,
|
|
2203
|
+
monitor_id: monitor.monitorId,
|
|
2204
|
+
total_count: monitor.events.length,
|
|
2205
|
+
by_context: Array.from(contextGroups.entries()).map(([context, count]) => ({ context, count })).sort((a, b) => b.count - a.count)
|
|
2206
|
+
// Sort by count desc
|
|
2207
|
+
};
|
|
2208
|
+
}).filter((monitor) => monitor.by_context.length > 0);
|
|
2209
|
+
const topMonitors = monitors.sort((a, b) => b.total_count - a.total_count).slice(0, params.limit ?? 10).map((m, i) => ({ rank: i + 1, ...m }));
|
|
2210
|
+
return {
|
|
2211
|
+
top: topMonitors,
|
|
2212
|
+
meta: {
|
|
2213
|
+
query: effectiveQuery,
|
|
2214
|
+
from: result.meta.from,
|
|
2215
|
+
to: result.meta.to,
|
|
2216
|
+
totalMonitors: monitorGroups.size,
|
|
2217
|
+
totalEvents: result.events.length,
|
|
2218
|
+
contextPrefixes,
|
|
2219
|
+
datadog_url: result.meta.datadog_url
|
|
2220
|
+
}
|
|
2121
2221
|
};
|
|
2122
2222
|
}
|
|
2123
2223
|
function parseIntervalToMs(interval) {
|
|
@@ -2388,6 +2488,7 @@ async function enrichWithMonitorMetadata(events, monitorsApi) {
|
|
|
2388
2488
|
if (monitor) {
|
|
2389
2489
|
enriched.monitorMetadata = {
|
|
2390
2490
|
id: monitor.id ?? 0,
|
|
2491
|
+
name: monitor.name ?? "",
|
|
2391
2492
|
type: String(monitor.type ?? ""),
|
|
2392
2493
|
message: monitor.message ?? "",
|
|
2393
2494
|
tags: monitor.tags ?? [],
|
|
@@ -2405,16 +2506,15 @@ async function enrichWithMonitorMetadata(events, monitorsApi) {
|
|
|
2405
2506
|
function registerEventsTool(server, apiV1, apiV2, monitorsApi, limits, readOnly = false, site = "datadoghq.com") {
|
|
2406
2507
|
server.tool(
|
|
2407
2508
|
"events",
|
|
2408
|
-
`Track Datadog events. Actions: list, get, create, search, aggregate, top, timeseries, incidents.
|
|
2409
|
-
|
|
2410
|
-
Filters: query (text search), sources, tags, priority, time range.
|
|
2411
|
-
Use for: monitor alerts, deployments, incidents, change tracking.
|
|
2509
|
+
`Track Datadog events. Actions: list, get, create, search, aggregate, top, timeseries, incidents, discover.
|
|
2510
|
+
For monitor alerts, use tags: ["source:alert"].
|
|
2412
2511
|
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2512
|
+
top: Returns monitors with context breakdown. Example: {name, monitor_id, total_count, by_context: [{context: "queue:X", count: 30}]}
|
|
2513
|
+
discover: Returns available tag prefixes from events.
|
|
2514
|
+
aggregate: Custom groupBy, returns pipe-delimited keys.
|
|
2515
|
+
search: Full event details.
|
|
2516
|
+
timeseries: Time-bucketed trends with interval.
|
|
2517
|
+
incidents: Deduplicate alerts with dedupeWindow.`,
|
|
2418
2518
|
InputSchema6,
|
|
2419
2519
|
async ({
|
|
2420
2520
|
action,
|
|
@@ -2433,7 +2533,8 @@ Use enrich:true with search to get monitor metadata (slower).`,
|
|
|
2433
2533
|
cursor,
|
|
2434
2534
|
interval,
|
|
2435
2535
|
dedupeWindow,
|
|
2436
|
-
enrich
|
|
2536
|
+
enrich,
|
|
2537
|
+
contextTags
|
|
2437
2538
|
}) => {
|
|
2438
2539
|
try {
|
|
2439
2540
|
checkReadOnly(action, readOnly);
|
|
@@ -2520,8 +2621,23 @@ Use enrich:true with search to get monitor metadata (slower).`,
|
|
|
2520
2621
|
to,
|
|
2521
2622
|
sources,
|
|
2522
2623
|
tags,
|
|
2523
|
-
|
|
2524
|
-
|
|
2624
|
+
limit,
|
|
2625
|
+
contextTags
|
|
2626
|
+
},
|
|
2627
|
+
limits,
|
|
2628
|
+
site
|
|
2629
|
+
)
|
|
2630
|
+
);
|
|
2631
|
+
case "discover":
|
|
2632
|
+
return toolResult(
|
|
2633
|
+
await discoverTagsV2(
|
|
2634
|
+
apiV2,
|
|
2635
|
+
{
|
|
2636
|
+
query,
|
|
2637
|
+
from,
|
|
2638
|
+
to,
|
|
2639
|
+
sources,
|
|
2640
|
+
tags
|
|
2525
2641
|
},
|
|
2526
2642
|
limits,
|
|
2527
2643
|
site
|
|
@@ -2580,7 +2696,7 @@ var InputSchema7 = {
|
|
|
2580
2696
|
id: z8.string().optional().describe("Incident ID (required for get/update/delete)"),
|
|
2581
2697
|
query: z8.string().optional().describe("Search query (for search action)"),
|
|
2582
2698
|
status: z8.enum(["active", "stable", "resolved"]).optional().describe("Filter by status (for list)"),
|
|
2583
|
-
limit: z8.number().optional().describe("Maximum number of incidents to return"),
|
|
2699
|
+
limit: z8.number().min(1).optional().describe("Maximum number of incidents to return (default: 50)"),
|
|
2584
2700
|
config: z8.record(z8.unknown()).optional().describe(
|
|
2585
2701
|
"Incident configuration (for create/update). Create requires: title. Update can modify: title, status, severity, fields."
|
|
2586
2702
|
)
|
|
@@ -2610,7 +2726,7 @@ function formatIncident(i) {
|
|
|
2610
2726
|
};
|
|
2611
2727
|
}
|
|
2612
2728
|
async function listIncidents(api, params, limits) {
|
|
2613
|
-
const effectiveLimit =
|
|
2729
|
+
const effectiveLimit = params.limit ?? limits.defaultLimit;
|
|
2614
2730
|
const response = await api.listIncidents({
|
|
2615
2731
|
pageSize: effectiveLimit
|
|
2616
2732
|
});
|
|
@@ -2633,7 +2749,7 @@ async function getIncident(api, id) {
|
|
|
2633
2749
|
async function searchIncidents(api, query, limits) {
|
|
2634
2750
|
const response = await api.searchIncidents({
|
|
2635
2751
|
query,
|
|
2636
|
-
pageSize: limits.
|
|
2752
|
+
pageSize: limits.defaultLimit
|
|
2637
2753
|
});
|
|
2638
2754
|
const incidents = (response.data?.attributes?.incidents ?? []).map(
|
|
2639
2755
|
(i) => ({
|
|
@@ -2732,7 +2848,7 @@ var InputSchema8 = {
|
|
|
2732
2848
|
ids: z9.array(z9.string()).optional().describe("Multiple SLO IDs (for list with specific IDs)"),
|
|
2733
2849
|
query: z9.string().optional().describe("Search query (for list)"),
|
|
2734
2850
|
tags: z9.array(z9.string()).optional().describe("Filter by tags (for list)"),
|
|
2735
|
-
limit: z9.number().optional().describe("Maximum number of SLOs to return"),
|
|
2851
|
+
limit: z9.number().min(1).optional().describe("Maximum number of SLOs to return (default: 50)"),
|
|
2736
2852
|
config: z9.record(z9.unknown()).optional().describe("SLO configuration (for create/update). Must include type, name, thresholds."),
|
|
2737
2853
|
from: z9.string().optional().describe('Start time for history (ISO 8601 or relative like "7d", "1w")'),
|
|
2738
2854
|
to: z9.string().optional().describe("End time for history (ISO 8601 or relative, default: now)")
|
|
@@ -2759,7 +2875,7 @@ function formatSlo(s) {
|
|
|
2759
2875
|
};
|
|
2760
2876
|
}
|
|
2761
2877
|
async function listSlos(api, params, limits) {
|
|
2762
|
-
const effectiveLimit =
|
|
2878
|
+
const effectiveLimit = params.limit ?? limits.defaultLimit;
|
|
2763
2879
|
const response = await api.listSLOs({
|
|
2764
2880
|
ids: params.ids?.join(","),
|
|
2765
2881
|
query: params.query,
|
|
@@ -2910,7 +3026,7 @@ var InputSchema9 = {
|
|
|
2910
3026
|
testType: z10.enum(["api", "browser"]).optional().describe("Test type filter (for list) or type for create"),
|
|
2911
3027
|
locations: z10.array(z10.string()).optional().describe("Filter by locations (for list)"),
|
|
2912
3028
|
tags: z10.array(z10.string()).optional().describe("Filter by tags (for list)"),
|
|
2913
|
-
limit: z10.number().optional().describe("Maximum number of tests to return"),
|
|
3029
|
+
limit: z10.number().min(1).optional().describe("Maximum number of tests to return (default: 50)"),
|
|
2914
3030
|
config: z10.record(z10.unknown()).optional().describe(
|
|
2915
3031
|
"Test configuration (for create/update). Includes: name, type, config, options, locations, message."
|
|
2916
3032
|
)
|
|
@@ -2929,7 +3045,7 @@ function formatTest(t) {
|
|
|
2929
3045
|
};
|
|
2930
3046
|
}
|
|
2931
3047
|
async function listTests(api, params, limits) {
|
|
2932
|
-
const effectiveLimit =
|
|
3048
|
+
const effectiveLimit = params.limit ?? limits.defaultLimit;
|
|
2933
3049
|
const response = await api.listTests({
|
|
2934
3050
|
pageSize: effectiveLimit
|
|
2935
3051
|
});
|
|
@@ -3129,7 +3245,7 @@ var InputSchema10 = {
|
|
|
3129
3245
|
action: ActionSchema10.describe("Action to perform"),
|
|
3130
3246
|
filter: z11.string().optional().describe('Filter hosts by name, alias, or tag (e.g., "env:prod")'),
|
|
3131
3247
|
from: z11.number().optional().describe("Starting offset for pagination"),
|
|
3132
|
-
count: z11.number().optional().describe("Number of hosts to return"),
|
|
3248
|
+
count: z11.number().min(1).optional().describe("Number of hosts to return"),
|
|
3133
3249
|
sortField: z11.string().optional().describe('Field to sort by (e.g., "apps", "cpu", "name")'),
|
|
3134
3250
|
sortDir: z11.enum(["asc", "desc"]).optional().describe("Sort direction"),
|
|
3135
3251
|
hostName: z11.string().optional().describe("Host name (required for mute/unmute)"),
|
|
@@ -3158,7 +3274,7 @@ async function listHosts(api, params, limits) {
|
|
|
3158
3274
|
const response = await api.listHosts({
|
|
3159
3275
|
filter: params.filter,
|
|
3160
3276
|
from: params.from,
|
|
3161
|
-
count:
|
|
3277
|
+
count: params.count ?? limits.defaultLimit,
|
|
3162
3278
|
sortField: params.sortField,
|
|
3163
3279
|
sortDir: params.sortDir
|
|
3164
3280
|
});
|
|
@@ -3252,7 +3368,7 @@ var InputSchema11 = {
|
|
|
3252
3368
|
id: z12.string().optional().describe("Downtime ID (required for get/update/cancel)"),
|
|
3253
3369
|
monitorId: z12.number().optional().describe("Monitor ID (required for listByMonitor)"),
|
|
3254
3370
|
currentOnly: z12.boolean().optional().describe("Only return active downtimes (for list)"),
|
|
3255
|
-
limit: z12.number().optional().describe("Maximum number of downtimes to return"),
|
|
3371
|
+
limit: z12.number().min(1).optional().describe("Maximum number of downtimes to return (default: 50)"),
|
|
3256
3372
|
config: z12.record(z12.unknown()).optional().describe("Downtime configuration (for create/update). Must include scope and schedule.")
|
|
3257
3373
|
};
|
|
3258
3374
|
function extractMonitorIdentifier(mi) {
|
|
@@ -3281,7 +3397,7 @@ function formatDowntime(d) {
|
|
|
3281
3397
|
};
|
|
3282
3398
|
}
|
|
3283
3399
|
async function listDowntimes(api, params, limits) {
|
|
3284
|
-
const effectiveLimit =
|
|
3400
|
+
const effectiveLimit = params.limit ?? limits.defaultLimit;
|
|
3285
3401
|
const response = await api.listDowntimes({
|
|
3286
3402
|
currentOnly: params.currentOnly
|
|
3287
3403
|
});
|
|
@@ -3386,9 +3502,9 @@ function formatMonitorDowntime(d) {
|
|
|
3386
3502
|
end: attrs?.end ? new Date(attrs.end).toISOString() : null
|
|
3387
3503
|
};
|
|
3388
3504
|
}
|
|
3389
|
-
async function listMonitorDowntimes(api, monitorId,
|
|
3505
|
+
async function listMonitorDowntimes(api, monitorId, _limits) {
|
|
3390
3506
|
const response = await api.listMonitorDowntimes({ monitorId });
|
|
3391
|
-
const downtimes = (response.data ?? []).
|
|
3507
|
+
const downtimes = (response.data ?? []).map(formatMonitorDowntime);
|
|
3392
3508
|
return {
|
|
3393
3509
|
downtimes,
|
|
3394
3510
|
monitorId,
|
|
@@ -3447,7 +3563,7 @@ var InputSchema12 = {
|
|
|
3447
3563
|
to: z13.string().optional().describe('End time (ISO 8601, relative like "now", or precise timestamp)'),
|
|
3448
3564
|
type: z13.enum(["all", "view", "action", "error", "long_task", "resource"]).optional().describe("RUM event type filter"),
|
|
3449
3565
|
sort: z13.enum(["timestamp", "-timestamp"]).optional().describe("Sort order for events"),
|
|
3450
|
-
limit: z13.number().optional().describe("Maximum number of events to return"),
|
|
3566
|
+
limit: z13.number().min(1).optional().describe("Maximum number of events to return (default: 50)"),
|
|
3451
3567
|
groupBy: z13.array(z13.string()).optional().describe('Fields to group by for aggregation (e.g., ["@view.url_path", "@session.type"])'),
|
|
3452
3568
|
compute: z13.object({
|
|
3453
3569
|
aggregation: z13.enum(["count", "cardinality", "avg", "sum", "min", "max", "percentile"]).optional(),
|
|
@@ -3549,7 +3665,7 @@ async function searchEvents(api, params, limits, site) {
|
|
|
3549
3665
|
filterFrom: new Date(fromTime * 1e3),
|
|
3550
3666
|
filterTo: new Date(toTime * 1e3),
|
|
3551
3667
|
sort: params.sort === "timestamp" ? "timestamp" : "-timestamp",
|
|
3552
|
-
pageLimit:
|
|
3668
|
+
pageLimit: params.limit ?? limits.defaultLimit
|
|
3553
3669
|
});
|
|
3554
3670
|
const events = (response.data ?? []).map(formatEvent);
|
|
3555
3671
|
return {
|
|
@@ -3766,7 +3882,7 @@ async function getSessionWaterfall(api, params, limits, site) {
|
|
|
3766
3882
|
const response = await api.listRUMEvents({
|
|
3767
3883
|
filterQuery: queryParts.join(" "),
|
|
3768
3884
|
sort: "timestamp",
|
|
3769
|
-
pageLimit:
|
|
3885
|
+
pageLimit: limits.defaultLimit
|
|
3770
3886
|
});
|
|
3771
3887
|
const events = (response.data ?? []).map(formatWaterfallEvent);
|
|
3772
3888
|
const summary = {
|
|
@@ -3852,7 +3968,7 @@ var InputSchema13 = {
|
|
|
3852
3968
|
to: z14.string().optional().describe('End time (ISO 8601, relative like "now")'),
|
|
3853
3969
|
severity: z14.enum(["info", "low", "medium", "high", "critical"]).optional().describe("Filter by severity"),
|
|
3854
3970
|
status: z14.enum(["open", "under_review", "archived"]).optional().describe("Filter signals by status"),
|
|
3855
|
-
pageSize: z14.number().optional().describe("Number of results to return"),
|
|
3971
|
+
pageSize: z14.number().min(1).optional().describe("Number of results to return"),
|
|
3856
3972
|
pageCursor: z14.string().optional().describe("Cursor for pagination")
|
|
3857
3973
|
};
|
|
3858
3974
|
function formatRule(rule) {
|
|
@@ -3894,7 +4010,7 @@ function formatSignal(signal) {
|
|
|
3894
4010
|
}
|
|
3895
4011
|
async function listRules(api, params, limits) {
|
|
3896
4012
|
const response = await api.listSecurityMonitoringRules({
|
|
3897
|
-
pageSize:
|
|
4013
|
+
pageSize: params.pageSize ?? limits.defaultLimit,
|
|
3898
4014
|
pageNumber: 0
|
|
3899
4015
|
});
|
|
3900
4016
|
const rules = (response.data ?? []).map(formatRule);
|
|
@@ -3931,7 +4047,7 @@ async function searchSignals(api, params, limits) {
|
|
|
3931
4047
|
to: new Date(toTime * 1e3)
|
|
3932
4048
|
},
|
|
3933
4049
|
page: {
|
|
3934
|
-
limit:
|
|
4050
|
+
limit: params.pageSize ?? limits.defaultLimit,
|
|
3935
4051
|
cursor: params.pageCursor
|
|
3936
4052
|
},
|
|
3937
4053
|
sort: "timestamp"
|
|
@@ -3960,7 +4076,7 @@ async function listFindings(api, params, limits) {
|
|
|
3960
4076
|
to: /* @__PURE__ */ new Date()
|
|
3961
4077
|
},
|
|
3962
4078
|
page: {
|
|
3963
|
-
limit:
|
|
4079
|
+
limit: params.pageSize ?? limits.defaultLimit,
|
|
3964
4080
|
cursor: params.pageCursor
|
|
3965
4081
|
}
|
|
3966
4082
|
}
|
|
@@ -4037,7 +4153,7 @@ var InputSchema14 = {
|
|
|
4037
4153
|
end: z15.number().optional()
|
|
4038
4154
|
}).optional().describe("Time configuration for notebook"),
|
|
4039
4155
|
status: z15.enum(["published"]).optional().describe("Notebook status"),
|
|
4040
|
-
pageSize: z15.number().optional().describe("Number of notebooks to return"),
|
|
4156
|
+
pageSize: z15.number().min(1).optional().describe("Number of notebooks to return"),
|
|
4041
4157
|
pageNumber: z15.number().optional().describe("Page number for pagination")
|
|
4042
4158
|
};
|
|
4043
4159
|
function formatNotebookSummary(nb) {
|
|
@@ -4092,8 +4208,8 @@ async function listNotebooks(api, params, limits) {
|
|
|
4092
4208
|
authorHandle: params.authorHandle,
|
|
4093
4209
|
excludeAuthorHandle: params.excludeAuthorHandle,
|
|
4094
4210
|
includeCells: params.includeCells ?? false,
|
|
4095
|
-
count:
|
|
4096
|
-
start: (params.pageNumber ?? 0) * (params.pageSize ?? limits.
|
|
4211
|
+
count: params.pageSize ?? limits.defaultLimit,
|
|
4212
|
+
start: (params.pageNumber ?? 0) * (params.pageSize ?? limits.defaultLimit)
|
|
4097
4213
|
});
|
|
4098
4214
|
const notebooks = (response.data ?? []).map(formatNotebookSummary);
|
|
4099
4215
|
return {
|
|
@@ -4310,7 +4426,7 @@ var InputSchema15 = {
|
|
|
4310
4426
|
id: z16.string().optional().describe("User ID (required for get action)"),
|
|
4311
4427
|
filter: z16.string().optional().describe("Filter users by name or email"),
|
|
4312
4428
|
status: z16.enum(["Active", "Pending", "Disabled"]).optional().describe("Filter by user status"),
|
|
4313
|
-
pageSize: z16.number().optional().describe("Number of users to return per page"),
|
|
4429
|
+
pageSize: z16.number().min(1).optional().describe("Number of users to return per page"),
|
|
4314
4430
|
pageNumber: z16.number().optional().describe("Page number for pagination")
|
|
4315
4431
|
};
|
|
4316
4432
|
function formatUser(user) {
|
|
@@ -4338,7 +4454,7 @@ async function listUsers(api, params, limits) {
|
|
|
4338
4454
|
const response = await api.listUsers({
|
|
4339
4455
|
filter: params.filter,
|
|
4340
4456
|
filterStatus: params.status,
|
|
4341
|
-
pageSize:
|
|
4457
|
+
pageSize: params.pageSize ?? limits.defaultLimit,
|
|
4342
4458
|
pageNumber: params.pageNumber ?? 0
|
|
4343
4459
|
});
|
|
4344
4460
|
const users = (response.data ?? []).map(formatUser);
|
|
@@ -4392,7 +4508,7 @@ var InputSchema16 = {
|
|
|
4392
4508
|
action: ActionSchema16.describe("Action to perform"),
|
|
4393
4509
|
id: z17.string().optional().describe("Team ID (required for get/members actions)"),
|
|
4394
4510
|
filter: z17.string().optional().describe("Filter teams by name"),
|
|
4395
|
-
pageSize: z17.number().optional().describe("Number of teams to return per page"),
|
|
4511
|
+
pageSize: z17.number().min(1).optional().describe("Number of teams to return per page"),
|
|
4396
4512
|
pageNumber: z17.number().optional().describe("Page number for pagination")
|
|
4397
4513
|
};
|
|
4398
4514
|
function formatTeam(team) {
|
|
@@ -4426,7 +4542,7 @@ function formatTeamMember(member) {
|
|
|
4426
4542
|
async function listTeams(api, params, limits) {
|
|
4427
4543
|
const response = await api.listTeams({
|
|
4428
4544
|
filterKeyword: params.filter,
|
|
4429
|
-
pageSize:
|
|
4545
|
+
pageSize: params.pageSize ?? limits.defaultLimit,
|
|
4430
4546
|
pageNumber: params.pageNumber ?? 0
|
|
4431
4547
|
});
|
|
4432
4548
|
const teams = (response.data ?? []).map(formatTeam);
|
|
@@ -4449,7 +4565,7 @@ async function getTeam(api, teamId) {
|
|
|
4449
4565
|
async function getTeamMembers(api, teamId, limits) {
|
|
4450
4566
|
const response = await api.getTeamMemberships({
|
|
4451
4567
|
teamId,
|
|
4452
|
-
pageSize: limits.
|
|
4568
|
+
pageSize: limits.defaultLimit
|
|
4453
4569
|
});
|
|
4454
4570
|
const members = (response.data ?? []).map(formatTeamMember);
|
|
4455
4571
|
return {
|