Platform

Contro1 Action Gateway

Choose the applications your organization approves, decide who may do what, and connect one MCP. Every person and agent gets exactly their access, and every action is recorded on their name.

Updated Sep 28, 2026

Pick the apps, decide the access, connect the MCP. The agent gets exactly its capsule, and nothing to integrate.

What the Action Gateway is

The Action Gateway is how people and agents act in your business applications through Contro1. Contro1 holds the connected accounts, checks every call against what the caller was granted, asks a person when the grant says so, makes the call itself and records what happened.

Setting it up is five steps: choose the applications, decide who may do what, have each person and agent connect with its own identity, add the Contro1 MCP, and use it.

Why teams use it

No integrations to build

Your developers do not write OAuth flows, store refresh tokens or wrap vendor APIs as tools. The applications are already in Contro1, with every action defined, described and rated for risk.

The agent never holds a credential

Contro1 keeps the provider tokens sealed in its vault, refreshes them, and makes the call itself. A prompt-injected agent cannot leak a key it never had.

One access model for every application

Grant by department, person or agent, action by action. Approvals, limits and revocation work the same way in Gmail as in Stripe.

Every action on a name

Each call is recorded against the person or agent that made it, as Contro1 observed it, not as the agent reported it afterwards.

Setup at a glance

Choose the applications your organization approves

Open Apps and add the business applications your organization has approved for AI. There is nothing to build: each application arrives with its actions already defined, described and rated for risk.

Decide who may do what

Open Access, pick a department, a person or an agent, and give it the actions it needs from each application. What you see there is its capsule: everything that identity can reach, in one place.

Each person and agent connects with its own identity

Access takes effect only when the person or agent it belongs to connects with its own identity. That is what puts every action on a name, instead of on a shared key nobody answers for.

Add the Contro1 MCP to the client or agent

Add one MCP server. The address is the same for everyone; what differs is who connects, and so what they get.

What the agent gets through the MCP

The agent calls list_actions and gets back exactly its capsule: the actions it may use now, and the ones it could ask for. An action it was not given appears in neither list, so it cannot try what it was never allowed.

Step 1: Choose the applications your organization approves

Who: An administrator. Where: Apps (https://contro1.com/apps).

Open Apps and add the business applications your organization has approved for AI. There is nothing to build: each application arrives with its actions already defined, described and rated for risk.

  • Gmail and Google Calendar are built in. Stripe, Notion, Jira, Confluence, Linear, Figma, Supabase, Vercel, PayPal, Webflow and Zapier are verified vendor connections you add in one step.
  • For an internal or self-hosted API, import its OpenAPI 3 document, review and publish only the operations you want, and run them through a private connector that only connects out over HTTPS. No public endpoint, no inbound rule and no MCP server to build. Early access.
  • For anything else, import the vendor's MCP server, or choose "Ask Contro1 to add it" and the Contro1 team adds it, usually within 24-48 hours.
  • Choose whose account the application runs in. Personal: each employee connects their own account. Shared: one team account, such as finance@, read-only until someone explicitly confirms write or send. Organization: a delegated domain, read-only in this release.
  • Tools imported from an MCP server arrive as drafts. None of them can run until a person reads and publishes it.

Connect AI agents to internal and on-prem apps · OpenAPI to MCP for internal APIs

Step 2: Decide who may do what

Who: An administrator, or the manager of the department. Where: Access (https://contro1.com/access).

Open Access, pick a department, a person or an agent, and give it the actions it needs from each application. What you see there is its capsule: everything that identity can reach, in one place.

  • Grant actions, not whole applications. An agent that reads charges does not need to refund them.
  • For each action choose Runs on its own, Needs approval or Not allowed. When two rules meet, the stricter one wins, and Not allowed always wins.
  • For actions that need approval, choose who approves them. The approver decides from the web app, email, Slack or Teams, and the action runs the moment they approve.
  • Grant to a department once. Everyone in it, and in every team beneath it, inherits the grant: a person in DevOps, which sits under Engineering, gets what Engineering was given. Moving someone to another department moves their access with them.
  • An agent has its own capsule. Acting as itself, it can do only what it was granted directly. Acting for a person, it works inside that person's access, and only for the actions that person delegated to it.
  • A sub-agent that runs as part of an agent, such as a worker inside a supervisor, uses that agent's grants and never more. It appears under the agent on the org map, marked ! until an administrator approves it, and can be narrowed or blocked on its own.
  • An organization-wide grant is read-only and needs two administrators. It does nothing until a second administrator, who did not create it, confirms it.

Step 3: Each person and agent connects with its own identity

Who: Every person, and the owner of every agent. Where: Connect an agent (https://contro1.com/connect-app).

Access takes effect only when the person or agent it belongs to connects with its own identity. That is what puts every action on a name, instead of on a shared key nobody answers for.

  • People connect their own account, from Apps, for any application that runs in personal accounts. Until they do, an action returns user_auth_required. Contro1 never falls back to a shared or organization account in their place.
  • An agent connects to Contro1 with its own identity, and its owner approves it. On a computer: contro1 connect claude-code (or openclaw, nanoclaw). With no browser: the agent shows a code and the owner enters it at contro1.com/connect-app on any device.
  • Every agent has an accountable owner. Owning an agent does not hand it the owner's access; the owner has to delegate it, and that delegation is recorded.

Step 4: Add the Contro1 MCP to the client or agent

Who: Whoever runs the AI client or the agent.

Add one MCP server. The address is the same for everyone; what differs is who connects, and so what they get.

  • Apps with an MCP connector, such as Claude, ChatGPT, Cursor, Grok and Codex: add a custom connector with the address below, sign in, and review what it asks for. To let it run actions, tick "Run Actions as you". It is off by default, and without it the connection can read and preview only.
  • Claude Code: add the address as a remote server, or go through the local Contro1 service so the agent never holds a credential.
  • An agent you build that runs on its own, on a server, in a container or a CI job: it does not sign in. Register it with contro1 agents register, give it its own Agent Credential (Settings, Agent keys) and call the HTTP API with it.
  • A tool that acts as you and has no browser: run contro1 mcp login --execute and approve the code it shows at contro1.com/connect-app. Never sign in under the name of an agent you are building: that makes a second identity that acts as you.
terminal
# The address, for any client that adds a remote MCP server
https://api.contro1.com/api/centcom/mcp

# Claude Code, as a remote server
claude mcp add --transport http contro1 https://api.contro1.com/api/centcom/mcp

# Claude Code, through the local Contro1 service (the agent never holds a credential)
contro1 connect claude-code --yes
claude mcp add --scope user contro1 -- contro1 mcp serve

# A tool that acts as you, with no browser: shows a code to approve at contro1.com/connect-app
# (not for an agent you build: that one uses its own Agent Credential)
contro1 mcp login --execute

Step 5: What the agent gets through the MCP

Who: The agent.

The agent calls list_actions and gets back exactly its capsule: the actions it may use now, and the ones it could ask for. An action it was not given appears in neither list, so it cannot try what it was never allowed.

  • It runs an action with invoke_action. Contro1 checks it, holds it for approval when the grant says so, makes the call with the account it holds, and records what happened.
  • It reads the outcome with get_action_invocation. It polls, or waits in the call with wait_seconds; it never sends the same action again to find out what happened. When a webhook endpoint is set up, Contro1 also sends one when the action is decided or finishes, so an agent that stopped can continue.
  • When it needs something it does not have, it calls request_capability. The request goes to whoever owns the account the action would run through, and asking grants nothing until a person approves.

The Contro1 MCP tools

ToolWhat it does
whoamiWho this session acts for, and in which organization.
list_applicationsThe applications the organization offers, and which are ready.
list_actionsThe capsule: actions it may use now, and actions it could ask for.
get_action_contractOne action in full: its input, its side effects, and whether it needs approval.
preview_actionWhat an action would do, without doing it.
invoke_actionRun an action. Contro1 checks it, asks for approval if needed, makes the call and records it.
get_action_invocationThe state and result of an action it ran. wait_seconds waits for a change.
request_capabilityAsk for an action it does not have. A person decides.
request_applicationAsk an administrator to add an application.

What happens on every call

  1. 1 · Step

    Who is calling

    Read from the credential. Anything the request says about identity is ignored.

  2. 2 · Step

    Is there a grant

    A grant is the only thing that allows an action. No grant, no action.

  3. 3 · Step

    Which account

    A personal account must belong to the person the call is for. There is no fallback.

  4. 4 · Step

    Policy and approval

    If the grant says so, the action waits until the named people decide.

  5. 5 · Step

    Contro1 makes the call

    With the account it holds. The agent never touches the credential.

  6. 6 · Step

    The record

    The action, the app, the account, who asked, who approved, and the outcome.

Calling it from your own code

Agents that do not use MCP call the same gateway over HTTP, or through the Python and TypeScript SDKs. The rules are the same.

  • Send an Idempotency-Key on every action with side effects, and reuse it only to retry the same intent. Contro1 will not derive one from your payload: two identical reminders an hour apart are two sends.
  • Waiting is not retrying. The SDKs poll the invocation; they never submit it again. A timeout means it is still live: read it again.
  • While an action waits, the answer says what for, when to read it again (poll_after_seconds), and whether a webhook will follow. Read with wait_seconds (up to 30) to wait for a change in the call itself.
  • With a webhook endpoint set up for the agent (Settings, Webhooks), Contro1 sends action.invocation.updated when an action is decided or finishes. It carries the state, never the result; read the result with get_action_invocation.
  • Sending is at-most-once. When an outcome is genuinely unknown, the invocation ends in execution_indeterminate and stops. That is a task for a person, never an automatic retry.
  • awaiting_approval means a person decides. The final states are executed, execution_failed, execution_indeterminate, denied, expired and cancelled.
send.py
from centcom import CentcomClient, needs_human_resolution
import os, uuid

client = CentcomClient(api_key=os.environ["CONTRO1_AGENT_CREDENTIAL"])

result = client.actions.invoke(
    action_id="gmail.message.send",
    input={"to": "customer@example.com", "subject": "Your invoice", "body": "..."},
    authority_mode="agent_principal",
    account_mode="shared",
    idempotency_key=str(uuid.uuid4()),
)

settled = client.actions.wait_for_invocation(result["invocation"]["invocation_id"])
if needs_human_resolution(settled):
    escalate_to_a_person(settled)  # Do not retry.
elif settled["state"] == "executed":
    sent = client.actions.get_result(settled["invocation_id"])
send.ts
import { CentcomClient, ActionsApi, needsHumanResolution } from "@contro1/sdk";

const actions = new ActionsApi(new CentcomClient({ apiKey: process.env.CONTRO1_AGENT_CREDENTIAL! }));

const { invocation } = await actions.invoke({
  action_id: "gmail.message.send",
  input: { to: "customer@example.com", subject: "Your invoice", body: "..." },
  authority_mode: "agent_principal",
  account_mode: "shared",
  idempotency_key: crypto.randomUUID(),
});

const settled = await actions.waitForInvocation(invocation.invocation_id);
if (needsHumanResolution(settled)) {
  // Do not retry. Hand it to a person.
} else if (settled.state === "executed") {
  const sent = await actions.getResult(settled.invocation_id);
}
terminal
curl -X POST https://api.contro1.com/api/centcom/v1/actions/invoke \
  -H "Authorization: Bearer $CONTRO1_AGENT_CREDENTIAL" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "action_id": "gmail.message.send",
    "input": { "to": "customer@example.com", "subject": "Your invoice", "body": "..." },
    "authority_mode": "agent_principal",
    "account_mode": "shared"
  }'

What is recorded, and what never is

  • Recorded: the invocation, the action, the application, the account and connection, the agent, the person it acted for, who approved, the target and the outcome.
  • Never recorded: message bodies, provider responses, credentials or tokens. They do not appear in an audit record, an error message, a log line or Activity.
  • Activity shows an action Contro1 executed and an action an agent only reported differently. If you are citing evidence, that difference is the evidence.
  • Each state change is hash-chained to the one before it and verified, which catches partial edits and faults. It is integrity verification, not a tamper-proof ledger.

If you are an AI agent helping someone connect

Follow these steps in order.

  • 1. Ask who you are helping: an administrator setting up the organization, a person connecting themselves, or a developer connecting an agent.
  • 2. An administrator: go to contro1.com/apps and add the approved applications (step 1), then to contro1.com/access and grant actions to departments, people and agents (step 2). You cannot grant access yourself; a person does it in Contro1.
  • 3. A person: connect their own accounts on Apps, then add the MCP address to their AI client. Tick "Run Actions as you" only if they want the client to act, not just read.
  • 4. A developer with an agent: install the CLI and run contro1 auth login. A coding agent or runtime on this computer (Claude Code, Cursor, Codex, OpenClaw, NanoClaw): contro1 connect <runtime>. An agent they are building in their own code: contro1 agents register, then a person creates its Agent Credential at contro1.com/settings/agent-keys and stores it as CONTRO1_API_KEY. Do not run contro1 mcp login for that agent: it signs a tool in as the person and creates a second identity.
  • 5. Check it worked: call whoami, then list_actions. If an action you need is missing, call request_capability. Do not work around a missing grant.
  • 6. Never paste a credential into a chat, never send agent_id in a request body, and never retry an action whose outcome is unknown.

Frequently asked questions

Do our developers need to build integrations?

No. The applications are already in Contro1 with their actions defined and rated for risk. An administrator adds them on Apps, and agents reach them through the Contro1 MCP or one HTTP endpoint. For an application that is not in the catalog, import its MCP server or ask Contro1 to add it.

If I grant something to a department, do its agents get it too?

The people in the department do, and so does everyone in the teams beneath it. An agent acting as itself uses only its own capsule. An agent acting for a person can use that person's access, including what they inherited, but only for the actions that person delegated to it.

What happens if an employee has not connected their account?

The action returns user_auth_required. Contro1 never falls back to a shared or organization account, because silently sending from a team mailbox is exactly what that rule prevents.

Can an agent use the account of the person who owns it?

Only if that person delegates it. Ownership says who is accountable for the agent, not what it may do. When the owner gives their agent an action on their own account, that is recorded as their delegation.

Is a sent email guaranteed to be sent exactly once?

No, and Contro1 does not claim it is. Gmail has no idempotency key, so sending is at-most-once. When an outcome is unknown, the invocation stops in execution_indeterminate and a person checks and decides.

Does the Action Gateway need a particular plan?

No. It is part of Contro1 for every organization. Access is decided by grants and by the credential, never by a plan tier or a feature flag.

Related resources

Connect an agent to Contro1

Choose a Contro1 connection path: five agent setup guides for production agents, Claude Code, Codex, Cursor and personal agents, plus web sign-in for Grok, ChatGPT and Claude.ai. Follow exact steps and verify access.

Contro1 CLI

Install and use the contro1 CLI to register AI agents, create approval requests, push AI inventory, retrieve evidence and traces, and test workflows before using the SDK or API.

Contro1 Python SDK

Install and use the framework-agnostic Contro1 Python SDK to request human approvals or input, verify signed webhooks, log autonomous actions, and fetch audit evidence.

Contro1 JavaScript and TypeScript SDK

Install and use @contro1/sdk in Node, TypeScript, Express, Fastify, or Next.js backends to create approval requests, verify webhooks, and write audit records.