Skip to main content
Glama

mcp-server-datadog

Apache 2.0
4,489
103
  • Apple
traces.test.ts9.18 kB
import { v2 } from '@datadog/datadog-api-client' import { describe, it, expect } from 'vitest' import { createDatadogConfig } from '../../src/utils/datadog' import { createTracesToolHandlers } from '../../src/tools/traces/tool' import { createMockToolRequest } from '../helpers/mock' import { http, HttpResponse } from 'msw' import { setupServer } from '../helpers/msw' import { baseUrl, DatadogToolResponse } from '../helpers/datadog' const tracesEndpoint = `${baseUrl}/v2/spans/events/search` describe('Traces Tool', () => { if (!process.env.DATADOG_API_KEY || !process.env.DATADOG_APP_KEY) { throw new Error('DATADOG_API_KEY and DATADOG_APP_KEY must be set') } const datadogConfig = createDatadogConfig({ apiKeyAuth: process.env.DATADOG_API_KEY, appKeyAuth: process.env.DATADOG_APP_KEY, site: process.env.DATADOG_SITE, }) const apiInstance = new v2.SpansApi(datadogConfig) const toolHandlers = createTracesToolHandlers(apiInstance) // https://docs.datadoghq.com/api/latest/spans/#search-spans describe.concurrent('list_traces', async () => { it('should list traces with basic query', async () => { const mockHandler = http.post(tracesEndpoint, async () => { return HttpResponse.json({ data: [ { id: 'span-id-1', type: 'spans', attributes: { service: 'web-api', name: 'http.request', resource: 'GET /api/users', trace_id: 'trace-id-1', span_id: 'span-id-1', parent_id: 'parent-id-1', start: 1640995100000000000, duration: 500000000, error: 1, meta: { 'http.method': 'GET', 'http.status_code': '500', 'error.type': 'Internal Server Error', }, }, }, { id: 'span-id-2', type: 'spans', attributes: { service: 'web-api', name: 'http.request', resource: 'GET /api/products', trace_id: 'trace-id-2', span_id: 'span-id-2', parent_id: 'parent-id-2', start: 1640995000000000000, duration: 300000000, error: 1, meta: { 'http.method': 'GET', 'http.status_code': '500', 'error.type': 'Internal Server Error', }, }, }, ], meta: { page: { after: 'cursor-value', }, }, }) }) const server = setupServer(mockHandler) await server.boundary(async () => { const request = createMockToolRequest('list_traces', { query: 'http.status_code:500', from: 1640995000, to: 1640996000, limit: 50, }) const response = (await toolHandlers.list_traces( request, )) as unknown as DatadogToolResponse expect(response.content[0].text).toContain('Traces:') expect(response.content[0].text).toContain('web-api') expect(response.content[0].text).toContain('GET /api/users') expect(response.content[0].text).toContain('GET /api/products') expect(response.content[0].text).toContain('count":2') })() server.close() }) it('should include service and operation filters', async () => { const mockHandler = http.post(tracesEndpoint, async () => { return HttpResponse.json({ data: [ { id: 'span-id-3', type: 'spans', attributes: { service: 'payment-service', name: 'process-payment', resource: 'process-payment', trace_id: 'trace-id-3', span_id: 'span-id-3', parent_id: 'parent-id-3', start: 1640995100000000000, duration: 800000000, error: 1, meta: { 'error.type': 'PaymentProcessingError', }, }, }, ], meta: { page: { after: null, }, }, }) }) const server = setupServer(mockHandler) await server.boundary(async () => { const request = createMockToolRequest('list_traces', { query: 'error:true', from: 1640995000, to: 1640996000, service: 'payment-service', operation: 'process-payment', }) const response = (await toolHandlers.list_traces( request, )) as unknown as DatadogToolResponse expect(response.content[0].text).toContain('payment-service') expect(response.content[0].text).toContain('process-payment') expect(response.content[0].text).toContain('PaymentProcessingError') })() server.close() }) it('should handle ascending sort', async () => { const mockHandler = http.post(tracesEndpoint, async () => { return HttpResponse.json({ data: [ { id: 'span-id-oldest', type: 'spans', attributes: { service: 'api', name: 'http.request', start: 1640995000000000000, }, }, { id: 'span-id-newest', type: 'spans', attributes: { service: 'api', name: 'http.request', start: 1640995100000000000, }, }, ], }) }) const server = setupServer(mockHandler) await server.boundary(async () => { const request = createMockToolRequest('list_traces', { query: '', from: 1640995000, to: 1640996000, sort: 'timestamp', // ascending order }) const response = (await toolHandlers.list_traces( request, )) as unknown as DatadogToolResponse expect(response.content[0].text).toContain('span-id-oldest') expect(response.content[0].text).toContain('span-id-newest') })() server.close() }) it('should handle empty response', async () => { const mockHandler = http.post(tracesEndpoint, async () => { return HttpResponse.json({ data: [], meta: { page: {}, }, }) }) const server = setupServer(mockHandler) await server.boundary(async () => { const request = createMockToolRequest('list_traces', { query: 'service:non-existent', from: 1640995000, to: 1640996000, }) const response = (await toolHandlers.list_traces( request, )) as unknown as DatadogToolResponse expect(response.content[0].text).toContain('Traces:') expect(response.content[0].text).toContain('count":0') expect(response.content[0].text).toContain('traces":[]') })() server.close() }) it('should handle null response data', async () => { const mockHandler = http.post(tracesEndpoint, async () => { return HttpResponse.json({ data: null, meta: { page: {}, }, }) }) const server = setupServer(mockHandler) await server.boundary(async () => { const request = createMockToolRequest('list_traces', { query: '', from: 1640995000, to: 1640996000, }) await expect(toolHandlers.list_traces(request)).rejects.toThrow( 'No traces data returned', ) })() server.close() }) it('should handle authentication errors', async () => { const mockHandler = http.post(tracesEndpoint, async () => { return HttpResponse.json( { errors: ['Authentication failed'] }, { status: 403 }, ) }) const server = setupServer(mockHandler) await server.boundary(async () => { const request = createMockToolRequest('list_traces', { query: '', from: 1640995000, to: 1640996000, }) await expect(toolHandlers.list_traces(request)).rejects.toThrow() })() server.close() }) it('should handle rate limit errors', async () => { const mockHandler = http.post(tracesEndpoint, async () => { return HttpResponse.json( { errors: ['Rate limit exceeded'] }, { status: 429 }, ) }) const server = setupServer(mockHandler) await server.boundary(async () => { const request = createMockToolRequest('list_traces', { query: '', from: 1640995000, to: 1640996000, }) await expect(toolHandlers.list_traces(request)).rejects.toThrow( /errors./, ) })() server.close() }) }) })

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/winor30/mcp-server-datadog'

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