Skip to main content

Run agents in CI and headless jobs

CI pipelines, scheduled jobs, and backend services run with no person present. apistash gives them purpose-issued credentials that authenticate headlessly — a browser session can't be used here (dashboard cookies and JWTs are rejected on the MCP endpoint), which is exactly what keeps a stolen login from becoming agent access.

Two ways to authenticate a headless agent​

  • Org-scoped API key — the simplest. Create a key, scope it, store it in your CI secret store, and send it in the X-API-Key: <key> header. Point its usage and quota at the organization with org_scope. See Authentication → API keys.
  • OAuth client credentials — for a service that acts as an organization with no user at all. A confidential OAuth client authenticates as itself and receives an access token to send as Authorization: Bearer <token> on the MCP endpoint. It's a first-class machine identity, independent of any person's key. Public clients can't use this grant, and clients are registered in the dashboard (there's no self-registration). See Authentication → OAuth.

Both are headless and non-interactive — no login prompt, no redirect.

What it can reach​

Every credential is granted the categories it can use (tools, resources, prompts, agents, or the OAuth mcp_* equivalents) explicitly, and an organization credential's team bindings additionally decide which team-scoped content it sees — all filtered by the access model. Tools and Agents are independent: Agent delivery through bootstrap and agent_context requires Agents and the applicable Agent visibility controls. Tools is required for governed tool calls. An organization API key cannot be granted more capability than its creator holds. An OAuth registration that contains Client Credentials—including a dual-flow registration—is likewise capped to the registrar's current management permissions and MCP capabilities in the selected team context.

Scope it tight, one per job​

Treat a CI credential like any production secret:

  • One credential per pipeline or service, so you can revoke and audit each independently — revocation blocks the next request.
  • Least privilege — allow only the tools the job actually uses. A build step that just needs arithmetic and time gets exactly those. See Scope an agent to least privilege.
  • Store it in a secret manager, never in source control, and rotate it periodically.

For example, a key limited to the three tools a pipeline calls — the tools capability opens the surface, and the tool_policy narrows it (tools are listed by ID; the dashboard's key form picks them by name for you):

{
"name": "ci-release-agent",
"mcp_capabilities": ["tools"],
"grants": [{ "scope": { "type": "personal" }, "permissions": [] }],
"tool_policy": {
"mode": "whitelist",
"tools": ["<calculator-tool-id>", "<datetime-now-tool-id>", "<json-to-yaml-tool-id>"]
}
}

A per-key list narrows which governed tools that key may call; it does not by itself hand the key a tool. The key needs the tools capability for those governed tools, and it reaches the intersection of your account's tool selection (Settings → MCP Settings) and its own list — so make sure the three tools above are selected there too. Otherwise the pipeline sees only the authenticated system tools setup, bootstrap, and agent_context. With the capability, the whitelist, and the selection in place, the agent sees exactly the three governed tools above plus those three fixed system tools — with no person and no browser anywhere in the loop.

To run under the organization's identity and quota instead, use org_scope or an OAuth client (above), where reach is narrowed by team bindings rather than a per-key tool list.