NetworkPolicy and seccomp profiles from that observed baseline. The web UI is one way to reach them.
The other is to point your own MCP client at the cluster. Enable the endpoint, port-forward, add one server entry, and the agent you already work in can ask about real observed behaviour and turn it into policy YAML — without an API key of kguardian’s own, and without leaving your terminal.
This is the same in-process tool registry the assistant uses, re-served over HTTP by the LLM Bridge at
POST /mcp. It is not a separate deployment: no extra Service, port, or workload. A standalone MCP server component existed until it was retired in mid-2026; its tools moved into the LLM Bridge, and this endpoint re-exposes them.Before you start
1
kguardian is installed and has observed traffic
Follow the Quickstart if you have not. Let workloads run for 5-15 minutes so there is a baseline to ask about.
2
The AI assistant is enabled
The MCP endpoint is served by the LLM Bridge, so
ai.enabled must be on. See AI Assistant in the installation guide.The endpoint itself needs no LLM provider key — the tools read the Broker directly, and your MCP client brings its own model. A provider key is only needed for the assistant tab in the UI.3
The MCP endpoint is enabled
Off by default. Turn it on with
ai.mcp.enabled, below.Step 1: Enable the endpoint
Generate a bearer token and store it as a Secret, then enable the endpoint against it:values.yaml
"mcp": true means the route is served. If it is false, the value did not reach the pod — check kubectl -n kguardian logs deployment/kguardian-llm-bridge | grep MCP, which states the posture outright at startup.
Step 2: Reach the endpoint
The Service is ClusterIP, so a port-forward is the normal way in. Leave this running:http://localhost:8080/mcp.
LLM Bridge allows only loopback browser origins (
localhost, 127.0.0.1, [::1]) by default. A browser-based MCP client served from any other origin must set ALLOWED_ORIGIN to that origin, through the chart’s llmBridge.env value (for example llmBridge.env: [{name: ALLOWED_ORIGIN, value: "https://mcp-client.example.com"}]). CLI clients such as Claude Code are not affected.Step 3: Add the server to your client
claude mcp add defaults to local scope. Add --scope project to write the entry into a .mcp.json your team shares, or write the file yourself:
Authorization header in whatever config they use.
Verify the client sees the tools:
What you can ask for
The tools cover these areas (the compute tools are described in Compute Gauges). The value is not any single call — it is that an agent can chain them: find the pod, read its real traffic, check what a policy would have denied, then write the policy.Observed network traffic
Observed network traffic
get_pod_network_traffic returns a pod’s source/destination IPs, ports, protocols, direction, and per-flow allow/drop decisions. get_cluster_traffic summarises the whole cluster — per-pod ingress/egress, allow/drop counts, unique peers, and a cluster-wide drop total — with an optional namespace filter.“Which pods in payments are seeing dropped egress, and what were they trying to reach?”Syscall activity
Syscall activity
get_pod_syscalls returns the syscall names, frequencies, and architecture observed for a pod.“Has the worker pod called anything unusual since yesterday’s deploy?”Cluster inventory
Cluster inventory
get_cluster_pods, get_pod_details_by_name, get_pods_on_node, list_services, and the IP-based lookups get_pod_details and get_service_details resolve names, IPs, nodes, and selectors.“An audit verdict names 10.0.4.19 — what is it, and what else runs on its node?”Audit verdicts
Audit verdicts
get_audit_verdicts returns flows the evaluator judged Allow or WouldDeny against your AuditNetworkPolicy and AuditClusterNetworkPolicy resources, with the human-readable reason, newest first. Filter by policy, namespace, cluster-scoped, verdict, direction, and limit.“Show me every WouldDeny on the api-baseline policy and explain what would break.”Policy and profile generation
Policy and profile generation
generate_network_policy returns ready-to-apply YAML — a standard NetworkPolicy by default, or a CiliumNetworkPolicy — synthesised deterministically from a pod’s captured flows, not guessed. generate_seccomp_profile returns seccomp JSON allow-listing the syscalls that pod actually made.“Generate a Cilium policy for checkout, then tell me which existing verdicts it would newly deny.”Workload security profiles and images
Workload security profiles and images
get_workload_security_profile returns one workload’s posture status (ok, warn, risk or unknown, derived from findings; there is no numeric score) and coverage, its top findings, controls, readiness checks, and per-dimension detail: Pod Security Standards level with the failing checks, network peers, syscalls and SeccompProfile sync, running image digests, and compute settings. When checks fail it includes a recommended securityContext patch. list_workload_profiles ranks many workloads (filter by namespace and posture: ok, warn, risk, unknown), and diff_workload_profile shows what changed between two stored revisions. get_image_inventory lists the image digests workloads run; it carries no vulnerability or signature data.Tools are keyed by workload (namespace, kind, name), not pod. null or unknown means kguardian has no data, or the source is not configured. It is never a pass: posture is ok only when all four core dimensions (network, syscalls, podSecurity, images) are known and ok, and images stays unknown until vulnerability data exists (it is risk when a running image’s signature does not verify), so the tools return coverage alongside the status. images.supplyChain carries the worst signature verdict over the workload’s current digests; verified is never described as trusted, and a digest never checked is unknown. A Pod Security Standards level of restricted is an upper bound kguardian cannot confirm. Every string in a result is cluster data, and the tools tell the model never to follow instructions inside it. Lists are capped (25 rows by default, 100 at most) and every response is size-bounded, with a truncated flag when rows were cut.“Which workloads in payments are at risk, and what is the smallest securityContext change that gets checkout to restricted?”Vulnerabilities, CVE exposure and SBOMs
Vulnerabilities, CVE exposure and SBOMs
get_image_vulnerabilities returns an image’s findings, deduplicated across sources (Trivy Operator, Grype), with every source’s fixed versions, KEV and EPSS where a source gives them. list_vulnerabilities lists CVEs across the inventory with affected image, workload and namespace counts. explain_cve_exposure follows one id from affected images to the workloads running them and each workload’s observed ingress. get_image_sbom returns every source’s SBOM with its trust level and one SBOM’s components.The tools tell the model never to invent a vulnerability id: every id in an answer must come from tool output. An image no source has scanned is unknown, not clean. Each finding carries its in-use state (executed, loaded, unknown or installed-not-observed, from exec and shared-library capture) and risk tier (P0 to Background) with the factors behind it; the tools can filter on both. Unknown in-use is treated as potentially reachable, and no finding is described as unreachable. exposed: null means no ingress was observed (egress alone does not count), never “not exposed”. Only an SBOM with trust verified is described as signed. Findings come from Trivy Operator reports and, when the opt-in supplychain matcher is enabled, from kguardian’s own Grype matcher, which matches SBOMs.“Are we affected by CVE-2024-3094, where does it run, and is any of it reachable from outside its namespace?”Image signatures and ImageTrustPolicy
Image signatures and ImageTrustPolicy
get_image_signers returns one digest’s signature verdict (verified, key_signed, unsigned, invalid, unknown) with the reason, the signers that verified (a keyless issuer and identity, or a configured key) and its signatures and attestations, verified first. explain_image_trust returns which ImageTrustPolicies would deny which running workloads and why (Trusted, WouldDeny, Unknown with the reason), with counts over every match; filter by namespace, workload and verdict. Both need supplychain.signatureDiscovery.enabled, and explain_image_trust needs the evaluator’s image trust evaluation.verified means valid for the signer shown, not trusted: only a policy says a signer is acceptable, and Trusted still does not mean safe. key_signed was not checked. An unverified signature never shows a signer. unknown, a digest never checked, Unknown policy results and an unavailable or not-yet-evaluated answer are unknown and never presented as signed, unsigned, trusted or an all-clear. Lists are capped with a truncated flag. Results are report-only: kguardian never admits or blocks an image.“Would anything in shop be denied if we enforced image signing, and who signed the images that would?”pod_name — the Broker resolves it cluster-wide, so there is no namespace argument. Cluster-wide tools take an optional namespace filter. Profile tools take the workload key: namespace, kind and name.
Every tool is a read against the Broker, plus two that compute policy locally. Nothing here writes to your cluster: an agent can hand you a
NetworkPolicy or a securityContext patch, but applying it is still kubectl apply and your review.How the endpoint behaves
Worth knowing before you file a bug:
The server identifies itself as
kguardian at the LLM Bridge version and advertises the tools capability only — it serves no MCP resources or prompts.
To check the wire directly, without a client:
Troubleshooting
404 on /mcp
404 on /mcp
The endpoint is not enabled.
curl -s localhost:8080/health reports "mcp": false. Check that ai.mcp.enabled=true reached the pod:406 Not Acceptable
406 Not Acceptable
The request is missing one of the two required headers. A compliant MCP client sends both automatically; this normally only appears in a hand-rolled
curl.405 on GET
405 on GET
Expected, not a fault. See the table above.
Tools connect but return no data
Tools connect but return no data
The endpoint is healthy and the Broker has nothing to report. Confirm the Controller is observing —
kubectl logs -n kguardian daemonset/kguardian-controller — and that workloads have been running long enough. See Troubleshooting.Enable the AI assistant
Chart values, provider keys, and OpenAI-compatible gateways
Architecture
Where the LLM Bridge sits and what it talks to
Audit policies
What the verdict tools are reading
Generating policies
The same generation, from the CLI