Security and identity model
Understand how MCP Stack handles OAuth, user identity, static headers, service accounts, app sessions, and client tools.
MCP Stack is designed so production agents do not need shared service-account shortcuts for user data. The preferred model is:
Gateway brokers the user grant and keeps the OAuth boundary out of every individual MCP client.
Use app-token auth when the agent is embedded inside a product that already signed the user in.
useAppAgent({
apiKey: "mcpstack_pk_xxxx",
agentId: "ag_xxxxx",
appSessionKey: session.id,
userIdentity: {
subject: session.user.id,
email: session.user.email,
organizationId: session.organizationId,
},
auth: {
mode: "app-token",
getToken: () => session.getAccessToken(),
},
});Gateway accepts that token only when the MCP server's Gateway profile matches the token issuer and audience, the agent is linked to that server, the request origin is allowed for the agent, and the requested scopes fit the server. The app remains responsible for issuing and refreshing its own user token.
The token getter should read from the app's current session at call time. If the app refreshes tokens, the SDK should receive the refreshed token without requiring a page reload or a second sign-in flow.
Use Gateway OAuth when an external MCP client needs user-scoped access to an upstream API.
Gateway needs:
Gateway publishes OAuth protected-resource and authorization-server metadata so MCP clients can discover how to authorize.
Embedded app auth and external OAuth can coexist on the same Gateway-backed MCP server.
Gateway can see the same person through more than one path:
If both paths authenticate the same app user in the same organization, Gateway should treat them as the same user for tool permissions and audit identity.
Use the stable app user id and organization/workspace id for that match. A session id is useful for debugging which login or grant was used, but it should not be the only value that decides who the user is.
Use Static Headers when every tool call should include the same upstream value.
Examples:
X-API-Key=UPSTREAM_API_KEYX-Tenant-Id=UPSTREAM_TENANT_IDAuthorization=UPSTREAM_AUTHORIZATIONStatic headers are not the right answer for user-scoped OAuth. If a token should vary by user, use Gateway.
Use Public API mode when no upstream credentials are required by the generated runtime.
Examples:
Public API mode does not add an OAuth layer.
When using @mcpstack/agent-sdk, pass the current host-app user as userIdentity:
<McpStackChat
apiKey="mcpstack_pk_xxxx"
agentId="ag_xxxxx"
appSessionKey={session.id}
userIdentity={{
subject: session.user.id,
email: session.user.email,
organizationId: session.organizationId,
displayName: session.user.name,
}}
/>This tells the SDK which signed-in user is using the agent. With app-token auth, it also gives Gateway and usage analytics a stable user and organization boundary.
Pass appSessionKey from your host app session. This prevents persisted MCP auth and resumed conversations from leaking across logout/login boundaries.
Use a value that changes when:
Do not use a static value for every user.
MCP Stack service-account keys are for automation against MCP Stack management APIs and CLI workflows. They are not a replacement for downstream user OAuth.
Use service-account keys for:
Do not use service-account keys to impersonate end users inside a SaaS product.
clientTools run inside the host app, not on the MCP server. They let an embedded agent manipulate local UI state, read page context, draft form fields, or trigger host-app workflows.
Treat client tools as privileged app code:
Choose the auth mode that matches your upstream API:
userIdentity, appSessionKey, and auth.getToken.Member roles (Owner, Admin, Developer, Viewer) control what each person can do in your organization. Billing visibility and checkout are separate from general read-only access.
See Organization roles and billing access for the full role and billing matrix.
See also API keys and service accounts for automation credentials and Embed an agent with app auth for end-user identity in embedded surfaces.