Skip to main content
Glama
dyeoman2

Clerk MCP Server Template

by dyeoman2
clerk.ts5.04 kB
import { createClerkClient, verifyToken } from '@clerk/backend' import { log } from './utils' interface ClerkSessionData { id: string userId: string expireAt: number } interface ClerkUserData { id: string email: string firstName: string lastName: string imageUrl: string | null } export async function verifyClerkToken( token: string, secretKey: string, ): Promise<ClerkSessionData> { try { const clerkClient = createClerkClient({ secretKey }) // Try JWT verification first (for session tokens) try { const payload = await verifyToken(token, { secretKey }) log.info('Successfully verified Clerk JWT token', { userId: payload.sub, sessionId: payload.sid, }) // Get the session using the session ID from the JWT const session = await clerkClient.sessions.getSession(payload.sid) return session } catch (jwtError) { log.warn('JWT verification failed, trying direct session lookup', { error: jwtError instanceof Error ? jwtError.message : String(jwtError), }) throw jwtError } } catch (error) { log.error('Error verifying Clerk token', { error: error instanceof Error ? error.message : String(error), }) throw new Error('Invalid authentication token') } } export async function getClerkUser( userId: string, secretKey: string, ): Promise<ClerkUserData> { try { const clerkClient = createClerkClient({ secretKey }) const user = await clerkClient.users.getUser(userId) return { id: userId, email: user.emailAddresses?.[0]?.emailAddress || 'unknown@example.com', firstName: user.firstName || 'Unknown', lastName: user.lastName || 'User', imageUrl: user.imageUrl || null, } } catch (error) { log.error('Error fetching Clerk user', { userId, error: error instanceof Error ? error.message : String(error), }) throw new Error('Failed to fetch user information') } } export async function refreshSessionToken( sessionId: string, secretKey: string, templateName: string = 'default', ): Promise<string> { const clerkClient = createClerkClient({ secretKey }) try { // First verify the session is still active const session = await clerkClient.sessions.getSession(sessionId) if (session.status !== 'active') { throw new Error(`Session is not active: ${session.status}`) } // Try to get a new token using the specified template let newToken: string | undefined try { const tokenResult = await clerkClient.sessions.getToken( sessionId, templateName, ) newToken = tokenResult.jwt log.info(`Successfully used template: ${templateName}`) } catch { log.info( `Template '${templateName}' not found, trying fallback templates...`, ) // Try common template names or create a basic token const fallbackTemplates = ['default', 'firebase', 'auth0', 'custom'] for (const template of fallbackTemplates) { try { const tokenResult = await clerkClient.sessions.getToken( sessionId, template, ) newToken = tokenResult.jwt log.info(`Successfully used fallback template: ${template}`) break } catch (e) { log.error('Error getting token', { template, error: e instanceof Error ? e.message : String(e), }) continue } } if (!newToken) { // If no templates work, the user needs to create one or we need a different approach throw new Error( `No valid JWT templates found. Please create a "${templateName}" template in Clerk Dashboard or use one of: ${fallbackTemplates.join(', ')}`, ) } } log.info('Successfully refreshed session token') return newToken } catch (error) { log.error('Token refresh failed', { error: error instanceof Error ? error.message : String(error), }) throw error } } export async function getToken( tokenManager: { sessionToken: string sessionId: string updateToken: (newToken: string) => void }, secretKey: string, templateName: string = 'default', ): Promise<string> { let token = tokenManager.sessionToken // Check if token is available if (!token) { throw new Error('No session token available') } // Check token expiration and refresh if needed try { const payload = JSON.parse(atob(token.split('.')[1] ?? '')) const expTime = payload.exp * 1000 // Convert to milliseconds const now = Date.now() if (expTime <= now) { log.info('Token has expired, attempting refresh...') token = await refreshSessionToken( tokenManager.sessionId, secretKey, templateName, ) tokenManager.updateToken(token) } else if (expTime - now < 5 * 60 * 1000) { log.info('Token expires soon, attempting refresh...') token = await refreshSessionToken( tokenManager.sessionId, secretKey, templateName, ) tokenManager.updateToken(token) } } catch (error) { log.warn('Could not parse token expiration', { error: error instanceof Error ? error.message : String(error), }) } log.info('Returning session token', { tokenPrefix: token?.substring(0, 20) + '...', }) return token }

Latest Blog Posts

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