Skip to content
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
125 changes: 26 additions & 99 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,92 +348,38 @@ In case multi-cluster support is enabled (default) and you have access to multip

<summary>kiali</summary>

- **kiali_graph** - Check the status of my mesh by querying Kiali graph
- **kiali_get_mesh_graph** - Returns the topology of a specific namespaces, health, status of the mesh and namespaces. Use this for high-level overviews
- `graphType` (`string`) - Type of graph to return: 'versionedApp', 'app', 'service', 'workload', 'mesh'. Default: 'versionedApp'
- `namespace` (`string`) - Optional single namespace to include in the graph (alternative to namespaces)
- `namespaces` (`string`) - Optional comma-separated list of namespaces to include in the graph

- **kiali_mesh_status** - Get the status of mesh components including Istio, Kiali, Grafana, Prometheus and their interactions, versions, and health status

- **kiali_istio_config** - Get all Istio configuration objects in the mesh including their full YAML resources and details

- **kiali_istio_object_details** - Get detailed information about a specific Istio object including validation and help information
- `group` (`string`) **(required)** - API group of the Istio object (e.g., 'networking.istio.io', 'gateway.networking.k8s.io')
- `kind` (`string`) **(required)** - Kind of the Istio object (e.g., 'DestinationRule', 'VirtualService', 'HTTPRoute', 'Gateway')
- `name` (`string`) **(required)** - Name of the Istio object
- `namespace` (`string`) **(required)** - Namespace containing the Istio object
- `version` (`string`) **(required)** - API version of the Istio object (e.g., 'v1', 'v1beta1')

- **kiali_istio_object_patch** - Modify an existing Istio object using PATCH method. The JSON patch data will be applied to the existing object.
- `group` (`string`) **(required)** - API group of the Istio object (e.g., 'networking.istio.io', 'gateway.networking.k8s.io')
- `json_patch` (`string`) **(required)** - JSON patch data to apply to the object
- `kind` (`string`) **(required)** - Kind of the Istio object (e.g., 'DestinationRule', 'VirtualService', 'HTTPRoute', 'Gateway')
- `name` (`string`) **(required)** - Name of the Istio object
- `namespace` (`string`) **(required)** - Namespace containing the Istio object
- `version` (`string`) **(required)** - API version of the Istio object (e.g., 'v1', 'v1beta1')

- **kiali_istio_object_create** - Create a new Istio object using POST method. The JSON data will be used to create the new object.
- `group` (`string`) **(required)** - API group of the Istio object (e.g., 'networking.istio.io', 'gateway.networking.k8s.io')
- `json_data` (`string`) **(required)** - JSON data for the new object
- `kind` (`string`) **(required)** - Kind of the Istio object (e.g., 'DestinationRule', 'VirtualService', 'HTTPRoute', 'Gateway')
- `namespace` (`string`) **(required)** - Namespace where the Istio object will be created
- `version` (`string`) **(required)** - API version of the Istio object (e.g., 'v1', 'v1beta1')

- **kiali_istio_object_delete** - Delete an existing Istio object using DELETE method.
- `group` (`string`) **(required)** - API group of the Istio object (e.g., 'networking.istio.io', 'gateway.networking.k8s.io')
- `kind` (`string`) **(required)** - Kind of the Istio object (e.g., 'DestinationRule', 'VirtualService', 'HTTPRoute', 'Gateway')
- `name` (`string`) **(required)** - Name of the Istio object
- `namespace` (`string`) **(required)** - Namespace containing the Istio object
- `version` (`string`) **(required)** - API version of the Istio object (e.g., 'v1', 'v1beta1')

- **kiali_validations_list** - List all the validations in the current cluster from all namespaces
- `namespace` (`string`) - Optional single namespace to retrieve validations from (alternative to namespaces)
- `namespaces` (`string`) - Optional comma-separated list of namespaces to retrieve validations from

- **kiali_namespaces** - Get all namespaces in the mesh that the user has access to

- **kiali_services_list** - Get all services in the mesh across specified namespaces with health and Istio resource information
- `rateInterval` (`string`) - Rate interval for fetching (e.g., '10m', '5m', '1h'). Default: '60s'

- **kiali_manage_istio_config** - Manages Istio configuration objects (Gateways, VirtualServices, etc.). Can list (objects and validations), get, create, patch, or delete objects
- `action` (`string`) **(required)** - Action to perform: list, get, create, patch, or delete
- `group` (`string`) - API group of the Istio object (e.g., 'networking.istio.io', 'gateway.networking.k8s.io')
- `json_data` (`string`) - JSON data to apply or create the object
- `kind` (`string`) - Kind of the Istio object (e.g., 'DestinationRule', 'VirtualService', 'HTTPRoute', 'Gateway')
- `name` (`string`) - Name of the Istio object
- `namespace` (`string`) - Namespace containing the Istio object
- `version` (`string`) - API version of the Istio object (e.g., 'v1', 'v1beta1')

- **kiali_get_resource_details** - Gets lists or detailed info for Kubernetes resources (services, workloads) within the mesh
- `namespaces` (`string`) - Comma-separated list of namespaces to get services from (e.g. 'bookinfo' or 'bookinfo,default'). If not provided, will list services from all accessible namespaces
- `resource_name` (`string`) - Name of the resource to get details for (optional string - if provided, gets details; if empty, lists all).
- `resource_type` (`string`) - Type of resource to get details for (service, workload)

- **kiali_service_details** - Get detailed information for a specific service in a namespace, including validation, health status, and configuration
- `namespace` (`string`) **(required)** - Namespace containing the service
- `service` (`string`) **(required)** - Name of the service to get details for

- **kiali_service_metrics** - Get metrics for a specific service in a namespace. Supports filtering by time range, direction (inbound/outbound), reporter, and other query parameters
- `byLabels` (`string`) - Comma-separated list of labels to group metrics by (e.g., 'source_workload,destination_service'). Optional
- `direction` (`string`) - Traffic direction: 'inbound' or 'outbound'. Optional, defaults to 'outbound'
- `duration` (`string`) - Duration of the query period in seconds (e.g., '1800' for 30 minutes). Optional, defaults to 1800 seconds
- `namespace` (`string`) **(required)** - Namespace containing the service
- `quantiles` (`string`) - Comma-separated list of quantiles for histogram metrics (e.g., '0.5,0.95,0.99'). Optional
- `rateInterval` (`string`) - Rate interval for metrics (e.g., '1m', '5m'). Optional, defaults to '1m'
- `reporter` (`string`) - Metrics reporter: 'source', 'destination', or 'both'. Optional, defaults to 'source'
- `requestProtocol` (`string`) - Filter by request protocol (e.g., 'http', 'grpc', 'tcp'). Optional
- `service` (`string`) **(required)** - Name of the service to get metrics for
- `step` (`string`) - Step between data points in seconds (e.g., '15'). Optional, defaults to 15 seconds

- **kiali_workloads_list** - Get all workloads in the mesh across specified namespaces with health and Istio resource information
- `namespaces` (`string`) - Comma-separated list of namespaces to get workloads from (e.g. 'bookinfo' or 'bookinfo,default'). If not provided, will list workloads from all accessible namespaces

- **kiali_workload_details** - Get detailed information for a specific workload in a namespace, including validation, health status, and configuration
- `namespace` (`string`) **(required)** - Namespace containing the workload
- `workload` (`string`) **(required)** - Name of the workload to get details for

- **kiali_workload_metrics** - Get metrics for a specific workload in a namespace. Supports filtering by time range, direction (inbound/outbound), reporter, and other query parameters
- **kiali_get_metrics** - Gets lists or detailed info for Kubernetes resources (services, workloads) within the mesh
- `byLabels` (`string`) - Comma-separated list of labels to group metrics by (e.g., 'source_workload,destination_service'). Optional
- `direction` (`string`) - Traffic direction: 'inbound' or 'outbound'. Optional, defaults to 'outbound'
- `duration` (`string`) - Duration of the query period in seconds (e.g., '1800' for 30 minutes). Optional, defaults to 1800 seconds
- `namespace` (`string`) **(required)** - Namespace containing the workload
- `duration` (`string`) - Time range to get metrics for (optional string - if provided, gets metrics; if empty, get default 1800s).
- `namespace` (`string`) **(required)** - Namespace to get resources from
- `quantiles` (`string`) - Comma-separated list of quantiles for histogram metrics (e.g., '0.5,0.95,0.99'). Optional
- `rateInterval` (`string`) - Rate interval for metrics (e.g., '1m', '5m'). Optional, defaults to '1m'
- `reporter` (`string`) - Metrics reporter: 'source', 'destination', or 'both'. Optional, defaults to 'source'
- `requestProtocol` (`string`) - Filter by request protocol (e.g., 'http', 'grpc', 'tcp'). Optional
- `resource_name` (`string`) **(required)** - Name of the resource to get details for (optional string - if provided, gets details; if empty, lists all).
- `resource_type` (`string`) **(required)** - Type of resource to get details for (service, workload)
- `step` (`string`) - Step between data points in seconds (e.g., '15'). Optional, defaults to 15 seconds
- `workload` (`string`) **(required)** - Name of the workload to get metrics for

- **kiali_health** - Get health status for apps, workloads, and services across specified namespaces in the mesh. Returns health information including error rates and status for the requested resource type
- `namespaces` (`string`) - Comma-separated list of namespaces to get health from (e.g. 'bookinfo' or 'bookinfo,default'). If not provided, returns health for all accessible namespaces
- `queryTime` (`string`) - Unix timestamp (in seconds) for the prometheus query. If not provided, uses current time. Optional
- `rateInterval` (`string`) - Rate interval for fetching error rate (e.g., '10m', '5m', '1h'). Default: '10m'
- `type` (`string`) - Type of health to retrieve: 'app', 'service', or 'workload'. Default: 'app'

- **workload_logs** - Get logs for a specific workload's pods in a namespace. Only requires namespace and workload name - automatically discovers pods and containers. Optionally filter by container name, time range, and other parameters. Container is auto-detected if not specified.
- `container` (`string`) - Optional container name to filter logs. If not provided, automatically detects and uses the main application container (excludes istio-proxy and istio-init)
Expand All @@ -442,36 +388,17 @@ In case multi-cluster support is enabled (default) and you have access to multip
- `tail` (`integer`) - Number of lines to retrieve from the end of logs (default: 100)
- `workload` (`string`) **(required)** - Name of the workload to get logs for

- **kiali_app_traces** - Get distributed tracing data for a specific app in a namespace. Returns trace information including spans, duration, and error details for troubleshooting and performance analysis.
- `app` (`string`) **(required)** - Name of the app to get traces for
- **kiali_get_traces** - Gets traces for a specific resource (app, service, workload) in a namespace
- `clusterName` (`string`) - Cluster name for multi-cluster environments (optional)
- `endMicros` (`string`) - End time for traces in microseconds since epoch (optional)
- `limit` (`integer`) - Maximum number of traces to return (default: 100)
- `minDuration` (`integer`) - Minimum trace duration in microseconds (optional)
- `namespace` (`string`) **(required)** - Namespace containing the app
- `namespace` (`string`) **(required)** - Namespace to get resources from
- `resource_name` (`string`) **(required)** - Name of the resource to get details for (optional string - if provided, gets details; if empty, lists all).
- `resource_type` (`string`) **(required)** - Type of resource to get metrics for (app, service, workload)
- `startMicros` (`string`) - Start time for traces in microseconds since epoch (optional)
- `tags` (`string`) - JSON string of tags to filter traces (optional)

- **kiali_service_traces** - Get distributed tracing data for a specific service in a namespace. Returns trace information including spans, duration, and error details for troubleshooting and performance analysis.
- `clusterName` (`string`) - Cluster name for multi-cluster environments (optional)
- `endMicros` (`string`) - End time for traces in microseconds since epoch (optional)
- `limit` (`integer`) - Maximum number of traces to return (default: 100)
- `minDuration` (`integer`) - Minimum trace duration in microseconds (optional)
- `namespace` (`string`) **(required)** - Namespace containing the service
- `service` (`string`) **(required)** - Name of the service to get traces for
- `startMicros` (`string`) - Start time for traces in microseconds since epoch (optional)
- `tags` (`string`) - JSON string of tags to filter traces (optional)

- **kiali_workload_traces** - Get distributed tracing data for a specific workload in a namespace. Returns trace information including spans, duration, and error details for troubleshooting and performance analysis.
- `clusterName` (`string`) - Cluster name for multi-cluster environments (optional)
- `endMicros` (`string`) - End time for traces in microseconds since epoch (optional)
- `limit` (`integer`) - Maximum number of traces to return (default: 100)
- `minDuration` (`integer`) - Minimum trace duration in microseconds (optional)
- `namespace` (`string`) **(required)** - Namespace containing the workload
- `startMicros` (`string`) - Start time for traces in microseconds since epoch (optional)
- `tags` (`string`) - JSON string of tags to filter traces (optional)
- `workload` (`string`) **(required)** - Name of the workload to get traces for

</details>


Expand All @@ -488,4 +415,4 @@ Compile the project and run the Kubernetes MCP server with [mcp-inspector](https
make build
# Run the Kubernetes MCP server with mcp-inspector
npx @modelcontextprotocol/inspector@latest $(pwd)/kubernetes-mcp-server
```
```
1 change: 0 additions & 1 deletion pkg/kiali/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,4 @@ const (
WorkloadDetailsEndpoint = "/api/namespaces/%s/workloads/%s"
WorkloadMetricsEndpoint = "/api/namespaces/%s/workloads/%s/metrics"
ValidationsEndpoint = "/api/istio/validations"
ValidationsListEndpoint = "/api/istio/validations"
)
142 changes: 142 additions & 0 deletions pkg/kiali/get_mesh_graph.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package kiali

import (
"context"
"encoding/json"
"strings"
"sync"
)

type GetMeshGraphResponse struct {
Graph json.RawMessage `json:"graph,omitempty"`
Health json.RawMessage `json:"health,omitempty"`
MeshStatus json.RawMessage `json:"mesh_status,omitempty"`
Namespaces json.RawMessage `json:"namespaces,omitempty"`
Errors map[string]string `json:"errors,omitempty"`
}

// GetMeshGraph fetches multiple Kiali endpoints in parallel and returns a combined response.
// Each field in the response corresponds to one API call result.
// - graph: /api/namespaces/graph (optionally filtered by namespaces)
// - health: /api/clusters/health (optionally filtered by namespaces and queryParams)
// - status(mesh):/api/mesh/graph
// - namespaces: /api/namespaces
func (k *Kiali) GetMeshGraph(ctx context.Context, namespaces []string, queryParams map[string]string) (string, error) {
Copy link
Member

@manusa manusa Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, this is a good candidate to try out MCP progress notifications (Not in this PR)

cleaned := make([]string, 0, len(namespaces))
for _, ns := range namespaces {
ns = strings.TrimSpace(ns)
if ns != "" {
cleaned = append(cleaned, ns)
}
}

resp := GetMeshGraphResponse{
Errors: make(map[string]string),
}

var errorsMu sync.Mutex
var wg sync.WaitGroup
wg.Add(4)

// Graph
go func() {
defer wg.Done()
data, err := k.getGraph(ctx, cleaned, queryParams)
if err != nil {
errorsMu.Lock()
resp.Errors["graph"] = err.Error()
errorsMu.Unlock()
return
}
resp.Graph = data
}()

// Health
go func() {
defer wg.Done()
data, err := k.getHealth(ctx, cleaned, queryParams)
if err != nil {
errorsMu.Lock()
resp.Errors["health"] = err.Error()
errorsMu.Unlock()
return
}
resp.Health = data
}()

// Mesh status
go func() {
defer wg.Done()
data, err := k.getMeshStatus(ctx)
if err != nil {
errorsMu.Lock()
resp.Errors["mesh_status"] = err.Error()
errorsMu.Unlock()
return
}
resp.MeshStatus = data
}()

// Namespaces
go func() {
defer wg.Done()
data, err := k.getNamespaces(ctx)
if err != nil {
errorsMu.Lock()
resp.Errors["namespaces"] = err.Error()
errorsMu.Unlock()
return
}
resp.Namespaces = data
}()

wg.Wait()

// If no errors occurred, omit the errors map in the final JSON
if len(resp.Errors) == 0 {
resp.Errors = nil
}

encoded, err := json.Marshal(resp)
if err != nil {
return "", err
}
return string(encoded), nil
}

// getGraph wraps the Graph call and returns raw JSON.
func (k *Kiali) getGraph(ctx context.Context, namespaces []string, queryParams map[string]string) (json.RawMessage, error) {
out, err := k.Graph(ctx, namespaces, queryParams)
if err != nil {
return nil, err
}
return json.RawMessage([]byte(out)), nil
}

// getHealth wraps the Health call and returns raw JSON.
func (k *Kiali) getHealth(ctx context.Context, namespaces []string, queryParams map[string]string) (json.RawMessage, error) {
nsParam := strings.Join(namespaces, ",")
out, err := k.Health(ctx, nsParam, queryParams)
if err != nil {
return nil, err
}
return json.RawMessage([]byte(out)), nil
}

// getMeshStatus wraps the MeshStatus call and returns raw JSON.
func (k *Kiali) getMeshStatus(ctx context.Context) (json.RawMessage, error) {
out, err := k.MeshStatus(ctx)
if err != nil {
return nil, err
}
return json.RawMessage([]byte(out)), nil
}

// getNamespaces wraps the ListNamespaces call and returns raw JSON.
func (k *Kiali) getNamespaces(ctx context.Context) (json.RawMessage, error) {
out, err := k.ListNamespaces(ctx)
if err != nil {
return nil, err
}
return json.RawMessage([]byte(out)), nil
}
15 changes: 12 additions & 3 deletions pkg/kiali/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,24 @@ import (
// Graph calls the Kiali graph API using the provided Authorization header value.
// `namespaces` may contain zero, one or many namespaces. If empty, the API may return an empty graph
// or the server default, depending on Kiali configuration.
func (k *Kiali) Graph(ctx context.Context, namespaces []string) (string, error) {
func (k *Kiali) Graph(ctx context.Context, namespaces []string, queryParams map[string]string) (string, error) {
u, err := url.Parse(GraphEndpoint)
if err != nil {
return "", err
}
q := u.Query()
// Static graph parameters per requirements
q.Set("duration", "60s")
q.Set("graphType", "versionedApp")
// Defaults with optional overrides via queryParams
duration := "60s"
graphType := "versionedApp"
if v, ok := queryParams["rateInterval"]; ok && strings.TrimSpace(v) != "" {
duration = strings.TrimSpace(v)
}
if v, ok := queryParams["graphType"]; ok && strings.TrimSpace(v) != "" {
graphType = strings.TrimSpace(v)
}
q.Set("duration", duration)
q.Set("graphType", graphType)
q.Set("includeIdleEdges", "false")
q.Set("injectServiceNodes", "true")
q.Set("boxBy", "cluster,namespace,app")
Expand Down
Loading