Skip to main content
Glama

Last9 Observability MCP

Official
Apache 2.0
122
45
  • Apple
logs.go3.59 kB
package logs import ( "context" "encoding/json" "fmt" "io" "net/http" "time" "last9-mcp/internal/models" "last9-mcp/internal/utils" "github.com/modelcontextprotocol/go-sdk/mcp" ) // GetLogsArgs represents the input arguments for the get_logs tool type GetLogsArgs struct { LogjsonQuery []interface{} `json:"logjson_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"` } // NewGetLogsHandler creates a handler for getting logs using logjson_query parameter func NewGetLogsHandler(client *http.Client, cfg models.Config) func(context.Context, *mcp.CallToolRequest, GetLogsArgs) (*mcp.CallToolResult, any, error) { return func(ctx context.Context, req *mcp.CallToolRequest, args GetLogsArgs) (*mcp.CallToolResult, any, error) { // Check if logjson_query is provided if len(args.LogjsonQuery) == 0 { return nil, nil, fmt.Errorf("logjson_query parameter is required. Use the logjson_query_builder prompt to generate JSON pipeline queries from natural language") } // Handle logjson_query directly result, err := handleLogJSONQuery(ctx, client, cfg, args.LogjsonQuery, args) if err != nil { return nil, nil, err } return result, nil, nil } } func handleLogJSONQuery(ctx context.Context, client *http.Client, cfg models.Config, logjsonQuery interface{}, args GetLogsArgs) (*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.MakeLogsJSONQueryAPI(ctx, client, cfg, logjsonQuery, startTime, endTime) if err != nil { return nil, fmt.Errorf("failed to call log JSON query API: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("logs 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 GetLogsArgs func parseTimeRangeFromArgs(args GetLogsArgs) (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) }

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