Autonomous Agent Access
Let agents call API-key-backed MCP servers through a Unified Access Gateway as themselves, with no user in the loop
Some agents do work of their own, with no person in the loop. Those agents can call MCP tools through a Unified Access Gateway by authenticating as themselves: Access Policies decide what an agent can reach, and each call is recorded in the audit log under the agent’s identity. For why an agent should have its own identity, see Give an agent its own identity.
How it works
Section titled “How it works”The agent gets an access token from Keycard using its own identity (behind the scenes, the SDK uses the client_credentials grant) and sends it to the gateway’s MCP endpoint.
To keep credentials fully separated, there are two actors in the flow: the agent communicating with the gateway, and the gateway acting on behalf of the agent toward the upstream. On each request, the gateway exchanges the agent’s token with Keycard, which runs a policy check for each actor before the request is allowed through:
| Check | Principal | Context |
|---|---|---|
| Subject check | The agent | context.on_behalf == false |
| Delegation check | The gateway | context.on_behalf == true |
Prerequisites
Section titled “Prerequisites”- Manager access to the Zone (see Roles & Permissions)
- The agent registered as an Application with a client credential (see Applications)
- The upstream MCP server registered as a Resource with a vaulted credential (see Vaulted Static Credentials)
- A Unified Access Gateway with the API-key MCP server attached as a dependency (see Unified Access Gateway)
Give an agent access
Section titled “Give an agent access”Access is configured entirely through Access Policies: a Policy permits the agent for the gateway it connects through and for each upstream it may reach.
-
Author the Policy
Permit the agent for the gateway and each API-key upstream, scoped to the agent acting as itself (
context.on_behalfandcontext.impersonatebothfalse):@id("nightly-report-agent-access")@description("Permit the reporting agent the gateway and its API-key upstream")permit (principal is Keycard::Application,action,resource) when {principal.identifier == "<agent-app-identifier>" &&["<gateway-mcp-url>", "<upstream-mcp-url>"].contains(resource.identifier) &&context.on_behalf == false &&context.impersonate == false};An agent permitted for the gateway but not for an upstream connects successfully and is denied that upstream’s tools.
-
Add it to your policy set
Add the new Policy to your policy set and activate the set. See Access Policies for authoring and activating policy sets.
Connect the agent
Section titled “Connect the agent”Copy the gateway’s MCP Access URL from its Application settings page and your Zone’s Issuer URL from Settings → Connection. The SDK handles authentication for the agent and brokers a token for the gateway. The agent then calls the gateway like any MCP server. This example uses the Keycard LangChain SDK:
import os
import httpxfrom mcp import ClientSessionfrom mcp.client.streamable_http import streamable_http_client
from keycardai.langchain import Access, KeycardGrantMiddleware
GATEWAY_URL = "<gateway-mcp-url>"
keycard = KeycardGrantMiddleware( zone_url=os.environ["KEYCARD_ISSUER"], resources=[GATEWAY_URL], client_id=os.environ["KEYCARD_CLIENT_ID"], client_secret=os.environ["KEYCARD_CLIENT_SECRET"],)
async def list_gateway_tools(): with keycard.grant(Access.as_self(), resources=[GATEWAY_URL]) as access: token = access.access(GATEWAY_URL).access_token
http_client = httpx.AsyncClient(headers={"Authorization": f"Bearer {token}"}) async with http_client, streamable_http_client(GATEWAY_URL, http_client=http_client) as (read, write): async with ClientSession(read, write) as session: await session.initialize() return (await session.list_tools()).toolsThere is no sign-in and no authorization prompt: your Policies already authorized the access.
Verify
Section titled “Verify”In Keycard Console, open the agent Application’s page and select the Activity tab: each run shows the credential issuance events for the gateway and the upstream, with no user attached. See Read an Activity Feed for how to read the feed.
Revoke access
Section titled “Revoke access”Remove the agent’s Policy from your policy set, or remove the upstream from that Policy if the agent should keep its other access. The gateway checks policy on every request, so the agent’s very next request is rejected. There is nothing to revoke. The denial shows up in the Audit Log as a denied exchange.
Revoking a user’s access works through grants instead. See Revoke a Grant.
Troubleshooting
Section titled “Troubleshooting”- The token exchange fails with
invalid_target. Either the upstream uses per-user OAuth (which stays on the user path), or the Resource has no vaulted credential yet. For the latter, add one on the Resource with Add credential. - The agent gets a token but an upstream’s tools are missing or denied. No Policy permits the agent for that upstream. Being permitted for the gateway is not enough. Add the upstream to the agent’s Policy, then retry. See Diagnosing policy-blocked actions.
- After activating a custom policy set, an upstream is unreachable through the gateway despite an agent permit. The set is missing the managed
default-app-direct-accesspolicy, which the gateway needs for its own access to the upstream. The denial appears in the audit log with the gateway as principal. Add the managed policy back to the set.