AIControl Docs

Integration

AIControl integrates as a gateway. Your agent's MCP client points at /mcp/{server_id}/... instead of the real downstream MCP server. AIControl evaluates Cedar policy on every tools/list and tools/call, audits the result, and forwards allowed calls to the real server.


The integration pattern

Admin registers the downstream server once
        ↓
POST /mcp-servers  →  {"id": "<server_id>", "status": "pending_review"}
        ↓
PATCH /mcp-servers/<server_id>  {"status": "active"}
        ↓
Agent's MCP client points at /mcp/<server_id>/
        ↓
Agent calls tools/list or tools/call
        ↓
AIControl evaluates Cedar policy, writes the audit event
        ↓
allow   → forwarded to the real downstream server, response returned
deny    → JSON-RPC error result returned, never forwarded
review  → a human has been notified (Slack, if configured); JSON-RPC error
          result returned immediately — your agent does not wait

Every call — regardless of decision — is written to the audit log before the response is returned.


Registering a downstream server

Registration is admin-only and metadata-only — no credential is stored on the row. Whatever Authorization header your agent sends on the gateway call is forwarded to the downstream server unchanged (pure passthrough).

bash
curl -X POST http://your-aicontrol-host:8001/mcp-servers \
  -H "Authorization: Bearer $AICONTROL_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "invoicing-mcp", "base_url": "https://invoicing.internal/mcp", "approved_tools": ["get_invoice", "create_invoice"]}'

Response 201:

json
{
  "id": "3f2a1c8b-...",
  "name": "invoicing-mcp",
  "base_url": "https://invoicing.internal/mcp",
  "status": "pending_review",
  "approved_tools": ["get_invoice", "create_invoice"],
  "created_at": "2026-09-09T10:00:00Z"
}

New registrations start in status: "pending_review" and are not reachable via the gateway until activated:

bash
curl -X PATCH http://your-aicontrol-host:8001/mcp-servers/<server_id> \
  -H "Authorization: Bearer $AICONTROL_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status": "active"}'

status is one of pending_review, active, or blocked. The gateway rejects any call to a server that isn't active with 403.

approved_tools on the server registration (separate from the per-agent approved_tools set via PATCH /agents/{agent_id}/approved-tools) scopes which of the downstream server's tools are visible/callable through this gateway at all — an empty list means every tool the downstream server exposes is reachable, subject to Cedar policy and the agent's own approved-tools list.


Environment setup

bash
AICONTROL_URL=http://your-aicontrol-host:8001   # required
AICONTROL_TOKEN=eyJhbGc...                       # required — agent-scoped JWT

Gateway calls require an agent-scoped token — a token issued with agent_id set (via scripts/onboard_agent.py or POST /tokens with agent_id). An admin token, or an agent-role token issued without an agent_id, is rejected with 403 — the gateway derives caller identity entirely from the token, so it must be attributable to exactly one registered agent.


Pointing your MCP client at the gateway

Configure your agent's MCP client with:

  • URL: http://your-aicontrol-host:8001/mcp/<server_id>/
  • Auth header: Authorization: Bearer <agent-scoped-token>

From there, standard MCP protocol calls apply.


The tools/list request

POST /mcp/{server_id}/tools/list
Authorization: Bearer <agent-scoped-token>
Content-Type: application/json
json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}

Response: the downstream server's own tools/list response, filtered to the server registration's approved_tools if that list is non-empty.

If the downstream server is unreachable, AIControl returns a JSON-RPC error rather than forwarding a timeout or connection error upstream to your agent:

json
{"jsonrpc": "2.0", "id": 1, "error": {"code": -32000, "message": "Downstream MCP server unreachable"}}

The call_tool request

POST /mcp/{server_id}/call_tool
Authorization: Bearer <agent-scoped-token>
Content-Type: application/json
json
{
  "jsonrpc": "2.0",
  "id": 1,
  "params": {
    "name": "query_credit_bureau",
    "arguments": {
      "applicant_id": "A-10042",
      "report_type": "full"
    },
    "session_id": "b3e1f9a2-...",
    "sequence_number": 3,
    "workflow": "loan_application_review",
    "input_tokens": 812,
    "output_tokens": 143,
    "cost_usd": 0.0091
  }
}
Field (under params)TypeRequiredNotes
namestringyesThe tool being called — matched against policies
argumentsobjectyesFull tool arguments; stored in the audit record
session_idUUIDyesGroups all tool calls within one agent run. Missing or invalid returns a -32602 JSON-RPC error
sequence_numberintegeryesCall order within the session. Missing or invalid returns a -32602 JSON-RPC error
workflowstringnoBusiness-process workflow name. Defaults to "unassigned" if omitted
input_tokens / output_tokens / cost_usdnumbernoFeed token_budget policy conditions — omit them and any such policy never fires for this call, since there's nothing to sum

Generate session_id once per agent run, not per tool call — reuse it across every call in that run so calls group correctly in the audit log and so session-scoped rate-limit/budget policies accumulate correctly.


The call_tool response

Allowed, forwarded successfully — the downstream server's own tools/call response is returned unchanged:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {"content": [{"type": "text", "text": "..."}]}
}

Denied by an agent-level approved-tools gate, a Cedar policy, or a response scan — a JSON-RPC result with isError: true, not an HTTP error:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {"content": [{"type": "text", "text": "Denied by policy: policy_matched:block_dangerous_tools"}], "isError": true}
}

Routed to human review — same isError: true shape, with a message naming the pending review; your agent does not receive a review_id field to poll on today — check the dashboard's Reviews page for pending items instead:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {"content": [{"type": "text", "text": "Pending human review: policy_matched:require_review_for_external_calls"}], "isError": true}
}

Malformed request (session_id or sequence_number missing/invalid) — a JSON-RPC protocol-level error, not a result:

json
{"jsonrpc": "2.0", "id": 1, "error": {"code": -32602, "message": "Invalid params: session_id is required"}}

Downstream server unreachable — same fail-closed error as tools/list:

json
{"jsonrpc": "2.0", "id": 1, "error": {"code": -32000, "message": "Downstream MCP server unreachable"}}

Response scanning

After a call is forwarded and the downstream server responds, AIControl scans the response before returning it to your agent (app/services/response_scanner.py — the same deterministic, pattern-based scanner used elsewhere in the product, not an LLM). A flagged response is blocked with isError: true even though the downstream call itself already happened and was already audited as allowed at the policy-evaluation step — the block is logged as a second audit event with decision_reason: response_scan_flagged:<category>.


Handling responses in your agent

Check result.isError on every call_tool response. true means the tool did not execute as your agent expects — treat it the same way you'd treat a denied tool call from any policy engine: don't retry blindly, and surface the text content (which names the policy or reason) to whatever is orchestrating the agent.


Checklist: integration complete

✓  AIControl deployed and verify.sh passes
✓  Downstream server registered (POST /mcp-servers) and status set to "active"
✓  Agent-scoped token issued (scripts/onboard_agent.py or POST /tokens with agent_id)
✓  MCP client pointed at http://your-aicontrol-host:8001/mcp/<server_id>/
✓  session_id generated once per agent run, reused across tool calls
✓  sequence_number increments with each tool call in the session
✓  result.isError checked on every call_tool response
✓  First call verified — audit event visible in dashboard

Framework and platform guides

For MCP-client configuration notes per framework (LangChain, CrewAI, LangGraph, and others) and for the four named agent-platform insertion points (Amazon Bedrock, Azure AI Foundry, Vertex AI, Microsoft Copilot Studio), see Platform & Framework Guide and Platform Discovery.