Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add service graph tool #41

Merged
merged 2 commits into from
Apr 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions tools/get_service_graph.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package tools

import (
"bytes"
"context"
"encoding/json"
"fmt"

mcpgolang "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/metoro-mcp-server/utils"
)

type GetServiceGraphHandlerArgs struct {
TimeConfig utils.TimeConfig `json:"time_config" jsonschema:"required,description=The time period to get the service graph for. e.g. if you want to get the graph for the last 5 minutes you would set time_period=5 and time_window=Minutes. You can also set an absoulute time range by setting start_time and end_time"`
ServiceName string `json:"serviceName" jsonschema:"required,description=The name of the service to get the graph for"`
Environments []string `json:"environments" jsonschema:"description=The environments to get the service graph for. If empty all environments will be used."`
}

type GetServiceGraphRequest struct {
// If Environments is not empty, only services that are in the list will be included in the graph.
// If Environments is empty, all services will be included in the graph.
Environments []string `json:"environments"`
// If InitialServices is not empty, only services that are in the list will be included in the graph.
// If InitialServices is empty, all services will be included in the graph.
InitialServices []string `json:"initialServices"`
// If EndingServices is not empty, only services that are in the list will be included in the graph.
// If EndingServices is empty, all services will be included in the graph.
EndingServices []string `json:"endingServices"`
// StartTime is the start time of the graph in seconds since epoch
StartTime int64 `json:"startTime"`
// EndTime is the end time of the graph in seconds since epoch
EndTime int64 `json:"endTime"`
// The filters to apply to the traces, so for example, if you want to get traces for a specific service
// you can pass in a filter like {"service_name": ["microservice_a"]}
Filters map[string][]string `json:"filters"`
// ExcludeFilters are filters that should be excluded from the traces
// For example, if you want to get traces for all services except microservice_a you can pass in
// {"service_name": ["microservice_a"]}
ExcludeFilters map[string][]string `json:"excludeFilters"`
// Regexes are used to filter traces based on a regex inclusively
Regexes []string `json:"regexes"`
// ExcludeRegexes are used to filter traces based on a regex exclusively
ExcludeRegexes []string `json:"excludeRegexes"`
}

func GetServiceGraphHandler(ctx context.Context, arguments GetServiceGraphHandlerArgs) (*mcpgolang.ToolResponse, error) {
startTime, endTime, err := utils.CalculateTimeRange(arguments.TimeConfig)
if err != nil {
return nil, fmt.Errorf("error calculating time range: %v", err)
}

request := GetServiceGraphRequest{
StartTime: startTime,
EndTime: endTime,
Environments: arguments.Environments,
InitialServices: []string{arguments.ServiceName},
EndingServices: []string{arguments.ServiceName},
}

body, err := getServiceGraphMetoroCall(ctx, request)
if err != nil {
return nil, fmt.Errorf("error getting service graph: %v", err)
}
return mcpgolang.NewToolResponse(mcpgolang.NewTextContent(fmt.Sprintf("%s", string(body)))), nil
}

func getServiceGraphMetoroCall(ctx context.Context, request GetServiceGraphRequest) ([]byte, error) {
requestBody, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("error marshaling service graph request: %v", err)
}
return utils.MakeMetoroAPIRequest("POST", "serviceGraph", bytes.NewBuffer(requestBody), utils.GetAPIRequirementsFromRequest(ctx))
}
5 changes: 5 additions & 0 deletions tools/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,9 @@ And then you can call this tool (get_k8s_events) to get the specific events you
Description: "Get the source repository URL/path for a specific service. This tool is useful for finding where the code for a service is stored. You need to provide the service name time range and optionally specific environments to search in.",
Handler: GetSourceRepositoryHandler,
},
{
Name: "get_service_graph",
Description: "Get the service graph showing which services make calls to a given service and which services the given service makes calls to. This tool is useful for understanding service dependencies and call patterns.",
Handler: GetServiceGraphHandler,
},
}