- The connector performs an OAuth on-behalf-of exchange. It does not simply forward a token — Power Platform’s Azure API Connections service takes the user’s Copilot Studio session and exchanges it for an access token, using the connector’s own client credentials. You configure this on the connector’s Security tab, and it happens in all three modes below.
- The gateway performs a second exchange, turning that token into one your MCP server accepts. You configure this on the MCP server’s Auth Data. Token passthrough is the mode where this second exchange does not happen at all.
What you are setting up
Prerequisites
- A Copilot Studio environment, and rights to create custom connectors in the same Power Platform environment as the agent.
- An MCP server in your Azure subscription that validates Entra JWTs and speaks Streamable HTTP (Server-Sent Events is no longer supported). To write one, see Create OAuth app registration with Azure Entra.
- Entra: Cloud Application Administrator is the least-privilege role that covers creating the app registrations and granting admin consent.
- Entra registered as an identity provider in TrueFoundry. See Identity Providers.
- For the CLI path through the app registrations: Azure CLI signed in to the tenant (
az login), plusuuidgen. The portal path needs neither.
The two identities, and why there are two
“The agent’s identity” means two different objects in two different systems. Copilot Studio creates an Entra Agent ID for each agent automatically. You will find it under Entra admin center → Agents, with the person who created the agent recorded as its sponsor, and governed by a Microsoft-published agent identity blueprint. TrueFoundry agent identity is mirror identity that you add in TrueFoundry agent registry. The registry entry binds them by mapping a claim in the incoming Entra token to a TrueFoundry principal you can write policy against.What this leads to
Because the Copilot Studio agent is a managed identity you cannot address, two objects in this setup are stand-ins for it:- Use the Agent ID for — inventory, the sponsor relationship, and Conditional Access on the agent’s own sign-ins within Microsoft 365.
- Use the TrueFoundry agent identity for the call path — which MCP servers and tools the agent may reach, and whom it may act for. That is the part the Agent ID cannot express.
Mapping to a TrueFoundry agent
Create an entry in the Agent Registry:Authentication modes and identity flows
There are three ways in which TrueFoundry gateway supports authentication and token exchanges on this journey$MCP_API, $AGENT_SVC, and $AGENT_CLIENT from earlier ones. If you start a new shell, re-derive them with az ad app list --display-name <name> --query "[0].appId" -o tsv.Part 1: Token passthrough
The copilot connector obtains a token for your MCP server directly and the gateway forwards it unchanged, so there is no token exchange happening at gateway.Token flow
App registrations you need
mcp-api — the tool's audience
- Portal
- Azure CLI
api://<mcp-api-app-id>. Add a delegated scope Tool.Write (type: User, state Enabled), and set requestedAccessTokenVersion: 2 in the manifest.appid instead of azp and a different issuer, which breaks the gateway’s issuer match and its agent lookup at once — hence requestedAccessTokenVersion: 2.mcp-api — authorize Azure API Connections
- Portal
- Azure CLI
fe053c5f-3692-4f14-aef2-ee34fc081cae, ticking Tool.Write.fe053c5f-… GUID is Microsoft’s Azure API Connections service — the thing that obtains tokens on your users’ behalf. Without it authorized here, users get an interactive sign-in prompt on every call instead of a silent hand-off, which presents as a broken connector rather than a missing grant.agent-client — the connector's credentials
- Portal
- Azure CLI
api://<mcp-api-app-id>/Tool.Write, plus Microsoft Graph offline_access. Create a client secret. Under Authentication → Web → Redirect URIs, add https://global.consent.azure-apim.net/redirect.=Scope), never Application (=Role). An application permission yields a token with no user to delegate — it validates cleanly and silently drops the person you were representing.Grant admin consent
- Portal
- Azure CLI
agent-client: API permissions → Grant admin consent.AADSTS65001 rather than prompting.agent-client’s secret goes to the Power Apps connector. Nothing in this mode gives a secret to TrueFoundry — the gateway holds no credential of yours at all.The custom connector
Build it in Power Apps, not with Copilot Studio’s MCP onboarding wizard — the wizard’s OAuth options are all authorization-code and have no on-behalf-of switch, so the user’s identity does not carry through.Import a definition
host and the key under paths:. Keep basePath: /.Configure the Security tab
Scope: Entra derives the audience from the resource of the requested scopes and rejects a request naming two. offline_access is resource-agnostic and yields the refresh token. This is the primary con with token passthrough approach as the connector now gets the broadest scope and there is no way to control that unless we make a token exchange hop through gateway.Share the connector
Add it to the agent
Register the MCP server on TrueFoundry
agent:<your-agent> as an MCP Server User collaborator.
On the gateway’s Identity Provider, list your MCP server’s audience — both api://<mcp-api-app-id> and <mcp-api-app-id> — under Allowed Audiences. That is what the connector’s token is minted for, and without it the gateway returns 401 before it ever calls your MCP server.
What your MCP server receives
Tool.Write in scp, and key the user on oid — not sub. In Entra sub is a pairwise identifier that differs per application, so a per-user store keyed on sub gives one person a different record depending on which mode was used to reach it.
actor_app is agent-client, the connector that actually called. This is the only mode where that is true; the other two overwrite it during their exchange.
scp carries every scope agent-client was consented for on mcp-api, not only the one the connector requested — Entra returns all consented scopes for a resource. The connector’s consent is therefore the ceiling for every MCP server behind it.What you can enforce
The governance gap with token passthrough
agent-service, which your MCP server rejects — so the only route to your tools runs through the gateway, where the exchange happens. Bypass stops being something to prevent and becomes something that cannot be expressed. Scope narrowing moves to the gateway’s per-server Scopes field, and one connector audience fans out to every MCP server behind it.
Part 2: On-behalf-of
The signed-in user’s identity is preserved all the way to your MCP server, and the gateway is on the token path by construction.Token flow
App registrations you need
Three. The third,agent-service, is the one passthrough does not need — and it is what makes the gateway unbypassable, because it gives the connector’s token an audience your MCP server refuses.
agent-service, using its client secret — which is also why TrueFoundry needs no app registration of its own.mcp-api — the tool's audience
- Portal
- Azure CLI
api://<mcp-api-app-id>. Add a delegated scope Tool.Write (type: User, state Enabled), and set requestedAccessTokenVersion: 2 in the manifest.mcp-api here. In this mode the connector’s token targets agent-service, and the pre-authorization belongs there instead.agent-service — the agent's audience, and the gateway's credential
- Portal
- Azure CLI
api://<agent-service-app-id> and add a delegated scope access_as_user. Then, under Expose an API → Authorized client applications, add fe053c5f-3692-4f14-aef2-ee34fc081cae, ticking access_as_user.Under API permissions, add from mcp-api: Delegated → Tool.Write, plus Delegated → Microsoft Graph → offline_access. Then create a client secret — this is the one the gateway will hold. Set requestedAccessTokenVersion: 2.fe053c5f-… GUID is Microsoft’s Azure API Connections service — the thing that obtains tokens on your users’ behalf. Without it authorized on access_as_user, users get an interactive sign-in prompt on every call instead of a silent hand-off, which presents as a broken connector rather than a missing grant.agent-client — the connector's credentials
- Portal
- Azure CLI
api://<agent-service>/access_as_user, plus Microsoft Graph offline_access. Create a client secret. Under Authentication → Web → Redirect URIs, add https://global.consent.azure-apim.net/redirect.=Scope), never Application (=Role), throughout this chain. An application permission yields a token with no user to delegate — it validates cleanly and silently drops the person you were representing.Grant admin consent
- Portal
- Azure CLI
agent-service and agent-client: API permissions → Grant admin consent.AADSTS65001 from the token endpoint.agent-service’s secret goes to TrueFoundry. agent-client’s secret goes to the Power Apps connector. Keep them apart — the gateway has no reason to hold the connector’s credential, and the connector has no reason to hold the gateway’s.The custom connector
Identical to Part 1’s except for two fields on the Security tab. If you already built a passthrough connector, build a second one rather than editing it:Resource URL is single-valued, so changing it converts a connector from one mode to the other. Both can share the same agent-client registration.
Import a definition
host and the key under paths:. Keep basePath: /.Configure the Security tab
agent-service — not your MCP server, and not the gateway. Point it at your MCP server and you have built Part 1 instead.One resource only in Scope: Entra derives the audience from the resource of the requested scopes and rejects a request naming two. offline_access is resource-agnostic and yields the refresh token.Share the connector, then add it to the agent
Register the MCP server on TrueFoundry
agent:<your-agent> as an MCP Server User collaborator.
On the gateway’s Identity Provider, list api://<agent-service-app-id> and <agent-service-app-id> under Allowed Audiences — that is what the connector’s token is minted for in this mode.
Three fields are easy to get wrong:
- Grant Type = JWT Bearer, not Token Exchange. Token Exchange is the RFC 8693 profile other identity providers use; Entra implements RFC 7523 (
jwt-bearer+requested_token_use=on_behalf_of) and rejects the other shape. - Client ID =
agent-service, matching the inbound token’s audience. Anything else givesAADSTS50013. - Scopes names the destination — your MCP server. Point it elsewhere and the exchange succeeds while your MCP server rejects the audience, which reads like an MCP bug.
What your MCP server receives
Tool.Write in scp. Use oid as the stable key for the user, not sub — in Entra sub is a pairwise identifier that differs per application. This is not theoretical: sub changes across the gateway’s exchange while oid does not, so a per-user store keyed on sub gives one person a different record depending on which mode was used to reach it.
actor_app is agent-service, not the connector: the exchange overwrites it. Your MCP server can prove an authorized agent called, but not which connector — per-hop attribution lives in the gateway’s audit trail.
What you can enforce
Part 3: Client credentials
The gateway calls your MCP server under one shared authority. The user is authenticated at the gateway and then deliberately not propagated. Use it for tools that genuinely act under one authority — a shared mailbox, a batch job, a system-of-record write attributed to the service rather than the person. Not as a shortcut past a delegated setup.Token flow
Everything up to the gateway is identical to Part 2 — same connector, same TOKEN A, same inbound validation and RBAC. Only exchange 2 changes.App registrations you need
The same three as Part 2, plus one app role and one assignment. If you have already built Part 2, this mode adds to it rather than replacing anything — the connector and the inbound token are identical, and only the gateway’s outbound call differs.mcp-api — add an app role
- Portal
- Azure CLI
Tool.Write delegated scope, add an app role Tool.Invoke with allowedMemberTypes: ["Application"].roles, never scp. Your MCP server must accept either shape, or this mode fails validation on a token that is perfectly valid.agent-service — request and be assigned the app role
- Portal
- Azure CLI
mcp-api: Application → Tool.Invoke. Then Grant admin consent.Make sure it is added as an Application permission, not a delegated one. Admin consent turns each Application permission into the app-role assignment on agent-service’s own service principal — which is what the client-credentials path needs. There is no separate screen for that assignment: Enterprise applications → mcp-api → Users and groups takes only users and groups.agent-service → API permissions, the Tool.Invoke row should read type Application with Status “Granted for <tenant>”. A “Not granted” warning there is the same condition that surfaces later as AADSTS501051. Granting only the delegated Tool.Write leaves it missing, because a delegated grant contributes scp to a user token and nothing at all to an app-only one.AADSTS501051, which names neither.agent-client — unchanged
agent-service-audienced user token exactly as in Part 2; the user is dropped later, at the gateway’s outbound hop.The custom connector
Unchanged from Part 2. Same connector, sameResource URL, same scope. Point its paths: key at this MCP server entry’s gateway path, or reuse the Part 2 connector and switch entries — the difference between the two modes is entirely on the gateway side.
Register the MCP server on TrueFoundry
The same MCP server, registered again. Only two fields differ from Part 2:/.default, not Tool.Write. An app-only grant cannot request named delegated scopes; it resolves whatever app roles the service principal holds — which is why Tool.Invoke had to be assigned to agent-service, not merely granted.
Add the same agent as an MCP Server User here too.
What your MCP server receives
Tool.Invoke in roles.
What you can enforce
RBAC you can set using the agent identity
Once an agent resolves at the gateway it becomes a first-class principal in your access policy, alongside users, teams and virtual accounts.What the gateway is worth in each mode
The gateway does two separable jobs. It is a control plane — the catalog of which agent may call which server and tool, on whose behalf, under which guardrails, with an audit record naming both parties. And it is a token broker — the thing that converts a token your MCP server would reject into one it accepts. The first job is identical in all three modes. Only the second changes, and every difference below follows from that.Reading the table
The last four rows are the same in all three modes. Identity resolution, agent RBAC, Agent Access, guardrails, rate limits and audit do not depend on the gateway performing an exchange. This is the point most easily missed: passthrough does not reduce the gateway to a proxy. On-behalf-of buys enforcement you cannot get any other way. Because your MCP server rejects the connector’s token, the gateway is on the path by construction — not by configuration, not by convention, and not by anything an application team can accidentally undo. Nothing else in the table is worth as much in a large tenant, and it is why on-behalf-of is the default recommendation. Client credentials buys simplicity at the cost of the user. There is no user in the token, so per-user authorization can only happen at the gateway. Choose it for tools that genuinely act under one shared authority, not as a shortcut past a delegated setup. Passthrough buys two real things, and they are not the ones usually claimed for it. Not “less configuration” — it needs an extra connector per MCP server, which grows faster than the on-behalf-of setup does. What it buys is that the gateway holds no credential of yours, and that your MCP server sees the real calling client rather than the app that performed the last exchange. If your threat model cares more about what a compromised gateway could mint than about whether the gateway can be bypassed, that is a coherent choice. The twodelegated modes are not interchangeable. Passthrough and on-behalf-of both deliver a verified end user, which makes them look equivalent at a glance. They differ on the two rows that matter most — bypassability and azp — and they differ in opposite directions. Neither dominates.
Limits and scaling
Three limits worth knowing
The Copilot Studio Entra Agent ID never reaches your MCP server — and cannot be registered directly anywhere in this chain. If you need the agent’s own Entra identity to travel with the call, the agent must be one that performs its own token exchange — Azure AI Foundry or custom-hosted, not Copilot Studio. Entra emits no nested delegation chain.azp is single-valued and is overwritten at each exchange, so the token your MCP server receives names the app that performed the last exchange — agent-service — not every hop before it. Per-hop attribution lives in the gateway’s audit trail. This is also why passthrough preserves agent-client at your MCP server: with no exchange, there is nothing to overwrite it.
Passthrough moves one guarantee out of identity and into networking. No gateway setting can restore it. If you cannot restrict your MCP server’s network reachability to the gateway, do not use passthrough — the RBAC you configure will be advisory rather than enforced.
Scaling to many agents
Point every agent at the sameagent-service audience. The audience identifies the tier of callers, while each agent is still distinguished by its own agent-client ID in the token. A second agent needs its own agent-client plus one Agent Registry entry; mcp-api and agent-service are shared.
Passthrough (Part 1) scales differently, and less well: Resource URL names one MCP server, so each MCP server needs its own connector. On-behalf-of adds a delegated permission on the shared agent-service instead. With a handful of MCP servers the difference is unimportant; with dozens it is the main argument for on-behalf-of on operational grounds alone.
Troubleshooting
Next steps
- Agent Registry — the full registration flow.
- Agent and its identity with TrueFoundry — how agent identity differs from a user or a virtual account, and how delegation is bounded.
- Agent Governance with Microsoft Entra — the wider Entra scenario.
- MCP Gateway authentication and security — every inbound and outbound option, not just these two.