Blueprint: Meta-Governance Agent
An agent that proposes safeguards, and a human who approves them
An agent connected to the Control Zero MCP server with a management key can read the org's policies and DLP configuration, validate a policy, and create it as a draft. It cannot make that draft govern anything on its own: an active attachment made with a management key waits for a different principal to approve it. That is the design -- the agent does the drafting, a person keeps the decision.
Architecture
1. Govern the governor
The governor agent's own MCP calls can be governed like any other tool call (see Governing MCP tool calls). Enforcement of these rules depends on the governor running in a client with Control Zero hook coverage or behind the SDK; the second-principal gate below holds either way, because the API enforces it. This policy lets the agent draft and propose, and denies it approving anything:
{
"name": "meta-governance-policy",
"rules": [
{
"id": "allow-governor-drafting",
"effect": "allow",
"principals": ["agent:governor-bot"],
"actions": ["mcp.tool:call"],
"resources": [
"mcp://controlzero/policies_list",
"mcp://controlzero/policy_validate",
"mcp://controlzero/policy_create",
"mcp://controlzero/attachment_create"
]
},
{
"id": "deny-governor-approvals",
"effect": "deny",
"principals": ["agent:governor-bot"],
"actions": ["mcp.tool:call"],
"resources": ["mcp://controlzero/approval_approve"]
}
]
}
2. Implementation
Use @controlzero/mcp-server 2.0.1 or later with a management key
(cz_mgmt_*) minted without unattended_publish.
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
async function proposeLockdown(projectId: string) {
const transport = new StdioClientTransport({
command: 'npx',
args: ['-p', '@controlzero/mcp-server', 'controlzero-mcp'],
env: {
PATH: process.env.PATH ?? '',
CONTROLZERO_MGMT_KEY: process.env.CONTROLZERO_MGMT_KEY ?? '',
},
});
const client = new Client({ name: 'governor-bot', version: '1.0.0' });
await client.connect(transport);
const rules = {
rules: [
{
id: 'task-specific-deny',
effect: 'deny',
principals: ['*'],
actions: ['sys:execute'],
resources: ['*'],
},
],
};
// 1. Validate first: nothing is saved.
console.log(await client.callTool({ name: 'policy_validate', arguments: { rules } }));
// 2. Create the policy as a draft. This changes no enforcement.
const created = await client.callTool({
name: 'policy_create',
arguments: { name: 'temporary-task-lockdown', rules },
});
console.log(created);
// 3. A person publishes the draft in the dashboard: an active attachment
// needs a published version, and the API refuses one without it.
//
// 4. Then propose attaching it. Without confirm this is a preview; with
// confirm a management key gets a pending-approval message for a human.
const policyId = '<the policy id from the policy_create result>';
const proposal = await client.callTool({
name: 'attachment_create',
arguments: { project_id: projectId, policy_id: policyId, state: 'active', confirm: true },
});
console.log(proposal);
await client.close();
}
In a real agent, steps 1-2 and step 4 are separate runs: the agent drafts, a person publishes the draft and later approves the attachment.
3. Validation Checklist
- MCP connection: the agent lists the server's tools.
- Draft only: a policy created by the agent appears in the dashboard as a draft and governs nothing.
- Second principal:
attachment_createwithconfirm: truefrom the agent's management key returns a pending-approval message, and the attachment takes effect only after a different principal approves it. - Governor is governed: the agent's own
approval_approvecall is denied by its policy.