Skip to main content
Glama

Clerk MCP Server Template

by dyeoman2
README.md11.5 kB
# Clerk MCP Server Template A production-ready template for building Model Context Protocol (MCP) servers with Clerk authentication on Cloudflare Workers. This template provides everything you need to create secure, authenticated MCP tools that integrate with your existing Clerk-powered applications. ## Features - ✅ **Clerk Authentication Integration** - Complete OAuth 2.0 flow with Clerk - ✅ **Cloudflare Workers** - Serverless edge computing with global distribution - ✅ **Durable Objects** - Persistent MCP session state management - ✅ **KV Storage** - Temporary OAuth session storage - ✅ **Security** - HMAC-signed state parameters and automatic token refresh - ✅ **TypeScript** - Full type safety throughout the codebase - ✅ **Example Tools** - Ready-to-use example MCP tools - ✅ **Development Tools** - ESLint, Prettier, and MCP Inspector integration ## Why This Template? This template bridges your existing Clerk-authenticated application with Claude AI through MCP tools. Perfect for: - **SaaS Applications**: Give Claude access to your user data and business logic - **Customer Support**: Let Claude query your systems with proper user context - **Data Analysis**: Provide Claude with authenticated access to your APIs - **Workflow Automation**: Create secure, user-specific automations ## Quick Start ### 1. Prerequisites - Node.js 22.x or later - A [Clerk](https://clerk.com) account with API keys - A [Cloudflare](https://cloudflare.com) account with Workers enabled - An existing application using Clerk for authentication ### 2. Use This Template ```bash git clone https://github.com/your-username/clerk-mcp-template.git my-mcp-server cd my-mcp-server npm install ``` ### 3. Configure Environment Variables Copy the example environment file: ```bash cp .dev.vars.example .dev.vars ``` Update `.dev.vars` with your Clerk keys and app URL: ```env CLERK_SECRET_KEY=sk_test_your_actual_clerk_secret_key CLERK_PUBLISHABLE_KEY=pk_test_your_actual_clerk_publishable_key APP_URL=https://your-app.com ``` > **Important**: `APP_URL` should point to your existing Clerk-authenticated > application where you'll implement the MCP auth flow. ### 4. Create KV Namespace Create a KV namespace for OAuth session storage: ```bash wrangler kv:namespace create "OAUTH_KV" ``` Update the `id` in `wrangler.jsonc` with the generated namespace ID. ### 5. Update Configuration **`wrangler.jsonc`:** - Change `name` from `"your-mcp-server"` to your desired worker name - Update the KV namespace ID with the one generated above **`src/index.ts`:** - Update the server name and version in the `McpServer` constructor - Replace example tools with your own (see examples below) ### 6. Start Development ```bash npm run dev ``` The server will be available at `http://localhost:8788` ## Architecture ```mermaid graph TB A[MCP Client] --> B[Cloudflare Worker] B --> C[OAuth Provider] C --> D[Clerk Authentication] B --> E[Durable Objects] B --> F[KV Storage] B --> G[Your API] E --> H[MCP Session State] F --> I[OAuth Sessions] D --> J[User Authentication] G --> K[Your Application Data] ``` ## Authentication Flow 1. **MCP Client connects** to `/sse` endpoint 2. **OAuth redirect** to `/authorize` endpoint 3. **User authentication** via Clerk (you implement this part) 4. **Token exchange** at `/callback` endpoint 5. **Session creation** in Durable Objects 6. **MCP tools** become available with authenticated context ## Integrating with Your Application ### Step 1: Add MCP Authentication Route Create an authentication route in your existing Clerk application at `/auth/mcp`. This route handles the OAuth flow initiated by the MCP server. #### React Router v7 (Framework Mode) Example This example shows integration with React Router v7 in framework mode (formerly Remix), but you can adapt it to Next.js, Express, or any framework. **`app/routes/auth.mcp.tsx`:** ```typescript import { createClerkClient } from '@clerk/express' import { redirect, type LoaderFunctionArgs } from 'react-router' export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url) const state = url.searchParams.get('state') const callbackUrl = url.searchParams.get('callback_url') const clientName = url.searchParams.get('client_name') if (!state || !callbackUrl) { throw new Error('Missing required parameters') } // Get the authenticated user's session token const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY, publishableKey: process.env.CLERK_PUBLISHABLE_KEY, }) const clerkAuth = (await clerkClient.authenticateRequest(request)).toAuth() const sessionToken = await clerkAuth?.getToken() if (!sessionToken) { // Redirect to sign-in if not authenticated const signInUrl = new URL('/sign-in', request.url) signInUrl.searchParams.set('redirect_url', request.url) return redirect(signInUrl.toString()) } // Redirect back to MCP server with token const redirectUrl = new URL(callbackUrl) redirectUrl.searchParams.set('clerk_token', sessionToken) redirectUrl.searchParams.set('state', state) return redirect(redirectUrl.toString()) } // Optional: Add a component for showing consent screen export default function McpAuth() { return ( <div className="max-w-md mx-auto mt-8 p-6 bg-white rounded-lg shadow-md"> <h1 className="text-xl font-bold mb-4">Authorize MCP Access</h1> <p className="text-gray-600 mb-4"> Claude AI is requesting access to your account data. </p> <p className="text-sm text-gray-500"> This will redirect you automatically... </p> </div> ) } ``` ### Step 2: Create API Endpoints Add protected API endpoints in your application that the MCP server can call with authenticated requests. **`app/routes/api.users.tsx`:** ```typescript import { createClerkClient } from '@clerk/express' import { json, type LoaderFunctionArgs } from 'react-router' export async function loader({ request }: LoaderFunctionArgs) { try { const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY, publishableKey: process.env.CLERK_PUBLISHABLE_KEY, }) // Verify the request is authenticated const clerkAuth = await clerkClient.authenticateRequest(request) const userId = clerkAuth.toAuth()?.userId if (!userId) { return json({ error: 'Unauthorized' }, { status: 401 }) } // Your business logic here const users = await getUsersForCurrentUser(userId) return { users } } catch (error) { return json({ error: 'Internal server error' }, { status: 500 }) } } ``` ### Step 3: Customize MCP Tools Replace the example tools in `src/index.ts` with your own: ```typescript // Custom tool example this.server.tool( 'getUsers', 'Fetch all users from your application', {}, this.requireAuth(async () => { const users = await this.makeApiRequest('api/users') return { content: [ { type: 'text', text: `Found ${users.length} users:\n${JSON.stringify(users, null, 2)}`, }, ], } }), ) ``` ## Configuration Reference ### Environment Variables | Variable | Description | Required | | ----------------------- | -------------------------- | -------- | | `CLERK_SECRET_KEY` | Your Clerk secret key | ✅ | | `CLERK_PUBLISHABLE_KEY` | Your Clerk publishable key | ✅ | | `APP_URL` | Your application URL | ✅ | Add your own application-specific environment variables to the `Env` interface in `src/types.ts`. ### Clerk JWT Templates Create a JWT template in your Clerk Dashboard for token generation: 1. Go to **JWT Templates** in your Clerk Dashboard 2. Create a new template (e.g., "mcp-server") 3. Update the template name in `src/index.ts`: ```typescript const token = await getToken( // ... token manager (this as any).env.CLERK_SECRET_KEY, 'your-template-name', // Update this ) ``` ## Development ### Available Scripts ```bash npm run dev # Start development server npm run deploy # Deploy to Cloudflare Workers npm run inspect # Launch MCP Inspector npm run lint # Run ESLint + format npm run typecheck # Run TypeScript type checking npm run validate # Run typecheck + lint ``` ### Testing with MCP Inspector 1. Start the development server: `npm run dev` 2. Open [MCP Inspector](https://mcpinspector.com/) 3. Set transport type to **SSE** 4. Connect to `http://localhost:8788/sse` 5. Complete the authentication flow 6. Test your tools ## Deployment ### 1. Set Production Secrets ```bash wrangler secret put CLERK_SECRET_KEY wrangler secret put CLERK_PUBLISHABLE_KEY wrangler secret put APP_URL ``` ### 2. Create Production KV Namespace ```bash wrangler kv:namespace create "OAUTH_KV" --env production ``` Update the production KV namespace ID in `wrangler.jsonc`. ### 3. Deploy and Configure ```bash npm run deploy ``` Add your deployed server to Claude Desktop MCP configuration: ```json { "mcpServers": { "my-app": { "command": "npx", "args": [ "@modelcontextprotocol/server-remote", "https://your-mcp-server.your-subdomain.workers.dev/sse" ] } } } ``` ## Project Structure ``` clerk-mcp-template/ ├── src/ │ ├── index.ts # Main MCP server class and tools │ ├── auth.ts # OAuth authentication handlers │ ├── clerk.ts # Clerk authentication utilities │ ├── utils.ts # Utility functions (HMAC, logging, etc.) │ └── types.ts # TypeScript type definitions ├── wrangler.jsonc # Cloudflare Worker configuration ├── package.json # Dependencies and scripts ├── tsconfig.json # TypeScript configuration ├── eslint.config.js # ESLint configuration ├── .dev.vars # Development environment variables └── README.md # This file ``` ## Security Considerations - **OAuth 2.0** ensures secure authentication flow - **HMAC signatures** protect state parameters from tampering - **Automatic token refresh** handles session expiration - **Session cleanup** removes expired OAuth sessions - **Secure headers** include proper CORS and authentication headers ## Troubleshooting ### Common Issues **Authentication fails:** - Verify Clerk API keys are correct - Ensure your authentication route is implemented - Check that JWT template exists in Clerk Dashboard **KV namespace errors:** - Verify namespace ID in `wrangler.jsonc` - Ensure namespace is created and bound **Tools not working:** - Check that user is authenticated - Verify API endpoints are correct - Review Cloudflare Workers logs ### Debugging ```bash # View real-time logs wrangler tail # Check deployment status wrangler deployments list # Test locally with debugging npm run dev ``` ## Contributing 1. Fork this repository 2. Create a feature branch: `git checkout -b feature/amazing-feature` 3. Commit your changes: `git commit -m 'Add amazing feature'` 4. Push to the branch: `git push origin feature/amazing-feature` 5. Open a Pull Request ## Resources - [Model Context Protocol Specification](https://modelcontextprotocol.io/) - [Clerk Authentication Documentation](https://clerk.com/docs) - [Cloudflare Workers Documentation](https://developers.cloudflare.com/workers/) - [Cloudflare MCP Examples](https://github.com/cloudflare/ai/tree/main/demos) - [React Router v7 Documentation](https://reactrouter.com/home) ## License MIT License - see [LICENSE](LICENSE) file for details.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dyeoman2/clerk-mcp-template'

If you have feedback or need assistance with the MCP directory API, please join our Discord server