Skip to main content
Glama

Last9 Observability MCP

Official
traces.go5.14 kB
package traces import ( "context" "encoding/json" "fmt" "io" "net/http" "time" "last9-mcp/internal/models" "last9-mcp/internal/utils" "github.com/modelcontextprotocol/go-sdk/mcp" ) // GetTracesDescription provides the description for the traces query tool const GetTracesDescription = `Query distributed traces across all services using trace JSON pipeline queries. This tool provides comprehensive access to trace data for debugging performance issues, understanding request flows, and analyzing distributed system behavior. It accepts raw JSON pipeline queries for maximum flexibility. The tool uses a pipeline-based query system similar to the logs API, allowing complex filtering and aggregation operations on trace data. Parameters: - tracejson_query: (Required) JSON pipeline query for traces. Use the tracejson_query_builder prompt to generate JSON pipeline queries from natural language - start_time_iso: (Optional) Start time in ISO format (YYYY-MM-DD HH:MM:SS) - end_time_iso: (Optional) End time in ISO format (YYYY-MM-DD HH:MM:SS) - lookback_minutes: (Optional) Number of minutes to look back from current time (default: 60) - limit: (Optional) Maximum number of traces to return (default: 20, range: 1-100) Returns comprehensive trace data including trace IDs, spans, durations, timestamps, and metadata. Example tracejson_query structures: - Simple filter: [{"type": "filter", "query": {"$eq": ["ServiceName", "api"]}}] - Multiple conditions: [{"type": "filter", "query": {"$and": [{"$eq": ["ServiceName", "api"]}, {"$eq": ["StatusCode", "STATUS_CODE_ERROR"]}]}}] - Trace ID lookup: [{"type": "filter", "query": {"$eq": ["TraceId", "abc123"]}}]` // GetTracesArgs represents the input arguments for the traces query tool type GetTracesArgs struct { TracejsonQuery []interface{} `json:"tracejson_query,omitempty"` StartTimeISO string `json:"start_time_iso,omitempty"` EndTimeISO string `json:"end_time_iso,omitempty"` LookbackMinutes int `json:"lookback_minutes,omitempty"` Limit int `json:"limit,omitempty"` } // NewGetTracesHandler creates a handler for getting traces using tracejson_query parameter func NewGetTracesHandler(client *http.Client, cfg models.Config) func(context.Context, *mcp.CallToolRequest, GetTracesArgs) (*mcp.CallToolResult, any, error) { return func(ctx context.Context, req *mcp.CallToolRequest, args GetTracesArgs) (*mcp.CallToolResult, any, error) { // Check if tracejson_query is provided if len(args.TracejsonQuery) == 0 { return nil, nil, fmt.Errorf("tracejson_query parameter is required. Use the tracejson_query_builder prompt to generate JSON pipeline queries from natural language") } // Handle tracejson_query directly result, err := handleTraceJSONQuery(ctx, client, cfg, args.TracejsonQuery, args) if err != nil { return nil, nil, err } return result, nil, nil } } func handleTraceJSONQuery(ctx context.Context, client *http.Client, cfg models.Config, tracejsonQuery interface{}, args GetTracesArgs) (*mcp.CallToolResult, error) { // Determine time range from parameters startTime, endTime, err := parseTimeRangeFromArgs(args) if err != nil { return nil, fmt.Errorf("failed to parse time range: %v", err) } // Use util to execute the query resp, err := utils.MakeTracesJSONQueryAPI(ctx, client, cfg, tracejsonQuery, startTime, endTime, args.Limit) if err != nil { return nil, fmt.Errorf("failed to call trace JSON query API: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("traces API request failed with status %d: %s", resp.StatusCode, string(body)) } // Parse response var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, fmt.Errorf("failed to decode response: %v", err) } // Return the result in MCP format return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{ Text: formatJSON(result), }, }, }, nil } // parseTimeRangeFromArgs extracts start and end times from GetTracesArgs func parseTimeRangeFromArgs(args GetTracesArgs) (int64, int64, error) { now := time.Now() // Default to last hour if no time parameters provided startTime := now.Add(-time.Hour).UnixMilli() endTime := now.UnixMilli() // Check for lookback_minutes if args.LookbackMinutes > 0 { startTime = now.Add(-time.Duration(args.LookbackMinutes) * time.Minute).UnixMilli() } // Check for explicit start_time_iso if args.StartTimeISO != "" { if parsed, err := time.Parse("2006-01-02 15:04:05", args.StartTimeISO); err == nil { startTime = parsed.UnixMilli() } } // Check for explicit end_time_iso if args.EndTimeISO != "" { if parsed, err := time.Parse("2006-01-02 15:04:05", args.EndTimeISO); err == nil { endTime = parsed.UnixMilli() } } return startTime, endTime, nil } // formatJSON formats JSON for display func formatJSON(data interface{}) string { bytes, err := json.MarshalIndent(data, "", " ") if err != nil { return fmt.Sprintf("%v", data) } return string(bytes) }

Latest Blog Posts

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

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