BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Multi-Agent AI for Production Security Operations: An A2A and MCP Architecture in a 5G Core

Multi-Agent AI for Production Security Operations: An A2A and MCP Architecture in a 5G Core

Listen to this article -  0:00

Key Takeaways

  • Build the reviewer agent first, with codified safety constraints (policy as code, rather than LLM prompts) and a clear escalation path to a human, built into the protocol itself
  • Coordinate through an Agent-to-Agent (A2A) open protocol  and integrate the environment through Model Context Protocol (MCP). Open coordination and context protocols outlive frameworks; agents written eighteen months apart will still talk if they share A2A, and each new tool exposed via MCP is immediately available to every agent at near-zero marginal integration cost.
  • Gate LLM inference with classical anomaly detection. A lightweight Isolation Forest pre-filter on raw telemetry routes the LLM-driven agents only to genuinely novel samples. This approach makes the architecture reactive, where inference cost stays bounded, latency stays predictable, and the LLM does the work only humans were doing before.
  • Reject both the monolithic-LLM and the GenAI-on-SIEM patterns for high-stakes security operations centers. The former is non-deterministic in ways production cannot tolerate; the latter is a productivity tool, not an architectural advance. A multi-agent layer with anomaly-gated inference, policy-gated autonomy, and a real human-in-the-loop is the durable alternative.
  • Measure the right latency. The metric that matters in a production Security Operations Center (SOC) is the time between a new threat class appearing in the wild and your SOC having a deployed detection for it. Optimize the architecture for that latency.

The problem you are about to face

A 5G core in production generates more security telemetry per hour than most enterprise SOC see in a week. The bottleneck in a mature SOC is rarely analyst triage; rather, it is the detection-engineering team's ability to keep the rule base aligned with a threat landscape that evolves faster than rules can be written.

The architecture pattern described below builds on production security operations within a Tier-1 telco’s 5G core and has been continuously refined and improved over the past year through iterative operational feedback and internal deployments. It uses a multi-agent layer, coordinated through the A2A protocol and integrated with its environment through the MCP, with a privileged reviewer agent enforcing safety as code.

Measured against a baselined set of incident classes, it has reduced mean times to detect and to respond by approximately forty percent each, has autonomously generated more than eighty detection rules that would not previously have been written, and has compressed the human work required to produce a new rule from roughly three hours to fifteen minutes. The platform monitors ten to twenty 5G network functions concurrently.

Two Patterns That Don’t Work and Why

There are two dominant patterns in current industry literature on AI for security operations, and both, in my judgement, are dead ends at telco-core scale.

The Monolithic LLM 

Pipe security telemetry, asset context, and operator queries into one large model and ask it to emit detections and responses. It fails in production for three compounding reasons.

First, the context window is too small for the breadth of telemetry a real SOC handles. In addition, the model is non-deterministic in ways unacceptable for outputs that trigger automated isolation on production infrastructure. Finally, a single prompt edit changes the behavior of the entire SOC, which makes change management almost impossible.

GenAI Bolted Onto a Conventional SIEM/SOAR 

Most vendors are shipping an LLM assistant that summarizes alerts and drafts playbooks on top of an existing stack. It delivers analyst productivity gains. It does not change the structural shape of the SOC. Rules are still hand-written and time-to-coverage on a new threat class is still bound by your detection-engineering team's writing speed. If you are running a high-stakes SOC and you have evaluated either of these patterns and felt that something was off, this article is the alternative.

The Architectural Bet

Treat the SOC as a multi-agent system in which narrow, specialized agents collaborate through an open coordination protocol, integrate with their environment through an open context protocol, gate expensive LLM inference behind classical anomaly detection, and keep a human in the loop by design rather than by accident. The properties below are the ones we treat as non-negotiable.

Property 1: Narrow Agents with Single-Page Contracts 

Each agent has several responsibilities: detection-rule synthesis, alert triage, response action proposal, environment context retrieval, and cross-agent review. Each agent’s system prompt, tool list, output schema, and escalation contract fit on a single page. If you cannot read an agent contract on one page, decompose the agent.

The temptation with large language models is to give agents rich personalities and elaborate prompts. Resist this temptation. The best-performing agents in our evaluations have terse, job-description-like system prompts; cleverness in prompts is technical debt.

Property 2: Coordination Over an Open Protocol (A2A) 

Inter-agent traffic uses Agent-to-Agent (A2A) protocol exchanges. A2A was open-sourced by Google in April 2025 and transferred to the Linux Foundation in June 2025. In practice, the alternatives are framework-specific buses. Choosing an openly governed protocol matters because the useful life of a production multi-agent system is measured in years; the coordination layer's durability dominates any specific framework's convenience. We pair A2A with MCP (also donated by Anthropic to the Linux Foundation's Agentic AI Foundation in December 2025) and a CNCF substrate (e.g., Cilium, cert-manager, OPA, Kyverno, Argo CD, and Prometheus). The whole stack then sits under a single open governance umbrella, which is itself a procurement and compliance argument in regulated industries.

Property 3: Environment integration over MCP 

Every interaction an agent has with the underlying environment goes through Model Context Protocol servers. This interaction includes asset inventory lookups, current network topology, recent incident history, and configuration state. MCP gives the agents a stable, schema-validated interface to a 5G environment whose internal tools evolve on their own cadence. When a new asset class is added or an inventory system is replaced, the change is absorbed by an MCP server's adapter; no agent prompt is rewritten.

Property 4: A Privileged Reviewer Agent 

No agent may initiate an externally visible action without explicit approval from a reviewer agent whose safety constraints are codified, version-controlled, and independently testable. Externally visible actions here mean deploying a detection rule, executing a containment, or modifying a firewall policy. The reviewer is the safety floor of the system. In a critical-infrastructure deployment, autonomous action is acceptable only because the reviewer makes it so.

Because it is where most early multi-agent deployments fail, the instinct is to encode the reviewer's safety rules into a prompt and have the LLM reason about safety on the fly. This is a bad idea. The reviewer agent calls out to a separate policy layer (in our case, OPA) and acts on a deterministic verdict; the reviewer's own prompt is short, the policy itself is version-controlled code.

Property 5: Human-in-the-Loop Is a First-Class Output 

Every consequential decision has three terminal states: auto-execute, auto-reject, and escalate to a SOC analyst with the full reasoning chain attached. The third state is reached whenever reviewer confidence falls under threshold, the asset class is on the always-escalate list, or the proposed action would exceed a configured blast radius.

The discipline this approach enforces is unfashionable but essential: Some decisions should never be automated. The protocol envelope routes those decisions to a human queue with all agent reasoning attached and before any action is taken.

What the Reviewer’s Policy Actually Looks Like

Property 4 describes the reviewer as a policy layer, not a prompt. In practice, that layer is really two layers working together, OPA and Kyverno; they do not do the same job.

The reviewer agent, backed by OPA, decides whether an action is allowed from an operational risk perspective: blast radius, confidence, reversibility, and human escalation. Kyverno independently validates how that action is expressed on the Kubernetes substrate once it reaches the cluster: trusted image sources, workload identity, resource constraints, and admission control. OPA enforces business safety invariants. Kyverno enforces platform security invariants. Together they give the system defence in depth between agent reasoning and production execution.

A quick note on the fields the OPA policy below relies on. The proposing agent estimates the blast radius and confidence at proposal time. The blast radius is the share of customer traffic a proposed action could affect if it goes wrong, while confidence is how sure the proposing agent is that its own proposal is correct. Reversible depends on the action type itself, blocking a route has a defined rollback and deleting or reconfiguring something core often does not. Config_validated is different from the other three, it is set by the reviewer, never by the proposing agent, since an agent should not be able to mark its own configuration change as safe.

The input below is not what the proposing agent sends verbatim. The reviewer agent builds it from the proposal, adding fields like config_validated that only the reviewer is trusted to set.

package reviewer.policy
# Input shape, illustrative only. Built by the reviewer agent from the proposing agent's output, not sent as-is by that agent.
# {
#   "action": {
#     "type": "deploy_rule",           # deploy_rule, execute_containment, or modify_config
#     "blast_radius_pct": 0.8,         # estimated by the proposing agent at proposal time
#     "confidence": 0.94,              # the proposing agent's own estimate that its proposal is correct
#     "reversible": true,              # set from the action type, not estimated
#     "config_validated": true         # set by the reviewer, never by the proposing agent
#   },
#   "asset": {
#     "NF_role": "upf",
#     "element_id": "upf-fr-paris-04"
#   }
# }
#
# Thresholds referenced below, data.limits, come from a separate data document, not from this file.
default decision := {"result": "escalate", "reason": "no matching rule"}
decision := {"result": "auto_reject", "reason": "configuration change is not clearly validated"} if {
	input.action.type == "modify_config"
	input.action.config_validated == false
} else := {"result": "escalate", "reason": msg} if {
	sensitive_elements[input.asset.element_id]
	msg := sprintf("%s is a sensitive network element and always escalates", [input.asset.element_id])
} else := {"result": "auto_reject", "reason": msg} if {
	input.action.blast_radius_pct > data.limits[input.action.type].max_blast_radius_pct
	msg := sprintf("blast radius %.2f exceeds limit for %s", [input.action.blast_radius_pct, input.action.type])
} else := {"result": "auto_execute"} if {
	config_ok
	not sensitive_elements[input.asset.element_id]
	input.action.blast_radius_pct <= data.limits[input.action.type].max_blast_radius_pct
	input.action.confidence >= data.limits[input.action.type].min_confidence
	input.action.reversible == true
}
config_ok if {
	input.action.type != "modify_config"
}
config_ok if {
	input.action.type == "modify_config"
	input.action.config_validated == true
}
sensitive_elements := {"upf-fr-paris-04", "sepp-fr-edge-01"}

The thresholds themselves live in a separate data document, rather than hard-coded in the policy. This approach keeps the decision logic and the actual risk tolerance independently versioned. The SOC team can tighten a threshold without touching the rule structure itself.

{
  "limits": {
    "deploy_rule": {
      "max_blast_radius_pct": 0.5,
      "min_confidence": 0.7
    },
    "execute_containment": {
      "max_blast_radius_pct": 0.2,
      "min_confidence": 0.9
    },
    "modify_config": {
      "max_blast_radius_pct": 0.3,
      "min_confidence": 0.8
    }
  }
}

Suppose the detection engineering agent generates a Kubernetes deployment for a new detection sensor, which the reviewer approves based on blast radius and confidence. That approval is not the end of the story. Before the object reaches the Kubernetes API server, Kyverno checks it independently, and it can still reject the deployment even after the reviewer said yes.

The following code snippet is a rule that rejects any deployment pulling an image from outside the approved internal registry, which matters because an agent generating a manifest could reference the wrong image source by mistake, and because a compromised dependency points somewhere it should not.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: trusted-registry
spec:
  validationFailureAction: Enforce
  rules:
    - name: verify-registry
      match:
        any:
          - resources:
              kinds: ["Deployment"]
      validate:
        message: "Images must come from the internal trusted registry"
        pattern:
          spec:
            template:
              spec:
                containers:
                  - image: "registry.internal/*"


The second code snippet is a rule that catches a different kind of mistake, an agent proposing a fix that works, but opens far more sources than intended. 
A common failure mode when an agent is asked to resolve a connectivity or access issue is to widen a NetworkPolicy or a ConfigMap until the symptom disappears, without noticing that the fix now allows traffic or access it should never have granted.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: block-permissive-network-policy
spec:
  validationFailureAction: Enforce
  rules:
    - name: reject-allow-all-ingress
      match:
        any:
          - resources:
              kinds: ["NetworkPolicy"]
              namespaces: ["soc-agents"]
      validate:
        message: "NetworkPolicy must not allow ingress from all sources"
        deny:
          conditions:
            any:
              - key: "{{ request.object.spec.ingress[].from[] | length(@) }}"
                operator: Equals
                value: 0

An empty from field on an ingress rule defines "allow everything", which is exactly the kind of change that solves an immediate problem while quietly removing the network boundary on which the architecture depends. Kyverno rejects the request before it reaches the cluster, regardless of how reasonable the change looked to the agent that proposed it, or how urgent the prompting incident is.

This is not a replacement for the reviewer's judgment. OPA decides whether an action makes sense from a risk standpoint. Kyverno makes sure that whatever gets expressed as a Kubernetes object meets the cluster's own baseline, independently of how well or badly the agent that generated it reasoned about risk. Neither layer is sufficient on its own, and treating either as the final word would be a mistake.

Component Decomposition

Agent Responsibility Output Tools used
Triage Classify incoming security events; identify novelty Event classification + novelty flag (Isolation-Forest-gated, LLM invoked only on samples above the anomaly threshold) Asset inventory, historical detection index
Detection engineering Synthesize detection rules for newly observed patterns Candidate rule + test fixtures Detection index and telemetry samples, retrieved through the Context agent
Response Propose containment / mitigation actions for confirmed threats Candidate response action + blast-radius estimate Asset inventory and topology via Context; response actuators, read only at proposal time; retrieval of similar past remediation outcomes
Context Retrieve and structure environment data for other agents Structured context payload All inventory + topology MCP tools
Reviewer Validate proposals against safety constraints Approval / rejection / escalation Safety policy index (OPA); record of past reviewer decisions used to audit consistency over time

I will point out that Kyverno is not listed as a tool used by any single agent above. It sits after the reviewer, at Kubernetes admission time, and applies independently of what any agent decided.

The reviewer's safety constraints span four categories. Blast radius limits prevent proposed responses from affecting more than a configured percentage of customer traffic. Reversibility requirements require that every proposed response has a defined rollback. Confidence thresholds prevent execution of proposals below a calibrated confidence from escalating rather than auto executing all requests Finally, human-in-the-loop triggers always escalate specific asset classes. A fifth, narrower rule sits alongside these: Any configuration change the reviewer cannot validate as unambiguous is rejected outright, regardless of how the other four categories score. These constraints live outside any LLM prompt, in a policy layer the reviewer calls directly at evaluation time.

Why the System Stays Responsive

A fair objection to multi-agent LLM systems in production is latency. If every security event triggered the full fan-out, triage from context to detection-engineering, response, and reviewer, each invoking an LLM, the per-event cost in time and tokens would be untenable at telco core volumes.

The architecture solves this problem with anomaly-gated inference. Before the triage agent invokes any LLM, the raw telemetry feature vector is scored by an Isolation Forest model, which is an unsupervised anomaly detection algorithm, trained on rolling historical traffic. Isolation Forest was chosen deliberately: It is fast at inference, requires no labelling, handles high-dimensional inputs well, and degrades gracefully under distribution drift. Only samples whose anomaly score crosses a calibrated threshold are forwarded to the LLM-driven agents. Everything else is summarized at the metric level and dropped.

The practical effect is that the LLM-driven pipeline does the work that human detection engineers were previously doing (i.e., investigating novel patterns) and is not asked to look at routine traffic. Per-event latency on the LLM path is bounded by the slowest agent in the fan-out (in our deployment this boundary was low single-digit seconds end-to-end including reviewer policy evaluation), and the LLM path itself is exercised on a small fraction of events.

Two design notes are worth flagging. The Isolation Forest is retrained weekly and feature drift between retrainings is tracked as a first-class metric; a stale anomaly model would silently widen the LLM's workload. The threshold is itself a policy parameter consulted by the reviewer, so under operational stress it can be tightened to reduce LLM load without redeploying any agent.

What the Coordination Layer Looks Like

To make the pattern concrete, the following code snippet demonstrates the shape of an A2A task message between the triage agent and the detection-engineering agent. The specific schema is implementation-internal, but the envelope is representative of the structure A2A imposes:

{
  "task_id": "tsk_2026-03-24_8c1b9f",
  "from_agent": "triage.v3",
  "to_agent": "detection_engineering.v2",
  "intent": "synthesize_detection",
  "trace_id": "01HSMJ8...",
  "context_refs": [
    "mcp://asset-inventory/upf/upf-fr-paris-04",
    "mcp://detection-index/recent?window=14d"
  ],
  "payload": {
    "observation": { "...telemetry fingerprint..." },
    "novelty_score": 0.92,
    "deadline_ms": 90000
  },
  "constraints": {
    "rule_language": "sigma",
    "must_include_test_corpus": true,
    "max_false_positive_rate": 0.005
  }
}

Two things stand out. First, the agent-to-agent envelope carries a trace_id that propagates with the task. Every downstream span lives under the same distributed trace: the detection-engineering agent's call into MCP, the reviewer agent's policy evaluation, and the eventual deployment. That is what makes the system debuggable.

Second, the context_refs field carries MCP URIs rather than embedded context. The detection-engineering agent will dereference the URIs via MCP at evaluation time. This dereferencing keeps payloads small, lets the context agent enforce access control at the MCP boundary, and causes a single asset-inventory change to be immediately visible to every agent.

The shape of an MCP call into the asset inventory looks like this example:

GET mcp://asset-inventory/upf/upf-fr-paris-04
  Headers: { agent-identity: spiffe://company.com/sa/detection_engineering }
  Returns: { hostname, customer_segments, NF_role, last_seen, ...}

The agent’s identity is a workload identity attached at the mesh layer; the MCP server enforces authorization on the inventory based on that identity. Identity-as-traffic-policy is the right place for it.

A Representative Request Flow

Suppose the triage agent receives a previously unseen control-plane signalling anomaly on a User Plane Function (UPF) in the 5G core:

  • Triage classifies the anomaly, queries the context agent via MCP for the UPF’s metadata, customer impact, and recent history, and determines that the pattern is novel.
  • Triage dispatches an A2A task to the detection-engineering agent, such as "Synthesize a detection rule that would have caught this pattern earlier, with a small test corpus".
  • In parallel, triage dispatches an A2A task to the response agent, such as "Propose a containment action assuming this signaling pattern is malicious".
  • Both proposals are submitted to the reviewer agent via A2A.
  • The reviewer evaluates each proposal against the policy bundle (OPA-style rules). If both pass, the rule is deployed and the response action is executed. If either fails, the case escalates to a human SOC analyst with the agents’ full reasoning chain attached.

Across hundreds of such flows per day, this approach produces the rule-creation compression and the autonomous coverage growth we measure at the operator level.

Measured Outcomes

Against the baseline architecture, using the same incident classes during internal evaluation, we measured:

  • An approximate forty percent reduction in MTTD and an approximate forty percent reduction in MTTR.
  • More than eighty detection rules generated autonomously on the 5G core, validated through the reviewer agent and human-spot-audited.
  • Approximately twelve times the compression of human time to produce a new detection rule (three hours being reduced to roughly fifteen minutes).
  • Concurrent monitoring of fifteen to twenty 5G network functions.

The figures above need two pieces of context, drawn from the platform's internal benchmark and the operator's incident-response metrics, rather than from a third-party study. They are baselined against the previous architecture at the same operator; your baseline will look different.

Trade-Offs and Limits of Applicability

The pattern fits well when your SOC is event-rich and the rule base is large enough that maintenance is a structural bottleneck, when the cost of a missed detection is high (e.g., critical infrastructure, financial services, and telco core) and when you have the engineering maturity to treat the reviewer's safety policy as a first-class artifact.

It is the wrong pattern if rule volumes are small enough that human detection engineering is not your bottleneck, if regulation mandates fully deterministic, statically-auditable detection logic, or if the operator lacks the engineering function to own the reviewer's safety policy. That last case matters most: Without that ownership, the platform is unsafe regardless of how well the rest is designed.

A few caveats are worth stating plainly. The architecture shifts detection engineers' work from rule authorship to reviewer-policy curation and agent-output audit, but it does not eliminate that work. A2A and MCP are still evolving, so any reviewer safety constraint that has not been red-teamed should be assumed insufficient.

What I Would Do Differently

With hindsight, two things would have gone differently. I underestimated the work involved in writing useful OPA policies; the code is small, but designing the right invariants, especially the right blast-radius constraints, required several iterations with the SOC team for which I had not budgeted. I also built the reviewer as a single agent. Having learned from the experience, I would now split the reviewer into a pre-execution reviewer (i.e., does this action satisfy policy?) and a post-execution auditor (i.e., did this action have the expected effect?), with the auditor's findings feeding back into reviewer policy tuning.

A few lessons emerged during the implementation and evaluation of this architecture.

Build the Reviewer First 

The safety floor is set by the reviewer. Investing in its constraints before scaling the rest of the agent layer would have saved retroactive constraint patches.

Add the Anomaly as a Pre-Filter From Day One 

We initially fanned events out to the LLM-driven agents too early and discovered the cost and latency problem only under production load. Placing an Isolation Forest in front of the LLM tier from the start would have saved a quarter of operational firefighting; the same is true of treating the anomaly threshold as a reviewer-consulted policy parameter rather than a configuration constant.

Resist Clever Prompts 

Terse, single-page system prompts beat elaborate personalities every time in production. Cleverness compounds as technical debt and obscures the change-management story.

Publish the Schemas Earlier 

A2A and MCP are open, but the SOC-domain agent schemas built on top of them have stayed internal. There is industry value in publishing reference schemas for SOC-domain agents and in opening up the policy language used by the reviewer. The field will converge on shared schemas in 2026-2027; getting there sooner is better.

Closing

Multi-agent AI for security operations, coordinated through A2A and integrated through MCP, is no longer a future choice for us; it is a current production pattern with measured outcomes. That pattern does not make it a universal answer; the trade-offs are real. But for cloud-native SOCs at the scale where rule maintenance is the structural bottleneck, it is, in my experience, the most durable architectural bet available today.

Two questions I keep hearing since presenting this architecture at KubeCon are how do you keep it reactive and where does the human sit. These questions have the same underlying answer: Be disciplined about where you put the LLM, putting cheaper more predictable mechanisms in front of expensive ones. Open protocols rather than bespoke buses, prioritizing safety in policy-as-code, rather than in the system prompt. Maintain a human-in-the-loop path that is a normal output of the system, rather than an exception bolted on the side.

The interesting work for the next eighteen months will not be in scaling models. It will be in hardening reviewer agents, standardizing SOC-domain agent schemas, and writing the safety policies that turn a clever architecture into one that is operationally trustworthy.

About the Author

Rate this Article

Adoption
Style

BT