Skip to main content
Glama

Datadog MCP Server

by Nozomuts
search.ts4.11 kB
import { z } from "zod"; import { searchLogs } from "../../datadog/logs/search.js"; import { createErrorResponse, createSuccessResponse } from "../../utils.js"; import type { Log, ToolResponse } from "../../types.js"; export const searchLogsZodSchema = z.object({ filterQuery: z .string() .optional() .default("*") .describe("Query string to search logs (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)" ), pageLimit: z .number() .min(1) .max(1000) .optional() .default(25) .describe("Maximum number of logs to retrieve (optional, default is 25)"), pageCursor: z .string() .optional() .describe("Cursor to retrieve the next page (optional)"), }); const generateSummaryText = ( data: z.infer<typeof searchLogsZodSchema>, result: { logs: Log[]; nextCursor?: string; } ): string => { let responseText = ""; responseText += "# Log Search Results\n"; responseText += "## Search 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 += `* Retrieved: ${result.logs.length} logs\n`; if (result.logs.length === 0) { return responseText; } if (result.nextCursor) { responseText += "## Pagination\n"; responseText += `* Next Page Cursor: ${result.nextCursor}\n`; } responseText += "## Log Summary\n"; const MAX_MESSAGE_LENGTH = 300; for (const [index, log] of result.logs.entries()) { responseText += `### [${index + 1}]\n`; if (log.service) { responseText += `* Service: ${log.service}\n`; } if (log.tags && log.tags.length > 0) { responseText += `* Tags: ${log.tags.join(", ")}\n`; } if (log.timestamp) { responseText += `* Time: ${new Date(log.timestamp).toLocaleString()}\n`; } if (log.status) { responseText += `* Status: ${log.status}\n`; } if (log.message) { responseText += `* Message: ${log.message.slice(0, MAX_MESSAGE_LENGTH)}${ log.message.length > MAX_MESSAGE_LENGTH ? "..." : "" }\n`; } if (log.host) { responseText += `* Host: ${log.host}\n`; } responseText += `#### Key Attributes\n`; for (const key of [ "http.method", "http.url", "http.status_code", "error", ]) { if (log.attributes && key in log.attributes) { responseText += `* ${key}: \`${JSON.stringify( log.attributes[key] )}\`\n`; } } } return responseText; }; export const searchLogsHandler = async ( parameters: z.infer<typeof searchLogsZodSchema> ): Promise<ToolResponse> => { const validation = searchLogsZodSchema.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 searchLogs(validatedParams); const summaryText = generateSummaryText(validation.data, result); const urlText = `[View in Datadog](https://app.datadoghq.com/logs?query=${encodeURIComponent( validation.data.filterQuery )}&start=${validation.data.filterFrom}&end=${validation.data.filterTo})`; return createSuccessResponse([summaryText, urlText]); } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return createErrorResponse(`Log search 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