Skip to main content
Glama

Datadog MCP Server

by Nozomuts
aggregate.ts5.04 kB
import { z } from "zod"; import { aggregateSpans } from "../../datadog/spans/aggregate.js"; import { createSuccessResponse, createErrorResponse } from "../../utils.js"; import type { SpanAggregationResult, ToolResponse } from "../../types.js"; export const aggregateSpansZodSchema = z.object({ filterQuery: z .string() .optional() .default("*") .describe("Query string to search for (optional, default is '*')"), filterFrom: z .number() .optional() .default(Date.now() / 1000 - 15 * 60) .describe( "Search start time (UNIX timestamp in seconds, optional, default is 15 minutes ago)" ), filterTo: z .number() .optional() .default(Date.now() / 1000) .describe( "Search end time (UNIX timestamp in seconds, optional, default is current time)" ), groupBy: z .array( z.enum([ "service", "resource_name", "env", "status", "operation_name", "type", "@version", "@http.status_code", "@http.client_ip", "@http.url", "@http.method", "@http.host", "@http.user_agent", "@http.path_group", "@http.route", ]) ) .optional() .describe("Attributes to group by (example: ['service', 'resource_name'])"), interval: z .string() .optional() .describe( "Time interval to group results by (optional, only used when type is timeseries)" ), type: z .enum(["timeseries", "total"]) .default("timeseries") .describe( "Result type - timeseries or total (optional, default is 'timeseries')" ), }); const generateSummaryText = ( data: z.infer<typeof aggregateSpansZodSchema>, result: SpanAggregationResult ): string => { let responseText = ""; responseText += `# Span Aggregation Results\n`; responseText += `## Aggregation Criteria\n`; responseText += `* Query: \`${data.filterQuery || "*"}\`\n`; responseText += `* Time Range: ${new Date( data.filterFrom * 1000 ).toLocaleString()} to ${new Date(data.filterTo * 1000).toLocaleString()}\n`; responseText += `* Group By: ${data.groupBy?.join(", ") || "none"}\n`; responseText += `* Type: ${data.type}\n`; if (data.interval) { responseText += `* Interval: ${data.interval}\n`; } if (result.status) { responseText += `## Status\n`; responseText += `* Status: ${result.status || "unknown"}\n`; responseText += `* Elapsed Time: ${result.elapsed || "unknown"}\n`; } if (result.buckets.length > 0) { responseText += `## Aggregation Results\n`; for (const bucket of result.buckets) { responseText += `### Group\n`; for (const [key, value] of Object.entries(bucket.by || {})) { responseText += `* ${key}: ${value}\n`; } for (const value of Object.values(bucket.compute || {})) { if (data.type === "total") { responseText += `* Aggregated Value: ${value}\n`; } else if (data.type === "timeseries") { for (const item of value) { if ("value" in item && "time" in item) { responseText += `* Time: ${item.time}, Value: ${item.value}\n`; } } } } } } if (result.warnings && result.warnings.length > 0) { responseText += `## Warnings\n`; for (const warning of result.warnings) { responseText += `### Details\n`; if (warning.title) { responseText += `* Title: ${warning.title}\n`; } if (warning.detail) { responseText += `* Detail: ${warning.detail}\n`; } if (warning.code) { responseText += `* Code: ${warning.code}\n`; } } } return responseText; }; export const aggregateSpansHandler = async ( parameters: z.infer<typeof aggregateSpansZodSchema> ): Promise<ToolResponse> => { const validation = aggregateSpansZodSchema.safeParse(parameters); if (!validation.success) { return createErrorResponse( `Parameter validation error: ${validation.error.message}` ); } try { // Convert to Date objects after validation const validatedParams = { ...validation.data, filterFrom: new Date(validation.data.filterFrom * 1000), filterTo: new Date(validation.data.filterTo * 1000), }; const result = await aggregateSpans(validatedParams); const formattedResult = generateSummaryText(validation.data, result); const urlText = `[View in Datadog](https://app.datadoghq.com/apm/traces?query=${encodeURIComponent( validation.data.filterQuery )}&start=${validation.data.filterFrom}&end=${ validation.data.filterTo }&viz=${ validation.data.type === "total" ? "toplist" : validation.data.type }&agg_q=${validation.data.groupBy?.join(",") || ""})`; return createSuccessResponse([formattedResult, urlText]); } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return createErrorResponse(`Span aggregation error: ${errorMessage}`); } };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Nozomuts/datadog-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server