> ## Documentation Index
> Fetch the complete documentation index at: https://www.truefoundry.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent and its Identity with TrueFoundry

> How agent registration associates an identity with each agent, backed by TrueFoundry or your identity provider, and how to pass and govern it in your code.

<Info>
  **Beta** — Agent Identity is in beta. The behavior and configuration described
  here may change.
</Info>

When an agent calls an MCP server or another agent, the receiving side needs to know **which agent** is calling — not just that some credential was presented. Without that, an agent either borrows the user's token, and vanishes from the record, or shares a service account with every other workload, and takes their permissions along with it.

An **agent identity** is how a registered agent proves who it is. Every agent you register in TrueFoundry has exactly one, created as part of registering the agent itself, and presents it on every call it makes.

## Where an identity comes from

Agent identity is not a separate object you create and then attach. It is a step in registering the agent, so the identity and the agent are one-to-one — registering the agent brings its identity into being, and deleting the agent takes it away.

<Frame caption="The Agent Identity step of the Integrate a Remote Agent flow">
  <img src="https://mintcdn.com/truefoundry/SJJ7CvojZAq_8UxL/images/docs/ai-gateway/agents/agent-registration-agent-identity.png?fit=max&auto=format&n=SJJ7CvojZAq_8UxL&q=85&s=db9386e641ff9e25e17518265857d592" alt="Agent Identity step of the Integrate a Remote Agent flow with TrueFoundry-backed selected and Identity provider-backed available" width="2000" height="1139" data-path="images/docs/ai-gateway/agents/agent-registration-agent-identity.png" />
</Frame>

The **Agent Identity** step asks *how does this agent prove who it is?* You pick where the credential comes from:

|                                                   | **TrueFoundry-backed**                                 | **Identity provider-backed**                                                            |
| ------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------- |
| Who issues and signs the credential               | TrueFoundry                                            | Your identity provider — Okta, Microsoft Entra, and similar                             |
| Agent registered in an external identity provider | Not required                                           | Required                                                                                |
| Best for                                          | Agents you build and run yourself, and getting started | Organizations where the identity provider stays the source of truth for every principal |

The identity means the same thing either way — only its issuer differs. For the rest of the registration flow, see [Remote Agents](/docs/agent-platform/agent-registry/remote-agents).

An agent has an identity whether or not the Gateway proxies calls to it. An *embedded* agent — hosted elsewhere, with no callable URL for the Gateway to front — still presents its identity on the calls **it** makes, so its outbound traffic is governed even though inbound traffic to it is not.

## How it differs from a user or a virtual account

TrueFoundry already has two kinds of principal, and an agent identity is a third — it is not a rename of either.

|            | User                            | Virtual account              | Agent identity                                |
| ---------- | ------------------------------- | ---------------------------- | --------------------------------------------- |
| Represents | A person                        | A service or application     | A registered agent                            |
| Acts as    | Itself                          | Itself                       | Itself, **or on behalf of a user or service** |
| Created by | Inviting a person to the tenant | Creating the virtual account | Registering the agent                         |

**Delegation is the difference that matters.** A virtual account can only ever act as itself: point one at an MCP server and every call looks identical, whoever prompted it. An agent identity can act *on behalf of* someone else — a user, or a service — so a single registered agent serving many callers makes calls that stay attributable to whoever each one is for, while remaining identifiable as the agent.

## Who the agent can act for

Delegation is bounded by the agent's **collaborators**, on the **Access Control** step of the agent's registration. The same list that decides who may invoke the agent also decides who the agent may act for.

<Frame caption="Collaborators on an agent: Agent Manager can edit it, Agent Access can invoke it and be acted for by it">
  <img src="https://mintcdn.com/truefoundry/SJJ7CvojZAq_8UxL/images/docs/ai-gateway/agents/agent-collaborators.png?fit=max&auto=format&n=SJJ7CvojZAq_8UxL&q=85&s=fdff0689254e87a3fcccf72c7418b94e" alt="Access Control step showing collaborators Akash Gupta as Agent Manager and everyone as Agent Access, with Add Collaborators and View Permission Details controls" width="1570" height="690" data-path="images/docs/ai-gateway/agents/agent-collaborators.png" />
</Frame>

| Role              | Grants                                       |
| ----------------- | -------------------------------------------- |
| **Agent Manager** | Edit the agent and its configuration         |
| **Agent Access**  | Invoke the agent, **and** be acted for by it |

Each collaborator can be a user, a team, or a virtual account:

| Collaborator    | The agent acts for |
| --------------- | ------------------ |
| User            | That person        |
| Team            | Anyone on the team |
| Virtual account | That service       |

A virtual account collaborator is how delegation works when there is no human involved. A pipeline or scheduled job authenticates as itself, the agent acts on its behalf, and the call stays attributable to both — the same delegation, with a non-human identity in the subject's place.

Reading the two roles together: anyone with **Agent Access** can both drive the agent and have the agent act in their name. In the screenshot above, `everyone` has Agent Access, so the agent can act on behalf of anyone in the tenant — but never on behalf of someone with no Agent Access grant, even if that person could reach the same MCP server directly.

<Tip>
  Scope **Agent Access** to the teams that actually use the agent when you want
  delegation held to a smaller set. Granting it to `everyone` is convenient for
  getting started, and wider than most agents need.
</Tip>

## Passing the identity in your code

A delegated call carries two bearer tokens: the user in the standard `Authorization` header, and the agent alongside it in `x-tfy-agent-authorization`.

| Header                      | Carries                    | Required |
| --------------------------- | -------------------------- | -------- |
| `Authorization`             | The user's token           | Yes      |
| `x-tfy-agent-authorization` | The agent's identity token | No       |

The same header pair works on every surface an agent talks to, so an agent that calls a model, a tool, and another agent presents its identity the same way in all three.

<Tabs>
  <Tab title="LLM Gateway">
    Calling a model on behalf of a user:

    ```bash theme={"dark"}
    curl ${GATEWAY_BASE_URL}/api/llm/chat/completions \
      -H "Authorization: Bearer ${USER_TOKEN}" \
      -H "x-tfy-agent-authorization: Bearer ${AGENT_TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "<model>",
        "messages": [{"role": "user", "content": "Summarize my open tickets"}]
      }'
    ```
  </Tab>

  <Tab title="MCP Gateway">
    Calling a tool on an MCP server on behalf of a user:

    ```bash theme={"dark"}
    curl ${GATEWAY_BASE_URL}/mcp/<server-name>/server \
      -H "Authorization: Bearer ${USER_TOKEN}" \
      -H "x-tfy-agent-authorization: Bearer ${AGENT_TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {"name": "search_tickets", "arguments": {"query": "open"}}
      }'
    ```
  </Tab>

  <Tab title="Agent Gateway">
    Calling another registered agent on behalf of a user:

    ```bash theme={"dark"}
    curl ${GATEWAY_BASE_URL}/agent/<agent-name> \
      -H "Authorization: Bearer ${USER_TOKEN}" \
      -H "x-tfy-agent-authorization: Bearer ${AGENT_TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{"messages": [{"role": "user", "content": "Summarize my open tickets"}]}'
    ```
  </Tab>
</Tabs>

Because the user token sits where it always has, adding an agent identity to an existing integration is additive — you attach one more header and the call keeps working exactly as before, now attributed to the agent as well.

<Warning>
  The agent identity token authenticates the agent itself. Keep it out of source
  control and out of anything the model can read back — an agent that can be
  prompted into disclosing its own token can be impersonated.
</Warning>

## Granting the agent access to a target

An agent reaches an MCP server the same way anyone else does — by being a collaborator on it. On the server's **Collaborators**, the picker offers **Users**, **Teams**, and **Agents**; pick the agent and give it a role, exactly as you would a person.

<Frame caption="Adding a registered agent as a collaborator on an MCP server">
  <img src="https://mintcdn.com/truefoundry/SJJ7CvojZAq_8UxL/images/docs/ai-gateway/agents/mcp-server-agent-collaborator.png?fit=max&auto=format&n=SJJ7CvojZAq_8UxL&q=85&s=4a960b76b9f160b7e5c4fb2a266ff7a3" alt="Update MCP Server dialog with collaborators developer as MCP Server Manager and my-remote-agent as MCP Server User, and the collaborator picker open on the Agents tab" width="1552" height="920" data-path="images/docs/ai-gateway/agents/mcp-server-agent-collaborator.png" />
</Frame>

There is no separate agent-specific permission model to learn. An agent takes the same roles as any other collaborator — **MCP Server User** to call the server's tools, **MCP Server Manager** to administer it — and granting that access is all the agent needs to reach the target.

<Note>
  In the YAML manifest, an agent collaborator is written with an `agent:` prefix
  on the subject — `agent:my-remote-agent` — alongside the `user:`, `team:`, and
  `virtualaccount:` prefixes.
</Note>

<Note>
  Access to the target and permission to delegate are two different grants.
  Being a collaborator on the MCP server lets the agent reach it; [Agent Access
  on the agent](#who-the-agent-can-act-for) decides whom it may act for once
  there.
</Note>

## What changes at the Gateway

Adding an agent identity changes **inbound** authentication only — how the Gateway identifies and authorizes the caller. Everything downstream is unaffected.

|          | With an agent identity                                                    |
| -------- | ------------------------------------------------------------------------- |
| Inbound  | The Gateway resolves both the user and the agent, and authorizes the pair |
| Outbound | Unchanged — the target is called exactly as it was before                 |

Because outbound authentication is untouched, whatever a target is already configured to use — OAuth2, a shared API key, token passthrough — keeps working as-is. Introducing agent identity to an existing setup does not require reconfiguring a single MCP server's upstream auth.

## End-to-end flow

Put together, here is a full chain: **user → agent → agent → MCP server**. Jane asks a planner agent to summarize her open tickets; the planner delegates to a research agent, which calls a Zendesk MCP server. Two things hold at every hop: **the user stays the same**, and **the agent header changes to whichever agent is currently calling**.

```mermaid theme={"dark"}
sequenceDiagram
    participant Jane as Jane (user)
    participant GW as Agent / MCP Gateway
    participant A1 as planner-agent
    participant A2 as research-agent
    participant MCP as Zendesk MCP Server

    Jane->>GW: Authorization: Jane
    Note over GW: Jane may call planner-agent?
    GW->>A1: Invoke planner-agent

    A1->>GW: Authorization: Jane<br/>x-tfy-agent-authorization: planner-agent
    Note over GW: planner-agent may call research-agent?<br/>planner-agent may act for Jane?
    GW->>A2: Invoke research-agent

    A2->>GW: Authorization: Jane<br/>x-tfy-agent-authorization: research-agent
    Note over GW: research-agent allowed on Zendesk MCP?<br/>research-agent may act for Jane?
    GW->>MCP: Call search_tickets
    MCP-->>GW: Jane's open tickets
    GW-->>A2: Result
    A2-->>A1: Summary
    A1-->>Jane: "You have 4 open tickets…"
```

Hop by hop:

| Hop                            | `Authorization` | `x-tfy-agent-authorization` | What the Gateway checks                                                |
| ------------------------------ | --------------- | --------------------------- | ---------------------------------------------------------------------- |
| Jane → planner-agent           | Jane            | —                           | Jane may call `planner-agent`                                          |
| planner-agent → research-agent | Jane            | `planner-agent`             | `planner-agent` may call `research-agent`, and may act for Jane        |
| research-agent → Zendesk MCP   | Jane            | `research-agent`            | `research-agent` is a collaborator on the server, and may act for Jane |

Two properties come out of this, and together they are the point of the design:

* **The user is never lost.** Zendesk is reached on Jane's behalf, so it returns Jane's tickets and enforces Jane's permissions — three hops from where she started.
* **Every hop is checked against the agent actually calling.** `research-agent` needs its own access to Zendesk and its own permission to act for Jane. It inherits neither from `planner-agent`, so a chain cannot accumulate reach that no single agent was granted.

<Note>
  Each agent replaces the agent header with its own identity while passing the
  user's token through unchanged. An agent is authorized on what **it** was
  granted, not on what its caller holds.
</Note>

## FAQ

<AccordionGroup>
  <Accordion title="What happens if the agent header isn't passed?">
    The call is an ordinary user call. `Authorization` is the only required header, so a request carrying just the user's token is authorized on the user's permissions alone, with no agent attribution and no delegation checks.

    This is what makes adoption incremental: existing integrations keep working untouched, and an agent starts being attributed the moment it begins sending `x-tfy-agent-authorization` — with no change needed at the target.
  </Accordion>

  <Accordion title="What does a denied call look like?">
    A denied call returns `403`, the same as any other permission denial, so
    nothing about your client's error handling needs to change. Only the message
    differs, carrying the real reason — which principal was refused, and why. An
    agent that lacks access to a target is therefore distinguishable from a user
    who lacks it, without inspecting anything but the message.
  </Accordion>

  <Accordion title="Can an agent act for someone who isn't a collaborator on it?">
    No. If the user has no **Agent Access** grant on the agent, the delegated call
    is rejected — even when that user could reach the same MCP server directly.
    Access to a target and permission to delegate are separate grants, and both
    must hold.
  </Accordion>

  <Accordion title="Does an agent identity replace a virtual account?">
    No. A virtual account still fits any service that acts only as itself. An
    agent identity is for an agent that acts *on behalf of* users or services,
    where you need the call attributable to both the agent and whoever it was for.
    See [How it differs from a user or a virtual
    account](#how-it-differs-from-a-user-or-a-virtual-account).
  </Accordion>

  <Accordion title="Do I need an identity provider to use agent identity?">
    Only if you choose an identity provider-backed identity. With a TrueFoundry-backed identity, TrueFoundry issues and signs the agent's token and there is nothing external to configure.

    Pick identity provider-backed when your own provider — Okta, Microsoft Entra, or similar — should remain the source of truth for every principal. Each agent chooses independently, so both kinds can coexist in the same tenant.
  </Accordion>
</AccordionGroup>
