Skip to content
API Reference
Guides
Use Keycard SDKs

Call External APIs from MCP

Connect MCP tools to third-party APIs via OAuth

Your MCP tools often need to call external APIs as the authenticated user: GitHub for issues and pull requests, Google for calendar or Drive, Slack for messages, or your own internal APIs. Delegated access is the pattern that lets the tool do that without shared service accounts, copied API keys, or blanket OAuth grants.

Keycard handles the token exchange: you write tools, Keycard manages OAuth flows, credential exchange, policy checks, audit, and per-user refresh.

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).

Userauthenticated via Keycard
AI Agentroutes tool calls
Your MCP Serverexchanges token
Keycardscopes & issues token
External APIGitHub, Google, etc.
  1. User authenticates to your MCP server with a Keycard token
  2. Your MCP server exchanges that token for an external API token scoped to the user
  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. Copy your Keycard redirect URL

    In Keycard Console, navigate to Zone Settings and copy the OAuth2 Redirect URL. You will need this when creating the OAuth App at your provider.

  2. Create an OAuth App at your provider

    In your provider’s developer console (e.g., GitHub Developer Settings, Google Cloud Console), create an OAuth App. Set the authorization callback / redirect URI to the URL you copied in step 1. Note the Client ID and Client Secret. You will need them in the next step.

  3. Add the API from the Catalog

    In Keycard Console, navigate to Applications -> Add Application -> Explore API Servers and add the API you want to integrate. Enter the Client ID and Client Secret from step 2. For per-vendor setup instructions, see the API server catalog - we have ready-to-use entries for GitHub, Gmail, Google Calendar, Google Drive, Jira, Confluence, Linear, Sentry, Slack, and Attio.

  4. Register your MCP server Resource

    Navigate to ResourcesCreate Resource:

    FieldValue
    Resource NameYour MCP Server
    Resource Identifierhttp://localhost:8000/mcp
    Credential ProviderZone Provider
  5. 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. These go into your environment as KEYCARD_CLIENT_ID and KEYCARD_CLIENT_SECRET. Your MCP server passes them to AuthProvider so it can exchange tokens on behalf of users.

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 Resource: 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)

  • 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