datadog-mcp 1.0.0 → 1.0.2
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 +2 -0
- package/dist/index.js +584 -283
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -72,7 +72,7 @@ function parseArgs() {
|
|
|
72
72
|
const nextArg = argv[i + 1];
|
|
73
73
|
if (nextArg && !nextArg.startsWith("--")) {
|
|
74
74
|
strings[argName] = nextArg;
|
|
75
|
-
i
|
|
75
|
+
i += 1;
|
|
76
76
|
} else {
|
|
77
77
|
booleans.add(argName);
|
|
78
78
|
}
|
|
@@ -98,18 +98,20 @@ function loadConfig() {
|
|
|
98
98
|
name: "datadog-mcp",
|
|
99
99
|
version: "1.0.0",
|
|
100
100
|
transport: args.strings.transport ?? process.env.MCP_TRANSPORT ?? "stdio",
|
|
101
|
-
port: parseInt(args.strings.port ?? process.env.MCP_PORT ?? "3000", 10),
|
|
101
|
+
port: Number.parseInt(args.strings.port ?? process.env.MCP_PORT ?? "3000", 10),
|
|
102
102
|
host: args.strings.host ?? process.env.MCP_HOST ?? "localhost"
|
|
103
103
|
},
|
|
104
104
|
limits: {
|
|
105
|
-
maxResults: parseInt(process.env.MCP_MAX_RESULTS ?? "100", 10),
|
|
106
|
-
maxLogLines: parseInt(process.env.MCP_MAX_LOG_LINES ?? "500", 10),
|
|
107
|
-
maxMetricDataPoints: parseInt(process.env.MCP_MAX_METRIC_POINTS ?? "1000", 10),
|
|
108
|
-
defaultTimeRangeHours: parseInt(process.env.MCP_DEFAULT_TIME_RANGE ?? "24", 10)
|
|
105
|
+
maxResults: Number.parseInt(process.env.MCP_MAX_RESULTS ?? "100", 10),
|
|
106
|
+
maxLogLines: Number.parseInt(process.env.MCP_MAX_LOG_LINES ?? "500", 10),
|
|
107
|
+
maxMetricDataPoints: Number.parseInt(process.env.MCP_MAX_METRIC_POINTS ?? "1000", 10),
|
|
108
|
+
defaultTimeRangeHours: Number.parseInt(process.env.MCP_DEFAULT_TIME_RANGE ?? "24", 10)
|
|
109
109
|
},
|
|
110
110
|
features: {
|
|
111
111
|
readOnly: args.booleans.has("read-only") || process.env.MCP_READ_ONLY === "true",
|
|
112
|
-
disabledTools: parseDisabledTools(
|
|
112
|
+
disabledTools: parseDisabledTools(
|
|
113
|
+
args.strings["disable-tools"] ?? process.env.MCP_DISABLE_TOOLS
|
|
114
|
+
)
|
|
113
115
|
}
|
|
114
116
|
};
|
|
115
117
|
return configSchema.parse(raw);
|
|
@@ -194,19 +196,31 @@ function handleDatadogError(error) {
|
|
|
194
196
|
case 400:
|
|
195
197
|
throw new McpError(ErrorCode.InvalidRequest, `Invalid request: ${message}`);
|
|
196
198
|
case 401:
|
|
197
|
-
throw new McpError(
|
|
199
|
+
throw new McpError(
|
|
200
|
+
DatadogErrorCode.Unauthorized,
|
|
201
|
+
`Authentication failed: Invalid Datadog API key or APP key`
|
|
202
|
+
);
|
|
198
203
|
case 403:
|
|
199
204
|
throw new McpError(DatadogErrorCode.Forbidden, `Authorization denied: ${message}`);
|
|
200
205
|
case 404:
|
|
201
206
|
throw new McpError(DatadogErrorCode.NotFound, `Resource not found: ${message}`);
|
|
202
207
|
case 429:
|
|
203
|
-
throw new McpError(
|
|
208
|
+
throw new McpError(
|
|
209
|
+
DatadogErrorCode.RateLimited,
|
|
210
|
+
"Rate limit exceeded. Retry after a short delay."
|
|
211
|
+
);
|
|
204
212
|
case 500:
|
|
205
213
|
case 502:
|
|
206
214
|
case 503:
|
|
207
|
-
throw new McpError(
|
|
215
|
+
throw new McpError(
|
|
216
|
+
DatadogErrorCode.ServiceUnavailable,
|
|
217
|
+
"Datadog service temporarily unavailable. Retry later."
|
|
218
|
+
);
|
|
208
219
|
default:
|
|
209
|
-
throw new McpError(
|
|
220
|
+
throw new McpError(
|
|
221
|
+
ErrorCode.InternalError,
|
|
222
|
+
`Datadog API error (${apiError.code}): ${message}`
|
|
223
|
+
);
|
|
210
224
|
}
|
|
211
225
|
}
|
|
212
226
|
throw new McpError(
|
|
@@ -341,7 +355,16 @@ function buildRumSessionUrl(applicationId, sessionId, site = "datadoghq.com") {
|
|
|
341
355
|
}
|
|
342
356
|
|
|
343
357
|
// src/tools/monitors.ts
|
|
344
|
-
var ActionSchema = z2.enum([
|
|
358
|
+
var ActionSchema = z2.enum([
|
|
359
|
+
"list",
|
|
360
|
+
"get",
|
|
361
|
+
"search",
|
|
362
|
+
"create",
|
|
363
|
+
"update",
|
|
364
|
+
"delete",
|
|
365
|
+
"mute",
|
|
366
|
+
"unmute"
|
|
367
|
+
]);
|
|
345
368
|
var InputSchema = {
|
|
346
369
|
action: ActionSchema.describe("Action to perform"),
|
|
347
370
|
id: z2.string().optional().describe("Monitor ID (required for get/update/delete/mute/unmute)"),
|
|
@@ -389,8 +412,8 @@ async function listMonitors(api, params, limits, site) {
|
|
|
389
412
|
};
|
|
390
413
|
}
|
|
391
414
|
async function getMonitor(api, id, site) {
|
|
392
|
-
const monitorId = parseInt(id, 10);
|
|
393
|
-
if (isNaN(monitorId)) {
|
|
415
|
+
const monitorId = Number.parseInt(id, 10);
|
|
416
|
+
if (Number.isNaN(monitorId)) {
|
|
394
417
|
throw new Error(`Invalid monitor ID: ${id}`);
|
|
395
418
|
}
|
|
396
419
|
const monitor = await api.getMonitor({ monitorId });
|
|
@@ -478,7 +501,7 @@ async function createMonitor(api, config) {
|
|
|
478
501
|
};
|
|
479
502
|
}
|
|
480
503
|
async function updateMonitor(api, id, config) {
|
|
481
|
-
const monitorId = parseInt(id, 10);
|
|
504
|
+
const monitorId = Number.parseInt(id, 10);
|
|
482
505
|
const body = normalizeMonitorConfig(config);
|
|
483
506
|
const monitor = await api.updateMonitor({ monitorId, body });
|
|
484
507
|
return {
|
|
@@ -487,12 +510,12 @@ async function updateMonitor(api, id, config) {
|
|
|
487
510
|
};
|
|
488
511
|
}
|
|
489
512
|
async function deleteMonitor(api, id) {
|
|
490
|
-
const monitorId = parseInt(id, 10);
|
|
513
|
+
const monitorId = Number.parseInt(id, 10);
|
|
491
514
|
await api.deleteMonitor({ monitorId });
|
|
492
515
|
return { success: true, message: `Monitor ${id} deleted` };
|
|
493
516
|
}
|
|
494
517
|
async function muteMonitor(api, id, params) {
|
|
495
|
-
const monitorId = parseInt(id, 10);
|
|
518
|
+
const monitorId = Number.parseInt(id, 10);
|
|
496
519
|
const monitor = await api.getMonitor({ monitorId });
|
|
497
520
|
await api.updateMonitor({
|
|
498
521
|
monitorId,
|
|
@@ -506,7 +529,7 @@ async function muteMonitor(api, id, params) {
|
|
|
506
529
|
return { success: true, message: `Monitor ${id} muted` };
|
|
507
530
|
}
|
|
508
531
|
async function unmuteMonitor(api, id) {
|
|
509
|
-
const monitorId = parseInt(id, 10);
|
|
532
|
+
const monitorId = Number.parseInt(id, 10);
|
|
510
533
|
const monitor = await api.getMonitor({ monitorId });
|
|
511
534
|
await api.updateMonitor({
|
|
512
535
|
monitorId,
|
|
@@ -531,7 +554,9 @@ TIP: For alert HISTORY (which monitors triggered), use the events tool with tags
|
|
|
531
554
|
checkReadOnly(action, readOnly);
|
|
532
555
|
switch (action) {
|
|
533
556
|
case "list":
|
|
534
|
-
return toolResult(
|
|
557
|
+
return toolResult(
|
|
558
|
+
await listMonitors(api, { name, tags, groupStates, limit }, limits, site)
|
|
559
|
+
);
|
|
535
560
|
case "get": {
|
|
536
561
|
const monitorId = requireParam(id, "id", "get");
|
|
537
562
|
return toolResult(await getMonitor(api, monitorId, site));
|
|
@@ -602,9 +627,7 @@ async function listDashboards(api, params, limits) {
|
|
|
602
627
|
let dashboards = response.dashboards ?? [];
|
|
603
628
|
if (params.name) {
|
|
604
629
|
const lowerName = params.name.toLowerCase();
|
|
605
|
-
dashboards = dashboards.filter(
|
|
606
|
-
(d) => d.title?.toLowerCase().includes(lowerName)
|
|
607
|
-
);
|
|
630
|
+
dashboards = dashboards.filter((d) => d.title?.toLowerCase().includes(lowerName));
|
|
608
631
|
}
|
|
609
632
|
const result = dashboards.slice(0, effectiveLimit).map(formatDashboardSummary);
|
|
610
633
|
return {
|
|
@@ -667,7 +690,7 @@ async function deleteDashboard(api, id) {
|
|
|
667
690
|
await api.deleteDashboard({ dashboardId: id });
|
|
668
691
|
return { success: true, message: `Dashboard ${id} deleted` };
|
|
669
692
|
}
|
|
670
|
-
function registerDashboardsTool(server, api, limits, readOnly = false) {
|
|
693
|
+
function registerDashboardsTool(server, api, limits, readOnly = false, _site = "datadoghq.com") {
|
|
671
694
|
server.tool(
|
|
672
695
|
"dashboards",
|
|
673
696
|
"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.",
|
|
@@ -729,9 +752,9 @@ function parseTime(input, defaultValue) {
|
|
|
729
752
|
return input;
|
|
730
753
|
}
|
|
731
754
|
const trimmed = input.trim();
|
|
732
|
-
const simpleRelativeMatch = trimmed.match(/^(\d+)(
|
|
755
|
+
const simpleRelativeMatch = trimmed.match(/^(\d+)([smhd])$/);
|
|
733
756
|
if (simpleRelativeMatch) {
|
|
734
|
-
const value = parseInt(simpleRelativeMatch[1] ?? "0", 10);
|
|
757
|
+
const value = Number.parseInt(simpleRelativeMatch[1] ?? "0", 10);
|
|
735
758
|
const unit = simpleRelativeMatch[2];
|
|
736
759
|
const nowTs = now();
|
|
737
760
|
switch (unit) {
|
|
@@ -747,13 +770,13 @@ function parseTime(input, defaultValue) {
|
|
|
747
770
|
return defaultValue;
|
|
748
771
|
}
|
|
749
772
|
}
|
|
750
|
-
const relativeWithTimeMatch = trimmed.match(/^(\d+)(
|
|
773
|
+
const relativeWithTimeMatch = trimmed.match(/^(\d+)([dh])[@\s](\d{1,2}):(\d{2})(?::(\d{2}))?$/);
|
|
751
774
|
if (relativeWithTimeMatch) {
|
|
752
|
-
const value = parseInt(relativeWithTimeMatch[1] ?? "0", 10);
|
|
775
|
+
const value = Number.parseInt(relativeWithTimeMatch[1] ?? "0", 10);
|
|
753
776
|
const unit = relativeWithTimeMatch[2];
|
|
754
|
-
const hours = parseInt(relativeWithTimeMatch[3] ?? "0", 10);
|
|
755
|
-
const minutes = parseInt(relativeWithTimeMatch[4] ?? "0", 10);
|
|
756
|
-
const seconds = parseInt(relativeWithTimeMatch[5] ?? "0", 10);
|
|
777
|
+
const hours = Number.parseInt(relativeWithTimeMatch[3] ?? "0", 10);
|
|
778
|
+
const minutes = Number.parseInt(relativeWithTimeMatch[4] ?? "0", 10);
|
|
779
|
+
const seconds = Number.parseInt(relativeWithTimeMatch[5] ?? "0", 10);
|
|
757
780
|
if (unit === "d") {
|
|
758
781
|
const date3 = startOfDayAgo(value);
|
|
759
782
|
date3.setHours(hours, minutes, seconds, 0);
|
|
@@ -767,26 +790,27 @@ function parseTime(input, defaultValue) {
|
|
|
767
790
|
const keywordMatch = trimmed.match(/^(today|yesterday)[@\s](\d{1,2}):(\d{2})(?::(\d{2}))?$/i);
|
|
768
791
|
if (keywordMatch) {
|
|
769
792
|
const keyword = keywordMatch[1]?.toLowerCase();
|
|
770
|
-
const hours = parseInt(keywordMatch[2] ?? "0", 10);
|
|
771
|
-
const minutes = parseInt(keywordMatch[3] ?? "0", 10);
|
|
772
|
-
const seconds = parseInt(keywordMatch[4] ?? "0", 10);
|
|
793
|
+
const hours = Number.parseInt(keywordMatch[2] ?? "0", 10);
|
|
794
|
+
const minutes = Number.parseInt(keywordMatch[3] ?? "0", 10);
|
|
795
|
+
const seconds = Number.parseInt(keywordMatch[4] ?? "0", 10);
|
|
773
796
|
const daysAgo = keyword === "yesterday" ? 1 : 0;
|
|
774
797
|
const date2 = startOfDayAgo(daysAgo);
|
|
775
798
|
date2.setHours(hours, minutes, seconds, 0);
|
|
776
799
|
return Math.floor(date2.getTime() / 1e3);
|
|
777
800
|
}
|
|
778
801
|
const date = new Date(trimmed);
|
|
779
|
-
if (!isNaN(date.getTime())) {
|
|
802
|
+
if (!Number.isNaN(date.getTime())) {
|
|
780
803
|
return Math.floor(date.getTime() / 1e3);
|
|
781
804
|
}
|
|
782
|
-
const ts = parseInt(trimmed, 10);
|
|
783
|
-
if (!isNaN(ts)) {
|
|
805
|
+
const ts = Number.parseInt(trimmed, 10);
|
|
806
|
+
if (!Number.isNaN(ts)) {
|
|
784
807
|
return ts;
|
|
785
808
|
}
|
|
786
809
|
return defaultValue;
|
|
787
810
|
}
|
|
788
811
|
function ensureValidTimeRange(from, to, minRangeSeconds = 60) {
|
|
789
812
|
if (from > to) {
|
|
813
|
+
;
|
|
790
814
|
[from, to] = [to, from];
|
|
791
815
|
}
|
|
792
816
|
if (to - from < minRangeSeconds) {
|
|
@@ -804,21 +828,21 @@ function parseDurationToNs(input) {
|
|
|
804
828
|
const trimmed = input.trim().toLowerCase();
|
|
805
829
|
const match = trimmed.match(/^(\d+(?:\.\d+)?)(ns|µs|us|ms|s|m|h|d|w)?$/);
|
|
806
830
|
if (!match) {
|
|
807
|
-
const raw = parseInt(trimmed, 10);
|
|
808
|
-
return isNaN(raw) ? void 0 : raw;
|
|
831
|
+
const raw = Number.parseInt(trimmed, 10);
|
|
832
|
+
return Number.isNaN(raw) ? void 0 : raw;
|
|
809
833
|
}
|
|
810
|
-
const value = parseFloat(match[1] ?? "0");
|
|
834
|
+
const value = Number.parseFloat(match[1] ?? "0");
|
|
811
835
|
const unit = match[2] ?? "ns";
|
|
812
836
|
const multipliers = {
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
837
|
+
ns: 1,
|
|
838
|
+
\u00B5s: 1e3,
|
|
839
|
+
us: 1e3,
|
|
840
|
+
ms: 1e6,
|
|
841
|
+
s: 1e9,
|
|
842
|
+
m: 6e10,
|
|
843
|
+
h: 36e11,
|
|
844
|
+
d: 864e11,
|
|
845
|
+
w: 6048e11
|
|
822
846
|
};
|
|
823
847
|
return Math.floor(value * (multipliers[unit] ?? 1));
|
|
824
848
|
}
|
|
@@ -834,10 +858,18 @@ function formatDurationNs(ns) {
|
|
|
834
858
|
var ActionSchema3 = z4.enum(["search", "aggregate"]);
|
|
835
859
|
var InputSchema3 = {
|
|
836
860
|
action: ActionSchema3.describe("Action to perform"),
|
|
837
|
-
query: z4.string().optional().describe(
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
861
|
+
query: z4.string().optional().describe(
|
|
862
|
+
'Log search query (Datadog syntax). Examples: "error", "service:my-service status:error", "error AND timeout"'
|
|
863
|
+
),
|
|
864
|
+
keyword: z4.string().optional().describe(
|
|
865
|
+
"Simple text search - finds logs containing this text (grep-like). Merged with query using AND"
|
|
866
|
+
),
|
|
867
|
+
pattern: z4.string().optional().describe(
|
|
868
|
+
'Regex pattern to match in log message (grep -E style). Example: "ERROR.*timeout|connection refused"'
|
|
869
|
+
),
|
|
870
|
+
from: z4.string().optional().describe(
|
|
871
|
+
"Start time. Formats: ISO 8601, relative (30s, 15m, 2h, 7d), precise (3d@11:45:23, yesterday@14:00)"
|
|
872
|
+
),
|
|
841
873
|
to: z4.string().optional().describe('End time. Same formats as "from". Example: from="3d@11:45:23" to="3d@12:55:34"'),
|
|
842
874
|
service: z4.string().optional().describe("Filter by service name"),
|
|
843
875
|
host: z4.string().optional().describe("Filter by host"),
|
|
@@ -845,8 +877,12 @@ var InputSchema3 = {
|
|
|
845
877
|
indexes: z4.array(z4.string()).optional().describe("Log indexes to search"),
|
|
846
878
|
limit: z4.number().optional().describe("Maximum number of logs to return"),
|
|
847
879
|
sort: z4.enum(["timestamp", "-timestamp"]).optional().describe("Sort order"),
|
|
848
|
-
sample: z4.enum(["first", "spread", "diverse"]).optional().describe(
|
|
849
|
-
|
|
880
|
+
sample: z4.enum(["first", "spread", "diverse"]).optional().describe(
|
|
881
|
+
"Sampling mode: first (chronological, default), spread (evenly across time range), diverse (distinct message patterns)"
|
|
882
|
+
),
|
|
883
|
+
compact: z4.boolean().optional().describe(
|
|
884
|
+
"Strip custom attributes for token efficiency. Keeps: id, timestamp, service, status, message (truncated), dd.trace_id, error info"
|
|
885
|
+
),
|
|
850
886
|
groupBy: z4.array(z4.string()).optional().describe("Fields to group by (for aggregate)"),
|
|
851
887
|
compute: z4.record(z4.unknown()).optional().describe("Compute operations (for aggregate)")
|
|
852
888
|
};
|
|
@@ -876,8 +912,9 @@ function formatLogCompact(log) {
|
|
|
876
912
|
const ts = attrs.timestamp;
|
|
877
913
|
timestamp = ts instanceof Date ? ts.toISOString() : new Date(String(ts)).toISOString();
|
|
878
914
|
}
|
|
879
|
-
const
|
|
880
|
-
const
|
|
915
|
+
const attrsAny = attrs;
|
|
916
|
+
const traceId = nestedAttrs["dd.trace_id"] ?? nestedAttrs["trace_id"] ?? attrsAny["dd.trace_id"] ?? "";
|
|
917
|
+
const spanId = nestedAttrs["dd.span_id"] ?? nestedAttrs["span_id"] ?? attrsAny["dd.span_id"] ?? "";
|
|
881
918
|
const errorType = nestedAttrs["error.type"] ?? nestedAttrs["error.kind"] ?? "";
|
|
882
919
|
const errorMessage = nestedAttrs["error.message"] ?? nestedAttrs["error.msg"] ?? "";
|
|
883
920
|
const fullMessage = attrs.message ?? "";
|
|
@@ -1054,35 +1091,66 @@ CORRELATION: Logs contain dd.trace_id in attributes for linking to traces and AP
|
|
|
1054
1091
|
SAMPLING: Use sample:"diverse" for error investigation (dedupes by message pattern), sample:"spread" for time distribution.
|
|
1055
1092
|
TOKEN TIP: Use compact:true to reduce payload size (strips heavy fields) when querying large volumes.`,
|
|
1056
1093
|
InputSchema3,
|
|
1057
|
-
async ({
|
|
1094
|
+
async ({
|
|
1095
|
+
action,
|
|
1096
|
+
query,
|
|
1097
|
+
keyword,
|
|
1098
|
+
pattern,
|
|
1099
|
+
service,
|
|
1100
|
+
host,
|
|
1101
|
+
status,
|
|
1102
|
+
from,
|
|
1103
|
+
to,
|
|
1104
|
+
indexes,
|
|
1105
|
+
limit,
|
|
1106
|
+
sort,
|
|
1107
|
+
sample,
|
|
1108
|
+
compact,
|
|
1109
|
+
groupBy,
|
|
1110
|
+
compute
|
|
1111
|
+
}) => {
|
|
1058
1112
|
try {
|
|
1059
1113
|
switch (action) {
|
|
1060
1114
|
case "search": {
|
|
1061
|
-
return toolResult(
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1115
|
+
return toolResult(
|
|
1116
|
+
await searchLogs(
|
|
1117
|
+
api,
|
|
1118
|
+
{
|
|
1119
|
+
query,
|
|
1120
|
+
keyword,
|
|
1121
|
+
pattern,
|
|
1122
|
+
service,
|
|
1123
|
+
host,
|
|
1124
|
+
status,
|
|
1125
|
+
from,
|
|
1126
|
+
to,
|
|
1127
|
+
indexes,
|
|
1128
|
+
limit,
|
|
1129
|
+
sort,
|
|
1130
|
+
sample,
|
|
1131
|
+
compact
|
|
1132
|
+
},
|
|
1133
|
+
limits,
|
|
1134
|
+
site
|
|
1135
|
+
)
|
|
1136
|
+
);
|
|
1076
1137
|
}
|
|
1077
1138
|
case "aggregate": {
|
|
1078
1139
|
const aggregateQuery = requireParam(query, "query", "aggregate");
|
|
1079
|
-
return toolResult(
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1140
|
+
return toolResult(
|
|
1141
|
+
await aggregateLogs(
|
|
1142
|
+
api,
|
|
1143
|
+
{
|
|
1144
|
+
query: aggregateQuery,
|
|
1145
|
+
from,
|
|
1146
|
+
to,
|
|
1147
|
+
groupBy,
|
|
1148
|
+
compute
|
|
1149
|
+
},
|
|
1150
|
+
limits,
|
|
1151
|
+
site
|
|
1152
|
+
)
|
|
1153
|
+
);
|
|
1086
1154
|
}
|
|
1087
1155
|
default:
|
|
1088
1156
|
throw new Error(`Unknown action: ${action}`);
|
|
@@ -1099,8 +1167,12 @@ import { z as z5 } from "zod";
|
|
|
1099
1167
|
var ActionSchema4 = z5.enum(["query", "search", "list", "metadata"]);
|
|
1100
1168
|
var InputSchema4 = {
|
|
1101
1169
|
action: ActionSchema4.describe("Action to perform"),
|
|
1102
|
-
query: z5.string().optional().describe(
|
|
1103
|
-
|
|
1170
|
+
query: z5.string().optional().describe(
|
|
1171
|
+
'For query: PromQL expression (e.g., "avg:system.cpu.user{*}"). For search: grep-like filter on metric names. For list: tag filter.'
|
|
1172
|
+
),
|
|
1173
|
+
from: z5.string().optional().describe(
|
|
1174
|
+
"Start time (ONLY for query action). Formats: ISO 8601, relative (30s, 15m, 2h, 7d), precise (3d@11:45:23)"
|
|
1175
|
+
),
|
|
1104
1176
|
to: z5.string().optional().describe('End time (ONLY for query action). Same formats as "from".'),
|
|
1105
1177
|
metric: z5.string().optional().describe("Metric name (for metadata action)"),
|
|
1106
1178
|
tag: z5.string().optional().describe("Filter by tag"),
|
|
@@ -1198,18 +1270,31 @@ Example: max:trace.{service}.request.duration{*}`,
|
|
|
1198
1270
|
switch (action) {
|
|
1199
1271
|
case "query": {
|
|
1200
1272
|
const metricsQuery = requireParam(query, "query", "query");
|
|
1201
|
-
return toolResult(
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1273
|
+
return toolResult(
|
|
1274
|
+
await queryMetrics(
|
|
1275
|
+
metricsV1Api,
|
|
1276
|
+
{
|
|
1277
|
+
query: metricsQuery,
|
|
1278
|
+
from,
|
|
1279
|
+
to
|
|
1280
|
+
},
|
|
1281
|
+
limits,
|
|
1282
|
+
site
|
|
1283
|
+
)
|
|
1284
|
+
);
|
|
1206
1285
|
}
|
|
1207
1286
|
case "search": {
|
|
1208
1287
|
const searchQuery = requireParam(query, "query", "search");
|
|
1209
|
-
return toolResult(
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1288
|
+
return toolResult(
|
|
1289
|
+
await searchMetrics(
|
|
1290
|
+
metricsV1Api,
|
|
1291
|
+
{
|
|
1292
|
+
query: searchQuery,
|
|
1293
|
+
limit
|
|
1294
|
+
},
|
|
1295
|
+
limits
|
|
1296
|
+
)
|
|
1297
|
+
);
|
|
1213
1298
|
}
|
|
1214
1299
|
case "list":
|
|
1215
1300
|
return toolResult(await listMetrics(metricsV1Api, { query }, limits));
|
|
@@ -1245,17 +1330,25 @@ var RESERVED_SPAN_FACETS = /* @__PURE__ */ new Set([
|
|
|
1245
1330
|
]);
|
|
1246
1331
|
var InputSchema5 = {
|
|
1247
1332
|
action: ActionSchema5.describe("Action to perform"),
|
|
1248
|
-
query: z6.string().optional().describe(
|
|
1249
|
-
|
|
1333
|
+
query: z6.string().optional().describe(
|
|
1334
|
+
'APM trace search query (Datadog syntax). Example: "@http.status_code:500", "service:my-service status:error"'
|
|
1335
|
+
),
|
|
1336
|
+
from: z6.string().optional().describe(
|
|
1337
|
+
"Start time. Formats: ISO 8601, relative (30s, 15m, 2h, 7d), precise (3d@11:45:23, yesterday@14:00)"
|
|
1338
|
+
),
|
|
1250
1339
|
to: z6.string().optional().describe('End time. Same formats as "from". Example: from="3d@11:45" to="3d@12:55"'),
|
|
1251
1340
|
service: z6.string().optional().describe('Filter by service name. Example: "my-service", "postgres"'),
|
|
1252
1341
|
operation: z6.string().optional().describe('Filter by operation name. Example: "express.request", "mongodb.query"'),
|
|
1253
|
-
resource: z6.string().optional().describe(
|
|
1342
|
+
resource: z6.string().optional().describe(
|
|
1343
|
+
'Filter by resource name (endpoint/query). Supports wildcards. Example: "GET /api/*", "*orders*"'
|
|
1344
|
+
),
|
|
1254
1345
|
status: z6.enum(["ok", "error"]).optional().describe('Filter by span status - "ok" for successful, "error" for failed spans'),
|
|
1255
1346
|
env: z6.string().optional().describe('Filter by environment. Example: "production", "staging"'),
|
|
1256
1347
|
minDuration: z6.string().optional().describe('Minimum span duration (find slow spans). Examples: "1s", "500ms", "100ms"'),
|
|
1257
1348
|
maxDuration: z6.string().optional().describe('Maximum span duration. Examples: "5s", "1000ms"'),
|
|
1258
|
-
httpStatus: z6.string().optional().describe(
|
|
1349
|
+
httpStatus: z6.string().optional().describe(
|
|
1350
|
+
'HTTP status code filter. Examples: "500", "5xx" (500-599), "4xx" (400-499), ">=400"'
|
|
1351
|
+
),
|
|
1259
1352
|
errorType: z6.string().optional().describe('Filter by error type (grep-like). Example: "TimeoutError", "ConnectionRefused"'),
|
|
1260
1353
|
errorMessage: z6.string().optional().describe('Filter by error message (grep-like). Example: "timeout", "connection refused"'),
|
|
1261
1354
|
limit: z6.number().optional().describe("Maximum number of results"),
|
|
@@ -1318,11 +1411,7 @@ function buildTraceQuery(params) {
|
|
|
1318
1411
|
parts.push(`operation_name:${params.operation}`);
|
|
1319
1412
|
}
|
|
1320
1413
|
if (params.resource) {
|
|
1321
|
-
|
|
1322
|
-
parts.push(`resource_name:${params.resource}`);
|
|
1323
|
-
} else {
|
|
1324
|
-
parts.push(`resource_name:${params.resource}`);
|
|
1325
|
-
}
|
|
1414
|
+
parts.push(`resource_name:${params.resource}`);
|
|
1326
1415
|
}
|
|
1327
1416
|
if (params.status) {
|
|
1328
1417
|
parts.push(`status:${params.status}`);
|
|
@@ -1345,7 +1434,7 @@ function buildTraceQuery(params) {
|
|
|
1345
1434
|
if (params.httpStatus) {
|
|
1346
1435
|
const status = params.httpStatus.toLowerCase();
|
|
1347
1436
|
if (status.endsWith("xx")) {
|
|
1348
|
-
const base = parseInt(status[0] ?? "0", 10) * 100;
|
|
1437
|
+
const base = Number.parseInt(status[0] ?? "0", 10) * 100;
|
|
1349
1438
|
parts.push(`@http.status_code:[${base} TO ${base + 99}]`);
|
|
1350
1439
|
} else if (status.startsWith(">=")) {
|
|
1351
1440
|
parts.push(`@http.status_code:>=${status.slice(2)}`);
|
|
@@ -1491,10 +1580,12 @@ async function listApmServices(api, params, limits) {
|
|
|
1491
1580
|
to: toTime
|
|
1492
1581
|
},
|
|
1493
1582
|
compute: [{ aggregation: "count", type: "total" }],
|
|
1494
|
-
groupBy: [
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1583
|
+
groupBy: [
|
|
1584
|
+
{
|
|
1585
|
+
facet: "service",
|
|
1586
|
+
limit: limits.maxResults
|
|
1587
|
+
}
|
|
1588
|
+
]
|
|
1498
1589
|
}
|
|
1499
1590
|
}
|
|
1500
1591
|
};
|
|
@@ -1521,45 +1612,77 @@ function registerTracesTool(server, spansApi, _servicesApi, limits, site = "data
|
|
|
1521
1612
|
`Analyze APM traces for request flow and latency debugging. Actions: search (find spans), aggregate (group stats), services (list APM services). Key filters: minDuration/maxDuration ("500ms", "2s"), httpStatus ("5xx", ">=400"), status (ok/error), errorMessage (grep).
|
|
1522
1613
|
APM METRICS: Traces auto-generate metrics in trace.{service}.* namespace. Use metrics tool to query: avg:trace.{service}.request.duration{*}`,
|
|
1523
1614
|
InputSchema5,
|
|
1524
|
-
async ({
|
|
1615
|
+
async ({
|
|
1616
|
+
action,
|
|
1617
|
+
query,
|
|
1618
|
+
from,
|
|
1619
|
+
to,
|
|
1620
|
+
service,
|
|
1621
|
+
operation,
|
|
1622
|
+
resource,
|
|
1623
|
+
status,
|
|
1624
|
+
env,
|
|
1625
|
+
minDuration,
|
|
1626
|
+
maxDuration,
|
|
1627
|
+
httpStatus,
|
|
1628
|
+
errorType,
|
|
1629
|
+
errorMessage,
|
|
1630
|
+
limit,
|
|
1631
|
+
sort,
|
|
1632
|
+
groupBy
|
|
1633
|
+
}) => {
|
|
1525
1634
|
try {
|
|
1526
1635
|
switch (action) {
|
|
1527
1636
|
case "search": {
|
|
1528
|
-
return toolResult(
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1637
|
+
return toolResult(
|
|
1638
|
+
await searchTraces(
|
|
1639
|
+
spansApi,
|
|
1640
|
+
{
|
|
1641
|
+
query,
|
|
1642
|
+
from,
|
|
1643
|
+
to,
|
|
1644
|
+
service,
|
|
1645
|
+
operation,
|
|
1646
|
+
resource,
|
|
1647
|
+
status,
|
|
1648
|
+
env,
|
|
1649
|
+
minDuration,
|
|
1650
|
+
maxDuration,
|
|
1651
|
+
httpStatus,
|
|
1652
|
+
errorType,
|
|
1653
|
+
errorMessage,
|
|
1654
|
+
limit,
|
|
1655
|
+
sort
|
|
1656
|
+
},
|
|
1657
|
+
limits,
|
|
1658
|
+
site
|
|
1659
|
+
)
|
|
1660
|
+
);
|
|
1545
1661
|
}
|
|
1546
1662
|
case "aggregate": {
|
|
1547
|
-
return toolResult(
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1663
|
+
return toolResult(
|
|
1664
|
+
await aggregateTraces(
|
|
1665
|
+
spansApi,
|
|
1666
|
+
{
|
|
1667
|
+
query,
|
|
1668
|
+
from,
|
|
1669
|
+
to,
|
|
1670
|
+
service,
|
|
1671
|
+
operation,
|
|
1672
|
+
resource,
|
|
1673
|
+
status,
|
|
1674
|
+
env,
|
|
1675
|
+
minDuration,
|
|
1676
|
+
maxDuration,
|
|
1677
|
+
httpStatus,
|
|
1678
|
+
errorType,
|
|
1679
|
+
errorMessage,
|
|
1680
|
+
groupBy
|
|
1681
|
+
},
|
|
1682
|
+
limits,
|
|
1683
|
+
site
|
|
1684
|
+
)
|
|
1685
|
+
);
|
|
1563
1686
|
}
|
|
1564
1687
|
case "services":
|
|
1565
1688
|
return toolResult(await listApmServices(spansApi, { env, from, to }, limits));
|
|
@@ -1575,7 +1698,16 @@ APM METRICS: Traces auto-generate metrics in trace.{service}.* namespace. Use me
|
|
|
1575
1698
|
|
|
1576
1699
|
// src/tools/events.ts
|
|
1577
1700
|
import { z as z7 } from "zod";
|
|
1578
|
-
var ActionSchema6 = z7.enum([
|
|
1701
|
+
var ActionSchema6 = z7.enum([
|
|
1702
|
+
"list",
|
|
1703
|
+
"get",
|
|
1704
|
+
"create",
|
|
1705
|
+
"search",
|
|
1706
|
+
"aggregate",
|
|
1707
|
+
"top",
|
|
1708
|
+
"timeseries",
|
|
1709
|
+
"incidents"
|
|
1710
|
+
]);
|
|
1579
1711
|
var InputSchema6 = {
|
|
1580
1712
|
action: ActionSchema6.describe("Action to perform"),
|
|
1581
1713
|
id: z7.string().optional().describe("Event ID (for get action)"),
|
|
@@ -1624,9 +1756,9 @@ function extractTitleFromMessage(message) {
|
|
|
1624
1756
|
function extractMonitorIdFromMessage(message) {
|
|
1625
1757
|
if (!message) return void 0;
|
|
1626
1758
|
const match = message.match(/\/monitors\/(\d+)/);
|
|
1627
|
-
if (match
|
|
1628
|
-
const id = parseInt(match[1], 10);
|
|
1629
|
-
return isNaN(id) ? void 0 : id;
|
|
1759
|
+
if (match?.[1]) {
|
|
1760
|
+
const id = Number.parseInt(match[1], 10);
|
|
1761
|
+
return Number.isNaN(id) ? void 0 : id;
|
|
1630
1762
|
}
|
|
1631
1763
|
return void 0;
|
|
1632
1764
|
}
|
|
@@ -1745,8 +1877,8 @@ async function listEventsV1(api, params, limits) {
|
|
|
1745
1877
|
};
|
|
1746
1878
|
}
|
|
1747
1879
|
async function getEventV1(api, id) {
|
|
1748
|
-
const eventId = parseInt(id, 10);
|
|
1749
|
-
if (isNaN(eventId)) {
|
|
1880
|
+
const eventId = Number.parseInt(id, 10);
|
|
1881
|
+
if (Number.isNaN(eventId)) {
|
|
1750
1882
|
throw new Error(`Invalid event ID: ${id}`);
|
|
1751
1883
|
}
|
|
1752
1884
|
const response = await api.getEvent({ eventId });
|
|
@@ -1910,13 +2042,18 @@ async function aggregateEventsV2(api, params, limits, site) {
|
|
|
1910
2042
|
async function topEventsV2(api, params, limits, site) {
|
|
1911
2043
|
const effectiveQuery = params.query ?? "source:alert";
|
|
1912
2044
|
const effectiveTags = params.tags ?? ["source:alert"];
|
|
1913
|
-
const result = await aggregateEventsV2(
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2045
|
+
const result = await aggregateEventsV2(
|
|
2046
|
+
api,
|
|
2047
|
+
{
|
|
2048
|
+
...params,
|
|
2049
|
+
query: effectiveQuery,
|
|
2050
|
+
tags: effectiveTags,
|
|
2051
|
+
groupBy: params.groupBy ?? ["monitor_name"],
|
|
2052
|
+
limit: params.limit ?? 10
|
|
2053
|
+
},
|
|
2054
|
+
limits,
|
|
2055
|
+
site
|
|
2056
|
+
);
|
|
1920
2057
|
return {
|
|
1921
2058
|
top: result.buckets.map((bucket, index) => ({
|
|
1922
2059
|
rank: index + 1,
|
|
@@ -2149,7 +2286,9 @@ async function incidentsEventsV2(api, params, limits, site) {
|
|
|
2149
2286
|
sample: inc.sample
|
|
2150
2287
|
};
|
|
2151
2288
|
});
|
|
2152
|
-
incidentList.sort(
|
|
2289
|
+
incidentList.sort(
|
|
2290
|
+
(a, b) => new Date(b.firstTrigger).getTime() - new Date(a.firstTrigger).getTime()
|
|
2291
|
+
);
|
|
2153
2292
|
const effectiveLimit = Math.min(params.limit ?? 100, 500);
|
|
2154
2293
|
return {
|
|
2155
2294
|
incidents: incidentList.slice(0, effectiveLimit),
|
|
@@ -2227,20 +2366,44 @@ Use action:"timeseries" with interval:"1h" to see alert trends over time.
|
|
|
2227
2366
|
Use action:"incidents" with dedupeWindow:"5m" to deduplicate alerts into incidents.
|
|
2228
2367
|
Use enrich:true with search to get monitor metadata (slower).`,
|
|
2229
2368
|
InputSchema6,
|
|
2230
|
-
async ({
|
|
2369
|
+
async ({
|
|
2370
|
+
action,
|
|
2371
|
+
id,
|
|
2372
|
+
query,
|
|
2373
|
+
from,
|
|
2374
|
+
to,
|
|
2375
|
+
priority,
|
|
2376
|
+
sources,
|
|
2377
|
+
tags,
|
|
2378
|
+
limit,
|
|
2379
|
+
title,
|
|
2380
|
+
text,
|
|
2381
|
+
alertType,
|
|
2382
|
+
groupBy,
|
|
2383
|
+
cursor,
|
|
2384
|
+
interval,
|
|
2385
|
+
dedupeWindow,
|
|
2386
|
+
enrich
|
|
2387
|
+
}) => {
|
|
2231
2388
|
try {
|
|
2232
2389
|
checkReadOnly(action, readOnly);
|
|
2233
2390
|
switch (action) {
|
|
2234
2391
|
case "list":
|
|
2235
|
-
return toolResult(
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2392
|
+
return toolResult(
|
|
2393
|
+
await listEventsV1(
|
|
2394
|
+
apiV1,
|
|
2395
|
+
{
|
|
2396
|
+
query,
|
|
2397
|
+
from,
|
|
2398
|
+
to,
|
|
2399
|
+
priority,
|
|
2400
|
+
sources,
|
|
2401
|
+
tags,
|
|
2402
|
+
limit
|
|
2403
|
+
},
|
|
2404
|
+
limits
|
|
2405
|
+
)
|
|
2406
|
+
);
|
|
2244
2407
|
case "get": {
|
|
2245
2408
|
const eventId = requireParam(id, "id", "get");
|
|
2246
2409
|
return toolResult(await getEventV1(apiV1, eventId));
|
|
@@ -2248,25 +2411,32 @@ Use enrich:true with search to get monitor metadata (slower).`,
|
|
|
2248
2411
|
case "create": {
|
|
2249
2412
|
const eventTitle = requireParam(title, "title", "create");
|
|
2250
2413
|
const eventText = requireParam(text, "text", "create");
|
|
2251
|
-
return toolResult(
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2414
|
+
return toolResult(
|
|
2415
|
+
await createEventV1(apiV1, {
|
|
2416
|
+
title: eventTitle,
|
|
2417
|
+
text: eventText,
|
|
2418
|
+
priority,
|
|
2419
|
+
tags,
|
|
2420
|
+
alertType
|
|
2421
|
+
})
|
|
2422
|
+
);
|
|
2258
2423
|
}
|
|
2259
2424
|
case "search": {
|
|
2260
|
-
const result = await searchEventsV2(
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2425
|
+
const result = await searchEventsV2(
|
|
2426
|
+
apiV2,
|
|
2427
|
+
{
|
|
2428
|
+
query,
|
|
2429
|
+
from,
|
|
2430
|
+
to,
|
|
2431
|
+
sources,
|
|
2432
|
+
tags,
|
|
2433
|
+
priority,
|
|
2434
|
+
limit,
|
|
2435
|
+
cursor
|
|
2436
|
+
},
|
|
2437
|
+
limits,
|
|
2438
|
+
site
|
|
2439
|
+
);
|
|
2270
2440
|
if (enrich && result.events.length > 0) {
|
|
2271
2441
|
const enrichedEvents = await enrichWithMonitorMetadata(result.events, monitorsApi);
|
|
2272
2442
|
return toolResult({ ...result, events: enrichedEvents });
|
|
@@ -2274,46 +2444,74 @@ Use enrich:true with search to get monitor metadata (slower).`,
|
|
|
2274
2444
|
return toolResult(result);
|
|
2275
2445
|
}
|
|
2276
2446
|
case "aggregate":
|
|
2277
|
-
return toolResult(
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2447
|
+
return toolResult(
|
|
2448
|
+
await aggregateEventsV2(
|
|
2449
|
+
apiV2,
|
|
2450
|
+
{
|
|
2451
|
+
query,
|
|
2452
|
+
from,
|
|
2453
|
+
to,
|
|
2454
|
+
sources,
|
|
2455
|
+
tags,
|
|
2456
|
+
groupBy,
|
|
2457
|
+
limit
|
|
2458
|
+
},
|
|
2459
|
+
limits,
|
|
2460
|
+
site
|
|
2461
|
+
)
|
|
2462
|
+
);
|
|
2286
2463
|
case "top":
|
|
2287
|
-
return toolResult(
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2464
|
+
return toolResult(
|
|
2465
|
+
await topEventsV2(
|
|
2466
|
+
apiV2,
|
|
2467
|
+
{
|
|
2468
|
+
query,
|
|
2469
|
+
from,
|
|
2470
|
+
to,
|
|
2471
|
+
sources,
|
|
2472
|
+
tags,
|
|
2473
|
+
groupBy,
|
|
2474
|
+
limit
|
|
2475
|
+
},
|
|
2476
|
+
limits,
|
|
2477
|
+
site
|
|
2478
|
+
)
|
|
2479
|
+
);
|
|
2296
2480
|
case "timeseries":
|
|
2297
|
-
return toolResult(
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2481
|
+
return toolResult(
|
|
2482
|
+
await timeseriesEventsV2(
|
|
2483
|
+
apiV2,
|
|
2484
|
+
{
|
|
2485
|
+
query,
|
|
2486
|
+
from,
|
|
2487
|
+
to,
|
|
2488
|
+
sources,
|
|
2489
|
+
tags,
|
|
2490
|
+
groupBy,
|
|
2491
|
+
interval,
|
|
2492
|
+
limit
|
|
2493
|
+
},
|
|
2494
|
+
limits,
|
|
2495
|
+
site
|
|
2496
|
+
)
|
|
2497
|
+
);
|
|
2307
2498
|
case "incidents":
|
|
2308
|
-
return toolResult(
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2499
|
+
return toolResult(
|
|
2500
|
+
await incidentsEventsV2(
|
|
2501
|
+
apiV2,
|
|
2502
|
+
{
|
|
2503
|
+
query,
|
|
2504
|
+
from,
|
|
2505
|
+
to,
|
|
2506
|
+
sources,
|
|
2507
|
+
tags,
|
|
2508
|
+
dedupeWindow,
|
|
2509
|
+
limit
|
|
2510
|
+
},
|
|
2511
|
+
limits,
|
|
2512
|
+
site
|
|
2513
|
+
)
|
|
2514
|
+
);
|
|
2317
2515
|
default:
|
|
2318
2516
|
throw new Error(`Unknown action: ${action}`);
|
|
2319
2517
|
}
|
|
@@ -2333,7 +2531,9 @@ var InputSchema7 = {
|
|
|
2333
2531
|
query: z8.string().optional().describe("Search query (for search action)"),
|
|
2334
2532
|
status: z8.enum(["active", "stable", "resolved"]).optional().describe("Filter by status (for list)"),
|
|
2335
2533
|
limit: z8.number().optional().describe("Maximum number of incidents to return"),
|
|
2336
|
-
config: z8.record(z8.unknown()).optional().describe(
|
|
2534
|
+
config: z8.record(z8.unknown()).optional().describe(
|
|
2535
|
+
"Incident configuration (for create/update). Create requires: title. Update can modify: title, status, severity, fields."
|
|
2536
|
+
)
|
|
2337
2537
|
};
|
|
2338
2538
|
function formatIncident(i) {
|
|
2339
2539
|
const attrs = i.attributes;
|
|
@@ -2385,11 +2585,13 @@ async function searchIncidents(api, query, limits) {
|
|
|
2385
2585
|
query,
|
|
2386
2586
|
pageSize: limits.maxResults
|
|
2387
2587
|
});
|
|
2388
|
-
const incidents = (response.data?.attributes?.incidents ?? []).map(
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2588
|
+
const incidents = (response.data?.attributes?.incidents ?? []).map(
|
|
2589
|
+
(i) => ({
|
|
2590
|
+
id: i.data?.id ?? "",
|
|
2591
|
+
title: i.data?.attributes?.title ?? "",
|
|
2592
|
+
state: i.data?.attributes?.state ?? "unknown"
|
|
2593
|
+
})
|
|
2594
|
+
);
|
|
2393
2595
|
return {
|
|
2394
2596
|
incidents,
|
|
2395
2597
|
total: response.data?.attributes?.total ?? incidents.length
|
|
@@ -2429,7 +2631,7 @@ async function deleteIncident(api, id) {
|
|
|
2429
2631
|
message: `Incident ${id} deleted`
|
|
2430
2632
|
};
|
|
2431
2633
|
}
|
|
2432
|
-
function registerIncidentsTool(server, api, limits, readOnly = false) {
|
|
2634
|
+
function registerIncidentsTool(server, api, limits, readOnly = false, _site = "datadoghq.com") {
|
|
2433
2635
|
server.tool(
|
|
2434
2636
|
"incidents",
|
|
2435
2637
|
"Manage Datadog incidents for incident response. Actions: list, get, search, create, update, delete. Use for: incident management, on-call response, postmortems, tracking MTTR/MTTD.",
|
|
@@ -2606,7 +2808,7 @@ async function getSloHistory(api, id, params) {
|
|
|
2606
2808
|
}
|
|
2607
2809
|
};
|
|
2608
2810
|
}
|
|
2609
|
-
function registerSlosTool(server, api, limits, readOnly = false) {
|
|
2811
|
+
function registerSlosTool(server, api, limits, readOnly = false, _site = "datadoghq.com") {
|
|
2610
2812
|
server.tool(
|
|
2611
2813
|
"slos",
|
|
2612
2814
|
"Manage Datadog Service Level Objectives. Actions: list, get, create, update, delete, history. SLO types: metric-based, monitor-based. Use for: reliability tracking, error budgets, SLA compliance, performance targets.",
|
|
@@ -2659,7 +2861,9 @@ var InputSchema9 = {
|
|
|
2659
2861
|
locations: z10.array(z10.string()).optional().describe("Filter by locations (for list)"),
|
|
2660
2862
|
tags: z10.array(z10.string()).optional().describe("Filter by tags (for list)"),
|
|
2661
2863
|
limit: z10.number().optional().describe("Maximum number of tests to return"),
|
|
2662
|
-
config: z10.record(z10.unknown()).optional().describe(
|
|
2864
|
+
config: z10.record(z10.unknown()).optional().describe(
|
|
2865
|
+
"Test configuration (for create/update). Includes: name, type, config, options, locations, message."
|
|
2866
|
+
)
|
|
2663
2867
|
};
|
|
2664
2868
|
function formatTest(t) {
|
|
2665
2869
|
return {
|
|
@@ -2750,7 +2954,7 @@ async function createTest(api, config, testType) {
|
|
|
2750
2954
|
}
|
|
2751
2955
|
async function updateTest(api, id, config) {
|
|
2752
2956
|
const normalizedConfig = normalizeConfigKeys2(config);
|
|
2753
|
-
let testType
|
|
2957
|
+
let testType;
|
|
2754
2958
|
try {
|
|
2755
2959
|
await api.getAPITest({ publicId: id });
|
|
2756
2960
|
testType = "api";
|
|
@@ -2820,7 +3024,7 @@ async function getTestResults(api, id) {
|
|
|
2820
3024
|
return { results, testType: "browser" };
|
|
2821
3025
|
}
|
|
2822
3026
|
}
|
|
2823
|
-
function registerSyntheticsTool(server, api, limits, readOnly = false) {
|
|
3027
|
+
function registerSyntheticsTool(server, api, limits, readOnly = false, _site = "datadoghq.com") {
|
|
2824
3028
|
server.tool(
|
|
2825
3029
|
"synthetics",
|
|
2826
3030
|
"Manage Datadog Synthetic tests (API and Browser). Actions: list, get, create, update, delete, trigger, results. Use for: uptime monitoring, API testing, user journey testing, performance testing, canary deployments.",
|
|
@@ -2933,9 +3137,10 @@ async function muteHost(api, hostName, params) {
|
|
|
2933
3137
|
override: params.override
|
|
2934
3138
|
}
|
|
2935
3139
|
});
|
|
3140
|
+
const muteEndMessage = params.end ? ` until ${new Date(params.end * 1e3).toISOString()}` : " indefinitely";
|
|
2936
3141
|
return {
|
|
2937
3142
|
success: true,
|
|
2938
|
-
message: `Host ${hostName} muted${
|
|
3143
|
+
message: `Host ${hostName} muted${muteEndMessage}`
|
|
2939
3144
|
};
|
|
2940
3145
|
}
|
|
2941
3146
|
async function unmuteHost(api, hostName) {
|
|
@@ -2950,12 +3155,25 @@ function registerHostsTool(server, api, limits, readOnly = false) {
|
|
|
2950
3155
|
"hosts",
|
|
2951
3156
|
"Manage Datadog infrastructure hosts. Actions: list (with filters), totals (counts), mute (silence alerts), unmute. Use for: infrastructure inventory, host health, silencing noisy hosts during maintenance.",
|
|
2952
3157
|
InputSchema10,
|
|
2953
|
-
async ({
|
|
3158
|
+
async ({
|
|
3159
|
+
action,
|
|
3160
|
+
filter,
|
|
3161
|
+
from,
|
|
3162
|
+
count,
|
|
3163
|
+
sortField,
|
|
3164
|
+
sortDir,
|
|
3165
|
+
hostName,
|
|
3166
|
+
message,
|
|
3167
|
+
end,
|
|
3168
|
+
override
|
|
3169
|
+
}) => {
|
|
2954
3170
|
try {
|
|
2955
3171
|
checkReadOnly(action, readOnly);
|
|
2956
3172
|
switch (action) {
|
|
2957
3173
|
case "list":
|
|
2958
|
-
return toolResult(
|
|
3174
|
+
return toolResult(
|
|
3175
|
+
await listHosts(api, { filter, from, count, sortField, sortDir }, limits)
|
|
3176
|
+
);
|
|
2959
3177
|
case "totals":
|
|
2960
3178
|
return toolResult(await getHostTotals(api));
|
|
2961
3179
|
case "mute": {
|
|
@@ -3141,7 +3359,9 @@ var InputSchema12 = {
|
|
|
3141
3359
|
interval: z13.string().optional()
|
|
3142
3360
|
}).optional().describe("Compute configuration for aggregation"),
|
|
3143
3361
|
// Performance action parameters
|
|
3144
|
-
metrics: z13.array(z13.enum(["lcp", "fcp", "cls", "fid", "inp", "loading_time"])).optional().describe(
|
|
3362
|
+
metrics: z13.array(z13.enum(["lcp", "fcp", "cls", "fid", "inp", "loading_time"])).optional().describe(
|
|
3363
|
+
"Core Web Vitals metrics to retrieve (default: all). lcp=Largest Contentful Paint, fcp=First Contentful Paint, cls=Cumulative Layout Shift, fid=First Input Delay, inp=Interaction to Next Paint, loading_time=View loading time"
|
|
3364
|
+
),
|
|
3145
3365
|
// Waterfall action parameters
|
|
3146
3366
|
applicationId: z13.string().optional().describe("Application ID for waterfall action"),
|
|
3147
3367
|
sessionId: z13.string().optional().describe("Session ID for waterfall action"),
|
|
@@ -3443,10 +3663,7 @@ function formatWaterfallEvent(event) {
|
|
|
3443
3663
|
};
|
|
3444
3664
|
}
|
|
3445
3665
|
async function getSessionWaterfall(api, params, limits, site) {
|
|
3446
|
-
const queryParts = [
|
|
3447
|
-
`@application.id:${params.applicationId}`,
|
|
3448
|
-
`@session.id:${params.sessionId}`
|
|
3449
|
-
];
|
|
3666
|
+
const queryParts = [`@application.id:${params.applicationId}`, `@session.id:${params.sessionId}`];
|
|
3450
3667
|
if (params.viewId) {
|
|
3451
3668
|
queryParts.push(`@view.id:${params.viewId}`);
|
|
3452
3669
|
}
|
|
@@ -3480,22 +3697,44 @@ function registerRumTool(server, api, limits, site = "datadoghq.com") {
|
|
|
3480
3697
|
"rum",
|
|
3481
3698
|
"Query Datadog Real User Monitoring (RUM) data. Actions: applications (list RUM apps), events (search RUM events), aggregate (group and count events), performance (Core Web Vitals: LCP, FCP, CLS, FID, INP), waterfall (session timeline with resources/actions/errors). Use for: frontend performance, user sessions, page views, errors, resource loading.",
|
|
3482
3699
|
InputSchema12,
|
|
3483
|
-
async ({
|
|
3700
|
+
async ({
|
|
3701
|
+
action,
|
|
3702
|
+
query,
|
|
3703
|
+
from,
|
|
3704
|
+
to,
|
|
3705
|
+
type,
|
|
3706
|
+
sort,
|
|
3707
|
+
limit,
|
|
3708
|
+
groupBy,
|
|
3709
|
+
compute,
|
|
3710
|
+
metrics,
|
|
3711
|
+
applicationId,
|
|
3712
|
+
sessionId,
|
|
3713
|
+
viewId
|
|
3714
|
+
}) => {
|
|
3484
3715
|
try {
|
|
3485
3716
|
switch (action) {
|
|
3486
3717
|
case "applications":
|
|
3487
3718
|
return toolResult(await listApplications(api));
|
|
3488
3719
|
case "events":
|
|
3489
|
-
return toolResult(
|
|
3720
|
+
return toolResult(
|
|
3721
|
+
await searchEvents(api, { query, from, to, type, sort, limit }, limits, site)
|
|
3722
|
+
);
|
|
3490
3723
|
case "aggregate":
|
|
3491
|
-
return toolResult(
|
|
3724
|
+
return toolResult(
|
|
3725
|
+
await aggregateEvents(api, { query, from, to, groupBy, compute }, limits, site)
|
|
3726
|
+
);
|
|
3492
3727
|
case "performance":
|
|
3493
|
-
return toolResult(
|
|
3728
|
+
return toolResult(
|
|
3729
|
+
await getPerformanceMetrics(api, { query, from, to, groupBy, metrics }, limits, site)
|
|
3730
|
+
);
|
|
3494
3731
|
case "waterfall":
|
|
3495
3732
|
if (!applicationId || !sessionId) {
|
|
3496
3733
|
throw new Error("waterfall action requires applicationId and sessionId parameters");
|
|
3497
3734
|
}
|
|
3498
|
-
return toolResult(
|
|
3735
|
+
return toolResult(
|
|
3736
|
+
await getSessionWaterfall(api, { applicationId, sessionId, viewId }, limits, site)
|
|
3737
|
+
);
|
|
3499
3738
|
default:
|
|
3500
3739
|
throw new Error(`Unknown action: ${action}`);
|
|
3501
3740
|
}
|
|
@@ -3653,7 +3892,13 @@ function registerSecurityTool(server, api, limits) {
|
|
|
3653
3892
|
}
|
|
3654
3893
|
return toolResult(await listRules(api, { pageSize, pageCursor }, limits));
|
|
3655
3894
|
case "signals":
|
|
3656
|
-
return toolResult(
|
|
3895
|
+
return toolResult(
|
|
3896
|
+
await searchSignals(
|
|
3897
|
+
api,
|
|
3898
|
+
{ query, from, to, severity, status, pageSize, pageCursor },
|
|
3899
|
+
limits
|
|
3900
|
+
)
|
|
3901
|
+
);
|
|
3657
3902
|
case "findings":
|
|
3658
3903
|
return toolResult(await listFindings(api, { query, pageSize, pageCursor }, limits));
|
|
3659
3904
|
default:
|
|
@@ -3677,10 +3922,19 @@ var InputSchema14 = {
|
|
|
3677
3922
|
excludeAuthorHandle: z15.string().optional().describe("Exclude notebooks by author handle"),
|
|
3678
3923
|
includeCells: z15.boolean().optional().describe("Include cell content in response (default: true for get)"),
|
|
3679
3924
|
name: z15.string().optional().describe("Notebook name (for create/update)"),
|
|
3680
|
-
cells: z15.array(
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3925
|
+
cells: z15.array(
|
|
3926
|
+
z15.object({
|
|
3927
|
+
type: z15.enum([
|
|
3928
|
+
"markdown",
|
|
3929
|
+
"timeseries",
|
|
3930
|
+
"toplist",
|
|
3931
|
+
"heatmap",
|
|
3932
|
+
"distribution",
|
|
3933
|
+
"log_stream"
|
|
3934
|
+
]),
|
|
3935
|
+
content: z15.unknown()
|
|
3936
|
+
})
|
|
3937
|
+
).optional().describe("Notebook cells (for create/update)"),
|
|
3684
3938
|
time: z15.object({
|
|
3685
3939
|
liveSpan: z15.string().optional(),
|
|
3686
3940
|
start: z15.number().optional(),
|
|
@@ -3845,7 +4099,9 @@ async function updateNotebook(api, notebookId, params) {
|
|
|
3845
4099
|
};
|
|
3846
4100
|
});
|
|
3847
4101
|
}
|
|
3848
|
-
const timeConfig = params.time?.liveSpan ? {
|
|
4102
|
+
const timeConfig = params.time?.liveSpan ? {
|
|
4103
|
+
liveSpan: params.time.liveSpan
|
|
4104
|
+
} : void 0;
|
|
3849
4105
|
const response = await api.updateNotebook({
|
|
3850
4106
|
notebookId,
|
|
3851
4107
|
body: {
|
|
@@ -3880,38 +4136,61 @@ async function deleteNotebook(api, notebookId) {
|
|
|
3880
4136
|
message: `Notebook ${notebookId} deleted successfully`
|
|
3881
4137
|
};
|
|
3882
4138
|
}
|
|
3883
|
-
function registerNotebooksTool(server, api, limits, readOnly = false) {
|
|
4139
|
+
function registerNotebooksTool(server, api, limits, readOnly = false, _site = "datadoghq.com") {
|
|
3884
4140
|
server.tool(
|
|
3885
4141
|
"notebooks",
|
|
3886
4142
|
"Manage Datadog Notebooks. Actions: list (search notebooks), get (by ID with cells), create (new notebook), update (modify notebook), delete (remove notebook). Use for: runbooks, incident documentation, investigation notes, dashboards as code.",
|
|
3887
4143
|
InputSchema14,
|
|
3888
|
-
async ({
|
|
4144
|
+
async ({
|
|
4145
|
+
action,
|
|
4146
|
+
id,
|
|
4147
|
+
query,
|
|
4148
|
+
authorHandle,
|
|
4149
|
+
excludeAuthorHandle,
|
|
4150
|
+
includeCells,
|
|
4151
|
+
name,
|
|
4152
|
+
cells,
|
|
4153
|
+
time,
|
|
4154
|
+
status,
|
|
4155
|
+
pageSize,
|
|
4156
|
+
pageNumber
|
|
4157
|
+
}) => {
|
|
3889
4158
|
try {
|
|
3890
4159
|
checkReadOnly(action, readOnly);
|
|
3891
4160
|
switch (action) {
|
|
3892
4161
|
case "list":
|
|
3893
|
-
return toolResult(
|
|
4162
|
+
return toolResult(
|
|
4163
|
+
await listNotebooks(
|
|
4164
|
+
api,
|
|
4165
|
+
{ query, authorHandle, excludeAuthorHandle, includeCells, pageSize, pageNumber },
|
|
4166
|
+
limits
|
|
4167
|
+
)
|
|
4168
|
+
);
|
|
3894
4169
|
case "get": {
|
|
3895
4170
|
const notebookId = requireParam(id, "id", "get");
|
|
3896
4171
|
return toolResult(await getNotebook(api, notebookId));
|
|
3897
4172
|
}
|
|
3898
4173
|
case "create": {
|
|
3899
4174
|
const notebookName = requireParam(name, "name", "create");
|
|
3900
|
-
return toolResult(
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
4175
|
+
return toolResult(
|
|
4176
|
+
await createNotebook(api, {
|
|
4177
|
+
name: notebookName,
|
|
4178
|
+
cells,
|
|
4179
|
+
time,
|
|
4180
|
+
status
|
|
4181
|
+
})
|
|
4182
|
+
);
|
|
3906
4183
|
}
|
|
3907
4184
|
case "update": {
|
|
3908
4185
|
const notebookId = requireParam(id, "id", "update");
|
|
3909
|
-
return toolResult(
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
4186
|
+
return toolResult(
|
|
4187
|
+
await updateNotebook(api, notebookId, {
|
|
4188
|
+
name,
|
|
4189
|
+
cells,
|
|
4190
|
+
time,
|
|
4191
|
+
status
|
|
4192
|
+
})
|
|
4193
|
+
);
|
|
3915
4194
|
}
|
|
3916
4195
|
case "delete": {
|
|
3917
4196
|
const notebookId = requireParam(id, "id", "delete");
|
|
@@ -3993,7 +4272,9 @@ function registerUsersTool(server, api, limits) {
|
|
|
3993
4272
|
try {
|
|
3994
4273
|
switch (action) {
|
|
3995
4274
|
case "list":
|
|
3996
|
-
return toolResult(
|
|
4275
|
+
return toolResult(
|
|
4276
|
+
await listUsers(api, { filter, status, pageSize, pageNumber }, limits)
|
|
4277
|
+
);
|
|
3997
4278
|
case "get": {
|
|
3998
4279
|
const userId = requireParam(id, "id", "get");
|
|
3999
4280
|
return toolResult(await getUser(api, userId));
|
|
@@ -4224,9 +4505,18 @@ function registerTagsTool(server, api, _limits, readOnly = false) {
|
|
|
4224
4505
|
|
|
4225
4506
|
// src/tools/usage.ts
|
|
4226
4507
|
import { z as z19 } from "zod";
|
|
4227
|
-
var ActionSchema18 = z19.enum([
|
|
4508
|
+
var ActionSchema18 = z19.enum([
|
|
4509
|
+
"summary",
|
|
4510
|
+
"hosts",
|
|
4511
|
+
"logs",
|
|
4512
|
+
"custom_metrics",
|
|
4513
|
+
"indexed_spans",
|
|
4514
|
+
"ingested_spans"
|
|
4515
|
+
]);
|
|
4228
4516
|
var InputSchema18 = {
|
|
4229
|
-
action: ActionSchema18.describe(
|
|
4517
|
+
action: ActionSchema18.describe(
|
|
4518
|
+
"Action to perform: summary (overall usage), hosts, logs, custom_metrics, indexed_spans, ingested_spans"
|
|
4519
|
+
),
|
|
4230
4520
|
from: z19.string().optional().describe('Start time (ISO 8601 date like "2024-01-01", or relative like "30d")'),
|
|
4231
4521
|
to: z19.string().optional().describe('End time (ISO 8601 date like "2024-01-31", or relative like "now")'),
|
|
4232
4522
|
includeOrgDetails: z19.boolean().optional().describe("Include usage breakdown by organization (for multi-org accounts)")
|
|
@@ -4238,7 +4528,7 @@ function parseDate(dateStr, defaultDate) {
|
|
|
4238
4528
|
return new Date(seconds * 1e3);
|
|
4239
4529
|
}
|
|
4240
4530
|
const parsed = new Date(dateStr);
|
|
4241
|
-
if (!isNaN(parsed.getTime())) {
|
|
4531
|
+
if (!Number.isNaN(parsed.getTime())) {
|
|
4242
4532
|
return parsed;
|
|
4243
4533
|
}
|
|
4244
4534
|
return defaultDate;
|
|
@@ -4395,7 +4685,9 @@ function registerUsageTool(server, api, _limits) {
|
|
|
4395
4685
|
import { z as z20 } from "zod";
|
|
4396
4686
|
var ActionSchema19 = z20.enum(["validate"]);
|
|
4397
4687
|
var InputSchema19 = {
|
|
4398
|
-
action: ActionSchema19.describe(
|
|
4688
|
+
action: ActionSchema19.describe(
|
|
4689
|
+
"Action to perform: validate - test if API key and App key are valid"
|
|
4690
|
+
)
|
|
4399
4691
|
};
|
|
4400
4692
|
function registerAuthTool(server, clients) {
|
|
4401
4693
|
server.tool(
|
|
@@ -4455,14 +4747,26 @@ function registerAllTools(server, clients, limits, features, site = "datadoghq.c
|
|
|
4455
4747
|
const { readOnly, disabledTools } = features;
|
|
4456
4748
|
const enabled = (tool) => !disabledTools.includes(tool);
|
|
4457
4749
|
if (enabled("monitors")) registerMonitorsTool(server, clients.monitors, limits, readOnly, site);
|
|
4458
|
-
if (enabled("dashboards"))
|
|
4750
|
+
if (enabled("dashboards"))
|
|
4751
|
+
registerDashboardsTool(server, clients.dashboards, limits, readOnly, site);
|
|
4459
4752
|
if (enabled("logs")) registerLogsTool(server, clients.logs, limits, site);
|
|
4460
|
-
if (enabled("metrics"))
|
|
4753
|
+
if (enabled("metrics"))
|
|
4754
|
+
registerMetricsTool(server, clients.metricsV1, clients.metricsV2, limits, site);
|
|
4461
4755
|
if (enabled("traces")) registerTracesTool(server, clients.spans, clients.services, limits, site);
|
|
4462
|
-
if (enabled("events"))
|
|
4756
|
+
if (enabled("events"))
|
|
4757
|
+
registerEventsTool(
|
|
4758
|
+
server,
|
|
4759
|
+
clients.eventsV1,
|
|
4760
|
+
clients.eventsV2,
|
|
4761
|
+
clients.monitors,
|
|
4762
|
+
limits,
|
|
4763
|
+
readOnly,
|
|
4764
|
+
site
|
|
4765
|
+
);
|
|
4463
4766
|
if (enabled("incidents")) registerIncidentsTool(server, clients.incidents, limits, readOnly, site);
|
|
4464
4767
|
if (enabled("slos")) registerSlosTool(server, clients.slo, limits, readOnly, site);
|
|
4465
|
-
if (enabled("synthetics"))
|
|
4768
|
+
if (enabled("synthetics"))
|
|
4769
|
+
registerSyntheticsTool(server, clients.synthetics, limits, readOnly, site);
|
|
4466
4770
|
if (enabled("hosts")) registerHostsTool(server, clients.hosts, limits, readOnly);
|
|
4467
4771
|
if (enabled("downtimes")) registerDowntimesTool(server, clients.downtimes, limits, readOnly);
|
|
4468
4772
|
if (enabled("rum")) registerRumTool(server, clients.rum, limits, site);
|
|
@@ -4561,19 +4865,16 @@ async function connectHttp(server, config) {
|
|
|
4561
4865
|
}
|
|
4562
4866
|
|
|
4563
4867
|
// src/index.ts
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
await connectStdio(server);
|
|
4572
|
-
}
|
|
4573
|
-
} catch (error) {
|
|
4574
|
-
console.error("[MCP] Failed to start server:", error);
|
|
4575
|
-
process.exit(1);
|
|
4868
|
+
try {
|
|
4869
|
+
const config = loadConfig();
|
|
4870
|
+
const server = createServer(config);
|
|
4871
|
+
if (config.server.transport === "http") {
|
|
4872
|
+
await connectHttp(server, config.server);
|
|
4873
|
+
} else {
|
|
4874
|
+
await connectStdio(server);
|
|
4576
4875
|
}
|
|
4876
|
+
} catch (error) {
|
|
4877
|
+
console.error("[MCP] Failed to start server:", error);
|
|
4878
|
+
process.exit(1);
|
|
4577
4879
|
}
|
|
4578
|
-
main();
|
|
4579
4880
|
//# sourceMappingURL=index.js.map
|