Skip to main content
When an agent or a client calls a tool through the MCP gateway, the gateway injects the upstream credential at the edge. Which credential depends on who is calling and on the policy you set per attachment — so one virtual server can serve a whole org without everyone sharing one identity. The agent itself stays generic: identity is never baked into it, it’s resolved per call.

Upstream auth types

How an upstream holds credentials in the first place:
With --oauth, the gateway discovers the provider and registers itself automatically (PKCE required); pass --oauth-client-id/--oauth-client-secret only for providers that don’t support dynamic registration. An oauth upstream with no connected accounts reports needs_auth health — a prompt to connect, not an outage.

Connecting an account

connect opens the provider’s consent page and waits for the grant to land. In the dashboard, members connect from the upstream row, and an agent’s integrations are authorized from its own agent page — the connectors panel lists every per-user OAuth upstream reachable through that agent’s connectors, with authorize, re-authorize, and revoke.
When you authorize an agent, the account you consent with becomes that agent’s identity on the upstream. Consent with a purpose-scoped account, not your personal one, unless you mean to hand the agent your whole access.
Tokens are vaulted encrypted and refreshed automatically; grants are never returned by the API. Disconnecting revokes upstream where the provider supports it. Deleting an agent revokes its grants, and transferring an app to another org drops the moved agents’ grants — the destination org re-consents.

How the identity is resolved

Identity follows the caller — there is nothing to configure for the common case: For a per-user OAuth upstream, the gateway resolves:
  • An agent-held token → that agent’s own connected account. Never its owner’s.
  • An unrestricted member token → that member’s own connected account.
  • Anything else (a scoped API key, which is neither a live user nor an agent) → denied.
An agent never inherits your connected account. Authorize the agent itself and it acts as its own identity — that is the whole configuration step.
The denial is explicit: “this endpoint resolves the caller’s own account, and this credential carries no resolvable identity (a scoped key is neither a live user nor an agent); call with an unrestricted credential or through an agent session, or bind a grant to the attachment.”

Bound accounts

The one policy you can store per attachment pins one pre-consented account for every caller, regardless of who calls:
Run zwrm mcp upstream grants <upstream> to find the principal to bind. The dashboard’s virtual-server editor offers the same two choices as an Identity row: each caller’s own account or a bound account. Use a bound account when headless work needs an identity nobody will consent to interactively — but see the warning below about what a shared account exposes.

Choosing well

A credential is an access view: whoever calls the connector sees everything that identity can reach. org_shared and a bound_grant pointed at a broad personal account expose that reach to every caller — so back shared connectors with a purpose-scoped service identity, never a real person’s general-purpose account. There is no shared-credential shortcut to per-user data: if callers must see their own view, they need their own connected accounts — which is exactly what the default does. Every proxied call is audited with the resolved principal, so an agent’s call records which agent acted, not just who owns it.