Skip to main content

AI agent change control for your API gateway: governing Management MCP writes

AI agent change control at the API gateway: how to scope Management MCP roles, stage writes as drafts, audit every change, and keep humans in the loop.

  • ai-agents
  • mcp
  • change-control
  • audit
  • rbac
Zerq team

Most AI agent governance discussions are about agents calling your APIs. The harder question shows up a few months later, when the platform team connects an assistant to the gateway's own control plane. Now the agent can create a proxy, rewrite a workflow, loosen a rate limit policy or rotate a partner's credentials. AI agent change control is the discipline of deciding which of those changes an agent may make, how they are staged, who sees them happen, and what evidence is left behind for the auditor. At the API gateway layer, this is not hypothetical: one bad edit is a production incident for every partner behind that route.

We see the same pattern in regulated teams. The first week, the assistant is used to answer questions: list the collections, summarise last night's errors, find which client owns a profile. By the second month someone asks it to "add a retry branch to the payments workflow", and it does. Nobody decided that the assistant should have write access to a production gateway. It inherited it from whichever token it was handed.

This post walks through how to put an AI agent behind the same change control you already apply to human operators, using Zerq Management MCP: which roles to give it, how drafts and workflow enablement act as gates, what the live change stream shows other operators, and what the audit trail actually records.

Why existing approaches to AI agent change control fail

The common workaround is a service account. A platform engineer creates an admin API key for the gateway's management API, puts it in the MCP server config for Claude, Cursor or an internal agent, and moves on. Kong's Admin API, Apigee's management API, and Azure APIM's ARM endpoints all invite this pattern because the fastest working integration is a long-lived credential with broad scope. The result is a change history where every edit made by the assistant, and every edit made by anyone else who copied that key, appears as one shared identity. Separation of duties is gone, and the change log can no longer answer "who did this".

The second workaround is to route agent changes through Git: the agent opens a pull request against declarative config, a human approves, a pipeline applies it. This is a sound pattern for some teams, and Zerq supports it through CI/CD automation. It does not cover the interactive case, where an operator is in the console with an assistant open beside them, and it does not stop an agent that was given a direct management credential from going around the pipeline entirely.

The third failure is visibility. Even when the change is attributed correctly, other operators usually find out after the fact. Two people editing the same workflow, one of them an assistant, is a classic lost-update problem: the human saves a stale canvas over the agent's change, or the other way round, and the audit log faithfully records both writes without anyone noticing the conflict.

How Zerq applies change control to AI agents

The design decision that makes the rest possible is simple: Management MCP has no privileged path into the platform. When an MCP client calls a tool such as update_proxy_workflow, the Management MCP handler forwards it to the corresponding Management API endpoint over HTTP, carrying the caller's own Authorization: Bearer header. The tool runner in internal/mcp/management/tools.go does exactly this for all 57 tools. Zerq Copilot for Management uses the same tools and, per the Copilot documentation, acts as the signed-in user.

That means every control below applies to the agent because it applies to the API, not because someone remembered to wire it into the MCP layer.

Step 1: map agent identities to the right RBAC role

Management access is OIDC-only. Zerq validates the token against your IdP and reads roles from the claim path you configure, then maps IdP role names into four internal permission sets. The mapping lives in environment variables on the management API:

# Management API OIDC trust
OIDC_ENABLED=true
OIDC_ISSUER_URL=https://idp.example.com/realms/api-platform   # your IdP issuer
OIDC_AUDIENCE=api-gateway-management                          # audience the token must carry
OIDC_ROLE_CLAIM_PATH=realm_access.roles                       # where roles live in the token

# IdP role names allowed into each permission set (comma-separated)
OIDC_VIEWER_ROLES=viewer,editor,admin,ai-readonly    # read routes, tools/list, SSE stream
OIDC_MODIFIER_ROLES=editor,admin,ai-change-bot       # create, update, toggle, rotate, delete
OIDC_AUDITOR_ROLES=auditor,admin                     # /api/v1/audit/logs
OIDC_ADMIN_ROLES=admin                               # admin-only routes such as deleting request logs

AUDIT_ENABLED=true                                   # turn on the management audit middleware

Two details from the route table matter for agent design. First, the modifier permission set covers deletes as well as edits: DELETE /api/v1/collections/:id, DELETE /api/v1/proxies/:id and profile credential rotation all require a modifier role. There is no "edit but not delete" tier, so the safe default for an assistant is a role that sits only in OIDC_VIEWER_ROLES. Second, audit log reads require an auditor role, so an assistant used to investigate changes needs that role explicitly and should not also hold modifier.

In practice we recommend three IdP identities: a read-only assistant identity (ai-readonly above) for inventory and troubleshooting, a separate write identity (ai-change-bot) used only inside a change window, and a human auditor group. A viewer-mapped identity that tries update_policy gets a 403 from the Management API, and the MCP client sees that error as the tool result. The security page covers the wider RBAC model.

Step 2: stage agent writes as drafts

Zerq's collections and proxies have a draft or published status. A draft proxy is not routable even under a published collection, and a draft collection hides all its proxies from the gateway and the developer portal. Duplicating a collection always creates the copies as drafts. That gives you a natural staging rule for agents: they build in draft, a human publishes.

Workflows add a second gate. Saving a workflow definition and enabling it are separate fields on the same endpoint, PUT /api/v1/proxies/:id/workflow. The backend validates the definition when workflow_enabled changes from false to true, and production triggers (cron, Kafka, IMAP) only run when the workflow is enabled and the proxy is published. An agent can save an in-progress definition while the workflow is disabled without touching live traffic.

A disciplined agent session looks like this as MCP tool calls:

{ "jsonrpc": "2.0", "id": "v1", "method": "tools/call",
  "params": { "name": "validate_proxy_workflow",
    "arguments": { "proxy_id": "665f1c2ab9e4", "workflow_definition": { "nodes": [], "edges": [] } } } }

{ "jsonrpc": "2.0", "id": "s1", "method": "tools/call",
  "params": { "name": "update_proxy_workflow",
    "arguments": { "proxy_id": "665f1c2ab9e4", "workflow_definition": { "nodes": [], "edges": [] } } } }

The first call runs POST /api/v1/proxies/:id/workflow/validate, which checks the definition without saving it. Validation sits behind the modifier role, like saving, so this sequence runs under the write identity. The second saves the definition and leaves workflow_enabled unchanged. The node and edge arrays are elided here; the real shape comes from workflow_list_nodes. Enabling the workflow ("workflow_enabled": true) and publishing (toggle_collection_status with "active": true) stay with the human. Write that split into the agent's system prompt, but do not rely on the prompt alone. The write identity can technically call both endpoints, so the real controls are that it only exists inside a change window, and that any enable or publish it does make lands in the audit log under its own name rather than a human's.

Step 3: let humans see agent changes as they happen

Every successful management write emits a small event on GET /api/v1/events/stream, a Server-Sent Events stream that any viewer-mapped session can open with its Bearer token. The payload carries identifiers and change hints, never resource bodies or secrets. An agent saving that workflow produces:

{
  "schema_version": 1,
  "resource_kind": "proxy_workflow",
  "actor_sub": "3f2c9a1e-7b4d-4e0a-9c61-58d2e7a4b0f3",
  "occurred_at_unix": 1792058400,
  "proxy_id": "665f1c2ab9e4",
  "definition_changed": true
}

actor_sub is the OIDC subject of whoever persisted the change, so a listener can tell an assistant's write from a colleague's. definition_changed and enabled_changed distinguish an edit from someone switching the workflow on. Validate calls and workflow test runs do not emit events, so the stream reflects persisted state only.

The management UI consumes this stream directly. If an operator has the same workflow open in the Workflow Builder with no unsaved edits, the canvas refetches silently. If they have unsaved edits, they get a banner reading "This workflow was saved in another session or tab. Reload to sync, or keep editing your local draft." Policy, client, profile and credential forms show the same kind of Reload banner. That closes the lost-update gap: a human cannot unknowingly overwrite an assistant's change, or the reverse. With Redis configured, events publish on the zerq:management_events channel so every management API replica fans them out to its own subscribers, which matters once you run more than one pod (see architecture).

Step 4: make the audit trail answer "which changes did the agent make"

With AUDIT_ENABLED=true, the audit middleware writes one record per matched management write to MongoDB, in your environment. Because the MCP tool runner calls the Management API over HTTP, an agent's change produces the same record a console change does. Here is a policy update made through Management MCP:

{
  "id": "6710a4c2f1e9b03d5a7c2e18",
  "timestamp": "2026-10-12T09:14:03Z",
  "actor_id": "[email protected]",
  "actor_type": "ai-change-bot",
  "resource_type": "policy",
  "action": "update",
  "ip_address": "127.0.0.1",
  "user_agent": "Go-http-client/1.1",
  "request_id": "b7d1c0e4-2a9f-4f63-8d0e-5c1a7e9f3b22",
  "metadata": {
    "url": "/api/v1/policies/66f0b2e1c4a8",
    "request_body": "{\"name\":\"partner-standard\",\"rate_limit_interval\":\"1m\",\"rate_limit_requests\":200}",
    "response_body": "{\"id\":\"66f0b2e1c4a8\",\"name\":\"partner-standard\"}",
    "status_code": 200
  }
}

For a compliance reviewer, the fields read as follows. actor_id is the identity's email claim, so it names the agent's identity rather than a shared key. actor_type is the list of roles the token carried, which shows whether the change came from a modifier-mapped identity. metadata.request_body is exactly what was submitted, and status_code shows whether it succeeded or was refused. The MCP tool runner does not set its own User-Agent, so changes routed through Management MCP carry the Go HTTP client default (Go-http-client/1.1) and the ip_address of the management API's internal hop, while console changes carry a browser user agent and the operator's address. That gives auditors a second signal alongside the dedicated identity.

One gap to close on day one: the shipped config/audit_rules.yaml covers collections, proxies, policies, clients, profiles, credentials and log deletion, but not the workflow save route. Workflow saves still emit SSE events with actor_sub, but if you want them in the audit collection, add a rule. The proxy route group already runs the audit middleware, so the rule is all that is needed:

audit_rules:
  # Record workflow definition saves and enable/disable toggles
  - path_pattern: "/api/v1/proxies/:id/workflow"   # :id matches any proxy id
    method: "PUT"
    resource_type: "proxy_workflow"                # value written to resource_type
    action: "update"                               # value written to action

Auditors then pull agent activity from the Audit Logs page, or programmatically for the SIEM, with GET /api/v1/audit/[email protected]&start_date=2026-10-01T00:00:00Z. An auditor-mapped assistant can run the same query through the list_audit_logs tool. More on log fields and retention is on the observability page.

A change control checklist for AI agents on the gateway

Use these questions to review any assistant you connect to the control plane:

  1. Does the agent authenticate with its own IdP identity, not a copied human token or a shared key?
  2. Is that identity's role mapped only into OIDC_VIEWER_ROLES unless it is the dedicated write identity?
  3. Is the write identity time-boxed to a change window and absent from OIDC_ADMIN_ROLES?
  4. Are agent-created collections and proxies left in draft, with publishing reserved for humans?
  5. Does the agent call validate_proxy_workflow before update_proxy_workflow, and never set workflow_enabled itself?
  6. Is AUDIT_ENABLED=true, and does audit_rules.yaml include the workflow route?
  7. Is Redis configured, so SSE change events reach operators on every replica?
  8. Can your auditor filter the audit log by the agent's actor_id and export the result to the SIEM?

What this looks like in practice

Illustrative scenario, not a specific customer deployment.

Consider a mid-sized payments provider running Zerq across three replicas on Kubernetes. The platform team had connected Claude to Management MCP using a senior engineer's token, and the assistant had become the fastest way to build workflows. A quarterly control review found eleven production changes in the audit log attributed to that engineer, four of them made while they were on leave. Nothing had gone wrong, but nothing could be proven either.

They created two identities in their IdP: ai-readonly, mapped into viewer roles and used by default in every engineer's MCP client config, and ai-change-bot, mapped into modifier roles and granted to a session only through their existing change ticket process. They added the workflow rule to audit_rules.yaml, confirmed Redis was set for the event channel, and changed their team guidance: the assistant drafts and validates, a named human enables and publishes. The compliance team got an auditor role and a saved filter on actor_id.

The next review took an afternoon instead of a week. Every agent write had its own identity, request body and status code. Two attempted policy edits from the read-only identity showed up as 403 responses in the agent's session, which was the evidence the CISO wanted that the boundary held. Engineers kept using the assistant as before, but publication of anything the assistant built now had a human name on it.

Closing summary

Zerq puts AI agents through the same control plane as your operators rather than beside it. Management MCP forwards every tool call to the Management API with the caller's own token, so RBAC applies unchanged. Draft status and the separate workflow enable step give agents room to build without touching live traffic. The SSE change stream shows humans each agent write as it lands, with the actor's subject attached. The audit log records every matched change with identity, roles, request body and outcome, in your own MongoDB. You get AI agent change control from configuration you already understand, not from a second governance product.


Zerq is an enterprise API gateway built for regulated industries — one platform for API management, AI agent access, compliance audit, and developer portal, running entirely in your own infrastructure. See how it works or request a demo to walk through your specific requirements.