ZuploZuplo
LoginSign Up
  • Documentation
  • API Reference
Introduction
Getting Started
    Develop using the Portal
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingMCP - Quick start
    Develop Locally
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth
Concepts
Development
Policies
Handlers
API Keys
MCP Server
MCP Gateway
    IntroductionBetaQuickstartQuickstart (Local Dev)How it works
    Connect MCP clients
    Authentication
      OverviewUpstream OAuthConnect an upstream OAuth provider
      Identity providers
        Auth0Amazon CognitoClerkMicrosoft EntraGoogleKeycloakLogtoOktaOneLoginPingOneWorkOSGeneric OIDC
      Manual OAuth testing
    Configuration
    Observability
    ReferenceTroubleshooting
AI Gateway
Developer Portal
Monetization
Deploying & Source Control
Observability
Networking & Infrastructure
Account Management
Programming API
Build with AI
Zuplo CLI
Migration Guides
Platform LimitsSecuritySupportTrust & ComplianceChangelog
powered by Zudoku
Identity providers

Configuring Clerk

The MCP Gateway can use Clerk as the identity provider behind its downstream OAuth flow. The mcp-clerk-oauth-inbound policy is a Clerk-friendly wrapper around the generic mcp-oauth-inbound policy: provide your Clerk Frontend API URL, a client ID, and a client secret, and the policy derives the OIDC issuer, JWKS URL, and authorize and token URLs for you.

This guide walks through the Clerk dashboard setup, then wires the policy into a gateway project. Read the authentication overview first for the two-layer OAuth model.

Set up Clerk

The MCP Gateway acts as an OAuth 2.1 authorization server in front of Clerk. Clerk handles browser login; the gateway issues its own access tokens that bind to MCP routes.

Create an OAuth application

  1. In the Clerk Dashboard, switch to the instance you want the gateway to use, then open Configure → OAuth Applications.
  2. Click Add OAuth application.
  3. Give the application a name (for example, Zuplo MCP Gateway).
  4. Set Redirect URIs to https://<gateway-host>/oauth/callback. Add http://localhost:9000/oauth/callback for local development with zuplo dev.
  5. Select the OIDC scopes the gateway needs — openid, profile, and email are enough.
  6. Click Save.

Note the Client ID and Client Secret from the application's detail page. You'll wire these into the policy in the next section.

Find the Frontend API URL

Open Configure → Domains in the Clerk Dashboard. The Frontend API URL is shown at the top — it looks like https://verb-noun-00.clerk.accounts.dev on development instances or https://clerk.example.com on production instances with a custom domain. Copy the origin (no trailing path).

Wire the policy into the gateway

Add the policy to config/policies.json:

Code
{ "name": "clerk-managed-oauth", "policyType": "mcp-clerk-oauth-inbound", "handler": { "module": "$import(@zuplo/runtime/mcp-gateway)", "export": "McpClerkOAuthInboundPolicy", "options": { "frontendApiUrl": "$env(CLERK_FRONTEND_API_URL)", "clientId": "$env(CLERK_CLIENT_ID)", "clientSecret": "$env(CLERK_CLIENT_SECRET)" } } }

frontendApiUrl is the origin only. Don't include a path, query string, or fragment — the policy fails at boot if any of those are present.

Set the three environment variables in your project's environment configuration. CLERK_FRONTEND_API_URL goes in plain config; the secret values belong in the project secret store.

Attach the policy to each MCP route in config/routes.oas.json:

Code
{ "paths": { "/mcp/linear-v1": { "get,post": { "operationId": "linear-mcp-server", "x-zuplo-route": { "corsPolicy": "none", "handler": { "module": "$import(@zuplo/runtime/mcp-gateway)", "export": "McpProxyHandler", "options": { "rewritePattern": "https://mcp.linear.app/mcp", }, }, "policies": { "inbound": ["clerk-managed-oauth", "mcp-token-exchange-linear"], }, }, }, }, }, }

Register the gateway plugin in modules/zuplo.runtime.ts:

Code
import { RuntimeExtensions } from "@zuplo/runtime"; import { McpGatewayPlugin } from "@zuplo/runtime/mcp-gateway"; export function runtimeInit(runtime: RuntimeExtensions) { runtime.addPlugin(new McpGatewayPlugin()); }

What the wrapper derives

Generic fieldDerived value
oidc.issuer{frontendApiUrl}
oidc.jwksUrl{frontendApiUrl}/.well-known/jwks.json
browserLogin.url{frontendApiUrl}/oauth/authorize
browserLogin.tokenUrl{frontendApiUrl}/oauth/token

Test the configuration

The fastest sanity check is to connect an MCP client:

  1. Open Claude Desktop, Cursor, Claude Code, or another OAuth-aware MCP client.
  2. Add a remote MCP server pointing at one of your /mcp/{slug} routes.
  3. The client should redirect you to Clerk's login page. After login, the gateway's consent screen renders. Approve it.
  4. The client receives an access token and can call tools/list.

If something fails partway through, walk the flow manually using the manual OAuth testing guide — it exercises every endpoint with curl so you can see the raw responses.

Common issues

  • The policy rejects frontendApiUrl at boot. The value includes a path, query string, or fragment. Use only the origin (https://clerk.example.com).
  • Browser login redirects but the callback fails. The https://<gateway-host>/oauth/callback URL isn't on the OAuth application's redirect URIs allow-list in Clerk.

Related

  • Authentication overview
  • Configuring a generic OIDC provider
  • Per-user OAuth to upstream MCP servers
Edit this page
Last modified on May 27, 2026
Amazon CognitoMicrosoft Entra
On this page
  • Set up Clerk
    • Create an OAuth application
    • Find the Frontend API URL
  • Wire the policy into the gateway
  • What the wrapper derives
  • Test the configuration
  • Common issues
  • Related
JSON
JSON
TypeScript