Integrating LangGraph with MAREF — Protocol-Level Governance That Works Today
By MAREF Engineering
If you're building production agents in 2026, there's a good chance they're a LangGraph state graph. Nodes, edges, conditional routing — elegant, testable, and — until you add a governance layer — completely unsupervised. This guide shows the two ways to govern a LangGraph app with MAREF, and it's honest about which is ready today.
TL;DR: the protocol-level path (MCP + A2A) is live and tested; the native LangGraphAdapter documented in the quickstart is on the roadmap, with the AutoGen sidecar adapter already shipped.
The honest status, first
MAREF's quickstart documents a sidecar.adapters.langgraph.LangGraphAdapter with three methods — evaluate_node_safety, observe_transition, and inject_governance. We want to be direct with you: that adapter is specified but not yet merged. The AutoGen adapter (sidecar.adapters.autogen.AutoGenAdapter) is live; LangGraph's native adapter is being built to the same contract.
What that means for you: you should not block on the adapter. The protocol-level integration below uses only shipped, tested code paths and gives you the same governance guarantees today.
Path 1 — Govern tool calls inside a LangGraph node (MCP)
LangGraph nodes call tools. Those tools are where the blast radius lives. Wrap them with MCPBridge and every call from any node goes through the security gate — with the same event stream you can feed your audit log:
from langgraph.graph import StateGraph
from maref.integration.mcp_client import MCPClient, MCPServerConfig
from maref.integration.mcp_bridge import MCPBridge
client = MCPClient()
conn = client.register_server(MCPServerConfig(
command=["npx", "-y", "@your/tool-server"],
transport_type="stdio",
server_name="tool-server",
))
bridge = MCPBridge(client) # wraps calls in the security gate
def tool_node(state):
# every node that touches the world goes through governance
return bridge.invoke_tool(
conn,
tool_name=state["tool"],
args=state["args"],
)
graph = StateGraph(dict)
graph.add_node("tools", tool_node)
graph.add_edge("__start__", "tools")
A DENY verdict returns {"error": "Tool blocked by security gate", ...} — the external server is never called, and the node's __error__ edge or fallback logic can route around it. Your LangGraph topology stays exactly as designed; MAREF just sits at every tool boundary.
Path 2 — Govern whole tasks across agents (A2A)
For multi-agent LangGraph deployments — several graphs, maybe a supervisor — the A2ABridge makes MAREF itself an A2A-governed agent that creates, delegates, and halts tasks across the federation:
from maref_lite.state_machine import GovernanceStateMachine
from maref.governance.audit import AuditLogger
from maref.integration.a2a_bridge import A2ABridge
bridge = A2ABridge(
state_machine=GovernanceStateMachine(),
audit_logger=AuditLogger(log_path="maref-audit.jsonl"),
agent_name="langgraph-supervisor",
)
task_id = bridge.create_task("Summarize Q3 report") # governed lifecycle
# another agent can delegate into us:
bridge.delegate_task(task_id, "https://other-agent.local:8000")
# any authorized human can halt a task outright:
bridge.force_halt_task(task_id, reason="scope change")
Every create_task, delegation, and state change is HMAC-signed into the audit log and runs through the same governance state machine — OBSERVE → ANALYZE → EVALUATE → DECIDE → ACT → VERIFY → STABILIZE → REPORT, with HALT reachable by any authorized human or the circuit breaker.
The result: your LangGraph graphs keep their orchestration logic, while MAREF owns the "is this safe?" decision at every boundary — tool calls, inter-agent handoffs, and task lifecycle.
Which path should you pick?
- Single graph, several tools → Path 1 (MCP bridge on tool calls). Minimal change, immediate audit trail.
- Multiple graphs / supervisor pattern → Path 2 (A2A). You get task lifecycle governance, delegation, and a kill-switch across the whole fleet.
- Both → They compose. MAREF governs tool calls and task orchestration simultaneously — that's the 8-layer architecture working as designed.
🛡️ Sources: MAREF source — src/maref/integration/mcp_bridge.py (MCPBridge.invoke_tool), src/maref/integration/a2a_bridge.py (A2ABridge.create_task / delegate_task / force_halt_task), src/sidecar/adapters/autogen.py (shipped sidecar adapter). LangGraph adapter contract defined in docs/quickstart.md §3.3 (roadmap — AutoGen adapter shipped). Quickstart · Integrations.