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
6 changes: 5 additions & 1 deletion docs/MCP.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The trivy-operator-explorer **frontend** ships a built-in [Model Context Protoco

Every read tool (`list_images`, `get_image`, `list_cves`, `list_images_with_cve`) accepts an optional `cluster` input. Set it to a cluster name to scope results to that cluster, or omit it to aggregate across all clusters in the bucket. The ignore-list tools are global (not cluster-scoped), matching the sqlite schema.

The tools are intentionally primitives (`list_images`, `get_image`, `list_cves`, `list_images_with_cve`, `list_ignored_cves`, `ignore_cves`, `unignore_cves`) rather than task-specific helpers. An LLM client composes them to answer ad-hoc questions; worked examples are at the bottom of this page.
The tools are intentionally primitives (`list_clusters`, `list_images`, `get_image`, `list_cves`, `list_images_with_cve`, `list_ignored_cves`, `ignore_cves`, `unignore_cves`) rather than task-specific helpers. An LLM client composes them to answer ad-hoc questions; worked examples are at the bottom of this page.

## Configuration

Expand Down Expand Up @@ -52,6 +52,10 @@ curl -sS -H 'Content-Type: application/json' \

Each tool's full input/output JSON Schema is published over the MCP `tools/list` method. The summary below is the same `description` field returned in that listing.

### `list_clusters` (read)

List the cluster names whose trivy-operator reports are currently available. Call this first in a multi-cluster deployment, then pass a returned name as the optional `cluster` argument on the other read tools to scope results to that cluster (omit it to aggregate across all clusters). Takes no inputs; returns `{total, clusters}`.

### `list_images` (read)

List every container image known to the cluster (scanned by trivy-operator plus any unscanned images detected via running pods). Returns per-image summary with vulnerability counts grouped by severity, fix-available counts, OS metadata, and the workloads that use the image. Mirrors the filters available at `/api/v1/images`.
Expand Down
17 changes: 12 additions & 5 deletions internal/mcp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,19 @@ func newServer() *mcpsdk.Server {
const serverInstructions = `Trivy Operator Explorer MCP server.

Read-only and mutating tools for working with the vulnerability reports
produced by Aqua Security's trivy-operator in a Kubernetes cluster, plus a
persisted "ignored CVE" list.
produced by Aqua Security's trivy-operator across one or more Kubernetes
clusters (collected into a shared S3 bucket), plus a persisted "ignored CVE"
list.

Use the read tools (list_images, get_image, list_cves, list_images_with_cve,
list_ignored_cves) to inspect findings, then use the mutating tools
(ignore_cves, unignore_cves) to manage the ignore list per image.
Use the read tools (list_clusters, list_images, get_image, list_cves,
list_images_with_cve, list_ignored_cves) to inspect findings, then use the
mutating tools (ignore_cves, unignore_cves) to manage the ignore list per image.

Reports come from many clusters. Call list_clusters first to discover the
available cluster names, then pass one as the optional "cluster" argument on
list_images/get_image/list_cves/list_images_with_cve to scope results to that
cluster. Omit "cluster" to aggregate across all clusters. The ignore list is
global (not cluster-scoped).

Every Vulnerability returned from list_images, get_image, list_cves, and
list_images_with_cve includes the trivy classification fields "class" (e.g.
Expand Down
28 changes: 28 additions & 0 deletions internal/mcp/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ const defaultRegistry = "index.docker.io"
// declared via mcp.AddTool so the SDK auto-generates input/output JSON
// Schemas from the Go types.
func registerTools(s *mcpsdk.Server) {
mcpsdk.AddTool(s, &mcpsdk.Tool{
Name: "list_clusters",
Description: "List the cluster names whose trivy-operator reports are currently available. " +
"Use a returned name as the optional `cluster` argument on the other tools to scope " +
"results to a single cluster; omit `cluster` to aggregate across all of them.",
}, listClustersTool)

mcpsdk.AddTool(s, &mcpsdk.Tool{
Name: "list_images",
Description: "List every container image known to the cluster (scanned by trivy-operator " +
Expand Down Expand Up @@ -79,6 +86,27 @@ func registerTools(s *mcpsdk.Server) {
}, unignoreCVEsTool)
}

// ----- list_clusters -----

// listClustersParams intentionally has no fields; list_clusters takes no input.
type listClustersParams struct{}

// listClustersResult wraps the cluster-name slice in an object so the
// auto-generated MCP output schema has type "object", which the spec requires
// for structured tool output.
type listClustersResult struct {
Total int `json:"total"`
Clusters []string `json:"clusters"`
}

func listClustersTool(_ context.Context, _ *mcpsdk.CallToolRequest, _ listClustersParams) (*mcpsdk.CallToolResult, listClustersResult, error) {
clusters := source.ListClusters()
if clusters == nil {
clusters = []string{}
}
return nil, listClustersResult{Total: len(clusters), Clusters: clusters}, nil
}

// ----- list_images -----

type listImagesParams struct {
Expand Down
Loading