datadog-mcp 1.0.5 → 1.0.7

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/dist/index.js CHANGED
@@ -454,9 +454,9 @@ async function searchMonitors(api, query, limits, site) {
454
454
  datadog_url: buildMonitorsListUrl(query, site)
455
455
  };
456
456
  }
457
- function normalizeMonitorConfig(config) {
457
+ function normalizeMonitorConfig(config, isUpdate = false) {
458
458
  const normalized = { ...config };
459
- if (!normalized.name && !normalized.type && !normalized.query) {
459
+ if (!isUpdate && !normalized.name && !normalized.type && !normalized.query) {
460
460
  throw new Error("Monitor config requires at least 'name', 'type', and 'query' fields");
461
461
  }
462
462
  if (normalized.options && typeof normalized.options === "object") {
@@ -515,7 +515,7 @@ async function createMonitor(api, config) {
515
515
  }
516
516
  async function updateMonitor(api, id, config) {
517
517
  const monitorId = Number.parseInt(id, 10);
518
- const body = normalizeMonitorConfig(config);
518
+ const body = normalizeMonitorConfig(config, true);
519
519
  const monitor = await api.updateMonitor({ monitorId, body });
520
520
  return {
521
521
  success: true,
@@ -673,6 +673,17 @@ function normalizeDashboardConfig(config) {
673
673
  if (!normalized.layoutType) {
674
674
  throw new Error("Dashboard config requires 'layoutType' (e.g., 'ordered', 'free')");
675
675
  }
676
+ if (normalized.tags && Array.isArray(normalized.tags)) {
677
+ const invalidTags = normalized.tags.filter((tag) => {
678
+ if (typeof tag !== "string") return true;
679
+ return !tag.startsWith("team:");
680
+ });
681
+ if (invalidTags.length > 0) {
682
+ throw new Error(
683
+ `Dashboard tags must use 'team:' prefix. Invalid tags: ${invalidTags.join(", ")}. Example: ["team:operations", "team:frontend"]`
684
+ );
685
+ }
686
+ }
676
687
  return normalized;
677
688
  }
678
689
  async function createDashboard(api, config) {
@@ -706,7 +717,7 @@ async function deleteDashboard(api, id) {
706
717
  function registerDashboardsTool(server, api, limits, readOnly = false, _site = "datadoghq.com") {
707
718
  server.tool(
708
719
  "dashboards",
709
- "Access Datadog dashboards and visualizations. Actions: list (filter by name/tags), get, create, update, delete. Use for: finding existing views, team dashboards, understanding what is monitored.",
720
+ 'Access Datadog dashboards and visualizations. Actions: list (filter by name/tags), get, create, update, delete. Use for: finding existing views, team dashboards, understanding what is monitored. NOTE: Dashboard tags must use "team:" prefix (e.g., ["team:operations"]).',
710
721
  InputSchema2,
711
722
  async ({ action, id, name, tags, limit, config }) => {
712
723
  try {
@@ -3258,11 +3269,33 @@ async function getDowntime(api, id) {
3258
3269
  downtime: response.data ? formatDowntime(response.data) : null
3259
3270
  };
3260
3271
  }
3272
+ function normalizeDowntimeConfig(config) {
3273
+ const normalized = { ...config };
3274
+ if (normalized.schedule && typeof normalized.schedule === "object") {
3275
+ const schedule = { ...normalized.schedule };
3276
+ const isRecurring = "duration" in schedule && "rrule" in schedule;
3277
+ if (!isRecurring) {
3278
+ if (schedule.start && typeof schedule.start === "string") {
3279
+ schedule.start = new Date(schedule.start);
3280
+ }
3281
+ if (schedule.end && typeof schedule.end === "string") {
3282
+ schedule.end = new Date(schedule.end);
3283
+ }
3284
+ if (schedule.timezone && !normalized.displayTimezone) {
3285
+ normalized.displayTimezone = schedule.timezone;
3286
+ }
3287
+ delete schedule.timezone;
3288
+ }
3289
+ normalized.schedule = schedule;
3290
+ }
3291
+ return normalized;
3292
+ }
3261
3293
  async function createDowntime(api, config) {
3294
+ const normalizedConfig = normalizeDowntimeConfig(config);
3262
3295
  const body = {
3263
3296
  data: {
3264
3297
  type: "downtime",
3265
- attributes: config
3298
+ attributes: normalizedConfig
3266
3299
  }
3267
3300
  };
3268
3301
  const response = await api.createDowntime({ body });
@@ -3272,11 +3305,12 @@ async function createDowntime(api, config) {
3272
3305
  };
3273
3306
  }
3274
3307
  async function updateDowntime(api, id, config) {
3308
+ const normalizedConfig = normalizeDowntimeConfig(config);
3275
3309
  const body = {
3276
3310
  data: {
3277
3311
  type: "downtime",
3278
3312
  id,
3279
- attributes: config
3313
+ attributes: normalizedConfig
3280
3314
  }
3281
3315
  };
3282
3316
  const response = await api.updateDowntime({ downtimeId: id, body });