Skip to content
API Reference
Guides
MCP Servers
Delegated Access

Add Delegated Access

Let your MCP tools call GitHub, Google, and other APIs on behalf of authenticated users

Your MCP tools need to call external APIs as the user, not a shared service account. Keycard’s token exchange handles this — you write tools, Keycard manages OAuth flows, credential exchange, and refresh per-user.

Token exchange lets your MCP server act as both a protected resource (receiving authenticated requests from AI agents) and an API client (calling upstream APIs on behalf of the authenticated user).

flowchart LR
    A[User] -->|Token A| B[AI Agent]
    B -->|Token A| C[Your MCP Server]
    C -->|Exchange A → B| D[Keycard]
    D -->|Token B| C
    C -->|Token B| E[External API]
  1. User authenticates to your MCP server with a Keycard token (Token A)
  2. Your MCP server exchanges Token A for an external API token (Token B)
  3. Your MCP server calls the external API with the exchanged token
  4. The user’s data is accessed with their own permissions — not a shared service account

These steps are the same regardless of which external API you’re integrating. Complete them before following a provider-specific guide.

  1. Add the API from Resource Catalog

    In Keycard Console, navigate to Resource Catalog and add the API you want to integrate (e.g., GitHub, Google Calendar, Google Drive). This automatically creates the OAuth provider and API resource.

  2. Set up the OAuth App callback

    1. Go to Zone Settings in Keycard Console and copy the OAuth2 Redirect URL
    2. In the external provider’s developer console, create or edit your OAuth App
    3. Set the authorization callback / redirect URI to the Keycard redirect URL
  3. Register your MCP server resource

    Navigate to ResourcesCreate Resource:

    FieldValue
    Resource NameYour MCP Server
    Resource Identifierhttp://localhost:8000/mcp
    Credential ProviderZone Provider
  4. Create an Application

    Navigate to ApplicationsCreate Application:

    FieldValue
    Provided ResourceYour MCP Server
    DependencyThe external API resource(s)

    After creating the application, generate client credentials (Client ID + Client Secret) and save them.

Every third-party integration follows the same steps:

  1. Add from Resource Catalog (or manually create the provider and resource for any OAuth 2.0 API)
  2. Register your MCP server — set Credential Provider to Zone Provider
  3. Create an Application — set your MCP server as the Provided Resource and external APIs as Dependencies
  4. Generate client credentials — Client ID + Client Secret for your application
  5. Use the grant pattern in code:
@auth_provider.grant("https://api.example.com")
async def my_tool(ctx: Context):
access_context: AccessContext = await ctx.get_state("keycardai")
token = access_context.access("https://api.example.com").access_token
# Call API with token

This works for any OAuth 2.0 provider — Slack, Linear, Notion, and more.

Follow a provider-specific guide to see the full implementation:

When deploying to production:

  • Update resource identifiers in Keycard Console to your production URLs (must use HTTPS)
  • Update OAuth redirect URIs in GitHub/Google to match your production Keycard zone
  • Set environment variables securely — never commit client secrets to source control
  • Token caching and refresh is handled automatically by Keycard

Symptom: access_context.has_errors() returns True (Python) / accessContext.hasErrors() returns true (TypeScript) / ac.HasErrors() returns true (Go)

  • Verify the external API resource is added as a dependency on your Application
  • Check that the OAuth provider credentials (in Resource Catalog) are correct
  • Ensure the user has completed the OAuth consent flow for the external API
  • Confirm your MCP server is reachable at the registered resource identifier URL

Symptom: External API returns 401 Unauthorized

  • Token refresh is automatic — if this persists, check provider configuration
  • Verify the scopes in Keycard Console match what the API requires
  • The user may need to re-authorize if they revoked access

Symptom: External API returns 403 Forbidden or missing data

  • Ensure scopes in Keycard Console match what the API requires
  • For Google: verify the required APIs are enabled in Google Cloud Console
  • User may need to disconnect and reconnect to pick up new scopes