Per-Agent API & MCP
Issue a key bound to a single agent. The /v1/agents/:agentId REST surface, the agent MCP endpoint, the agent scope namespace, the tool catalog, and the isolation guarantee.
What a per-agent key is
A per-agent key (ca_agt_…) is bound server-side to exactly one agent. It can read and (if you grant it) drive that one agent — and nothing else. It cannot enumerate other agents, cannot reach your contacts, billing, inboxes, integrations, or webhooks, and cannot mint keys.
This is ideal for handing a single agent to a third party, an embedded app, or a CI job without exposing the rest of your account.
The binding lives on the hashed key row in our database, not in the URL. Changing the :agentId in a request path does not widen a per-agent key — it just gets a 403.
Where to mint the key
Per-agent keys are minted from the agent's own settings, not the account API-keys page:
- Dashboard: open the agent → Settings → API & MCP → New key. Copy the secret immediately (shown once).
- REST:
POST /v1/agents/:agentId/api-keys(admin session or account key, depending on your org policy).
curl -X POST https://api.customagents.io/v1/agents/agent_abc123/api-keys \
-H "Authorization: Bearer ca_acct_YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Embed: support widget",
"scopes": ["agent:config:read", "agent:conversations:read"]
}'{
"id": "key_def456",
"name": "Embed: support widget",
"keyType": "agent",
"agentId": "agent_abc123",
"keyPrefix": "ca_agt_",
"scopes": ["agent:config:read", "agent:conversations:read"],
"key": "ca_agt_…", // shown ONCE
"createdAt": "2026-06-17T10:30:00Z"
}The keyType and agentId are forced server-side — you cannot widen a key by passing a different agent, an account scope, *, or write:api_keys. A per-agent key is also denied this route: a key cannot mint another key.
Agent scopes
A per-agent key holds scopes only from the agent: namespace. The default (when scopes are omitted) is read-only.
| Scope | Grants | Default |
|---|---|---|
agent:config:read | Read this agent's configuration | ✓ |
agent:conversations:read | Read this agent's conversations | ✓ |
agent:activity:read | Read this agent's activity | ✓ |
agent:config:write | Update this agent's configuration | opt-in |
agent:trigger | Trigger this agent via chat — money-spending | opt-in |
agent:trigger is separated from the reads so a read-only key can never spend credits. Grant it only when the key needs to drive the agent.
REST surface
A ca_agt_ key can reach only /v1/agents/<its-own-agentId>/**:
| Method & path | Required scope |
|---|---|
GET /v1/agents/:id | agent:config:read |
PATCH /v1/agents/:id | agent:config:write |
GET /v1/agents/:id/contacts | agent:conversations:read |
GET /v1/agents/:id/drafts | agent:conversations:read |
GET /v1/agents/:id/activity | agent:activity:read |
POST /v1/agents/:id/chat | agent:trigger |
# Read this agent's config
curl https://api.customagents.io/v1/agents/agent_abc123 \
-H "Authorization: Bearer ca_agt_YOUR_KEY"
# Trigger the agent (requires agent:trigger)
curl -X POST https://api.customagents.io/v1/agents/agent_abc123/chat \
-H "Authorization: Bearer ca_agt_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "message": "Summarize today's open threads" }'Per-agent MCP
The agent also exposes a dedicated MCP endpoint so an IDE can work with just that one agent:
Per-agent MCP endpoint: https://api.customagents.io/v1/agents/<AGENT_ID>/mcpAuthenticate with the ca_agt_ key for that agent. Configuration is identical to the account MCP setup — only the URL and key differ. For Claude Code:
claude mcp add --transport http my-agent \
https://api.customagents.io/v1/agents/agent_abc123/mcp \
--header "Authorization: Bearer ca_agt_YOUR_KEY"Agent tool catalog
The per-agent MCP server registers only agent-scoped tools — there is no list_agents and no cross-agent or account tool. Every query is hard-bound to { organizationId, agentId }. Destructive tools prompt for confirmation in the IDE.
| Tool | Required scope | Destructive |
|---|---|---|
get_agent_config | agent:config:read | — |
get_agent_conversations | agent:conversations:read | — |
get_agent_activity | agent:activity:read | — |
update_agent_config | agent:config:write | Yes |
trigger_agent | agent:trigger | Yes |
Isolation guarantee
A per-agent key (ca_agt_…) is structurally confined to its one agent. Concretely, it returns 403 on:
- The account MCP endpoint
POST /v1/mcp. - Any other agent:
GET /v1/agents/<otherId>/**and/v1/agents/<otherId>/mcp. - The agents collection
GET/POST /v1/agents. - Every account router: inboxes, domains, webhooks, integrations, subscriptions, payment methods, team, notifications, stats, usage, logs, feed, and
api_keys. - Bulk endpoints such as account-wide
/activityand/drafts.
There is no cross-agent or account tool in the per-agent MCP server, so isolation is structural, not just a permission check. A compromised per-agent key cannot enumerate your other agents or touch inboxes, billing, or integrations.
See also
Connect your account to an IDE (MCP)
Use your CustomAgents account from Claude Code, Cursor, Claude Desktop, or VS Code over the Model Context Protocol. Endpoint, IDE config, tool catalog, and security.
SDKs & Libraries
How to call CustomAgents from your code today — the REST API and the hosted MCP server. There is no published client library yet.