Agentic Control Plane (ACP)
A governed MCP server that enforces OAuth 2.1 scope checking and policy-driven access control for AI agents, providing a full audit trail on every tool call. It includes tools for Cisco Webex Contact Center knowledge search and SD-WAN network operations.
README
Agentic Control Plane (ACP)
Rajmohan Mangattu | CCIE Collaboration #55207
LAB PROTOTYPE — built to demonstrate governed agentic AI architecture at enterprise scale, combining years of Cisco UC/CC/networking expertise with modern AI engineering.
What this is
The Agentic Control Plane (ACP) is a governed MCP (Model Context Protocol) server that sits between AI agents and domain knowledge — enforcing OAuth 2.1 scope checking, policy-driven access control, and a full audit trail on every tool call.
It is not a chatbot. It is the governance layer that enterprise AI deployments need before autonomous agents can be trusted in regulated industries.
The A2A boundary — what this demonstrates
Natural language question
↓
network_caller.py (MCP client)
— grounds LLM with real inventory
— Groq picks tool + parameters
— validates against real topology
↓ real MCP protocol over HTTP
ACP on port 8100 (MCP server)
— decodes JWT token
— checks control_hub.yaml policy
— runs domain tool
— writes audit line
↓
Prose answer + governed audit trail
Demo run:
Question : "What is the device in Mumbai branch?"
Groq picks: check_device_role(node=branch-cedge-01)
ACP says : ALLOWED — governance passed
Answer : Cisco ISR1100 IOS-XE SD-WAN cEdge, spoke role,
5 peers, dual-transport MPLS + internet
Audit : tool=check_device_role decision=ALLOWED written to audit.readable.log
Demo — the A2A boundary in action
A natural-language question about a Cisco SD-WAN network, answered end to end through the governed MCP boundary.
1. ACP server running
The governed MCP server starts and serves both /health and /mcp on port 8100.

2. The A2A flow — natural language to governed tool call
The caller grounds the LLM with real inventory, Groq picks find_path with the
correct parameters, the code validates them against the real topology, then calls
ACP over the real MCP protocol.

3. The governed answer
Groq composes a prose answer from the governed result — every fact traced to the topology, crossing the SD-WAN OMP tunnel.

4. Governance blocks an unauthorized caller
The same question with a viewers token. Governance blocks the flow at the first
tool call — no inventory returned, no answer, distinct audit reason.

Architecture
┌─────────────────────────────────────────────────────────┐
│ network_caller.py — A2A caller │
│ Groq tool router + validation guard + prose writer │
└──────────────────────────┬──────────────────────────────┘
│ MCP protocol (HTTP port 8100)
▼
┌─────────────────────────────────────────────────────────┐
│ ACP governed MCP server │
│ ┌──────────────────┬──────────────────────────────┐ │
│ │ Track C │ Track N │ │
│ │ search_wxcc_ │ describe_topology │ │
│ │ corpus │ find_path │ │
│ │ │ check_device_role │ │
│ └──────────────────┴──────────────────────────────┘ │
│ OAuth 2.1 scopes + control_hub.yaml + audit trail │
└─────────────────────────────────────────────────────────┘
Two domain modules
Track C — Contact Center Searches a corpus of 2,633 chunks of Cisco Webex Contact Center knowledge (BGE-M3/1024-dim embeddings, Qdrant Cloud). Returns Tier 1 sourced, grounded answers to specific deployment, compliance, and design questions — with provenance tracking so every answer traces back to its source document.
Track N — Network Three tools over a Cisco SD-WAN topology descriptor (9 nodes, 11 links):
describe_topology— nodes, links, sites, SD-WAN hub/spoke summaryfind_path— BFS shortest L3 hop path between any two nodescheck_device_role— role, platform, and peer connections for a named node
Governance on every call
Every tool call goes through two checks before the domain function runs:
- Group policy — is this tool Allowed or Blocked for the caller's group
in
control_hub.yaml? - Scope check — does the JWT token carry the required scope
(
knowledge:readordiagnostics:run)?
Both refusal types write distinct audit lines to audit.readable.log with
the reason. Allowed calls write an ALLOWED line. Nothing reaches the domain
tool without passing both checks.
Key design decisions
ACP has its own direct path to the data Rather than routing through the WxCC SLM's API, ACP keeps its own database client and embedder. This means the two systems are independent — if the SLM goes down, ACP still works. They share the data, not the code.
Governance is a parameter, not a dependency The governance function is passed into each tool as an argument rather than imported directly. This keeps the code clean and avoids circular dependencies — the tool doesn't need to know anything about the server that hosts it.
The LLM proposes, the code decides When the A2A caller asks Groq to pick a tool parameter (like a node name), it doesn't just trust the answer blindly. Every parameter is checked against the real data before any call goes to ACP. If the LLM guesses a node that doesn't exist, the caller rejects it and shows what's actually available.
How to run
Prerequisites
- Python 3.11 (ACP venv)
- Qdrant Cloud account — collection
wxcc_slm_corpus - Groq API key — https://console.groq.com/keys
- BGE-M3 cached at
D:\\hf_cache(or setHF_HOMEto your cache path)
Setup
git clone https://github.com/Rajmohan80/project-acp.git
cd project-acp
python -m venv .venv
.venv\\Scripts\\activate
pip install -e .
cp .env.example .env
# Fill in .env with your real values
Run the A2A demo (two terminals)
Terminal 1 — start ACP server:
python scripts\\run_mcp_server.py
Wait for: Uvicorn running on http://0.0.0.0:8100
Terminal 2 — run the A2A caller:
python scripts\\network_caller.py --question "What is the device in Mumbai branch?"
Try --group viewers to see governance block the flow.
Run the WxCC corpus tool demo
python scripts\\demo_wxcc.py --query "What are the WxCC data residency requirements for UAE?"
Run the Track N topology tools demo
python scripts\\demo_network.py
Repository structure
src/
core/
mcp/
server/app.py — governed MCP server, all tools registered
control_hub.yaml — allow/block policy per group per tool
oauth/issuer.py — JWT token minter (port 9000)
audit/writer.py — every decision → audit.readable.log
common/config.py — settings from .env, fails loud on missing vars
domains/
contact_center/
corpus_client.py — BGE-M3 + Qdrant client (Track C)
tool.py — search_wxcc_corpus governed tool
network/
topology_store.py — JSON topology loader, BFS path finder
tool.py — describe_topology, find_path, check_device_role
topologies/
sample_sdwan_branch.json — 9-node SD-WAN topology descriptor
scripts/
run_mcp_server.py — starts ACP as standing HTTP service
network_caller.py — A2A caller (grounded LLM + MCP client)
demo_wxcc.py — Track C validation
demo_network.py — Track N validation (6 runs)
docs/
naming-map.md — ACP ↔ Cisco concept mapping
BLOCK_5A_MCP_TRANSPORT.md — how the MCP HTTP transport was wired
BLOCK_5_A2A_BOUNDARY.md — A2A boundary design and validated output
A2A_FLOW_DIAGRAM.md — flow diagram + step-by-step explanation
Governance proof — what the audit log shows
After running the demo, audit.readable.log contains entries like:
{"actor": "demo.engineer", "tool": "check_device_role",
"outcome": "ALLOWED", "refusal_reason": "NONE", ...}
{"actor": "demo.viewer", "tool": "check_device_role",
"outcome": "REFUSED", "refusal_reason": "TOOL_BLOCKED_IN_CONTROL_HUB", ...}
Two callers, same tool, different outcomes — based purely on the signed JWT token's group claim. The governance layer cannot be bypassed.
Related projects
- wxcc-slm — the domain AI this project governs: https://github.com/Rajmohan80/wxcc-slm
Stack
| Component | Technology |
|---|---|
| MCP server | FastMCP 3.4.5 (streamable-http) |
| OAuth issuer | FastAPI + python-jose (JWT) |
| Policy enforcement | control_hub.yaml (YAML, no code change needed) |
| Audit trail | TinyDB → audit.readable.log |
| Embeddings | BGE-M3 (BAAI/bge-m3, 1024-dim, sentence-transformers) |
| Vector DB | Qdrant Cloud |
| LLM | Groq Llama-3.3-70B-versatile |
| Runtime | Python 3.11, uvicorn |
Rajmohan Mangattu | CCIE Collaboration #55207 Lab prototype — not production ready. Built to demonstrate governed agentic AI architecture for enterprise contact center and network domains.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。