### Install MCP Tools and Dependencies Source: https://github.com/clerk/mcp-tools/blob/main/next/README.md Install the necessary packages for MCP tools and Next.js integration. If using Clerk for authentication, also install the Clerk Next.js SDK. ```bash npm install @clerk/mcp-tools mcp-adapter next ``` ```bash npm install @clerk/nextjs ``` -------------------------------- ### Install MCP Tools and Dependencies Source: https://github.com/clerk/mcp-tools/blob/main/express/README.md Install the necessary packages for MCP tools, Express, and the Model Context Protocol SDK. If using Clerk, also install the Clerk Express SDK. ```bash npm install @clerk/mcp-tools express @modelcontextprotocol/sdk ``` ```bash npm install @clerk/express ``` -------------------------------- ### MCP Server: Core MCP Handler with Clerk Authentication Source: https://github.com/clerk/mcp-tools/blob/main/next/README.md Implements the core MCP handler for a Next.js server, integrating with Clerk authentication. This example defines a tool to fetch Clerk user data and uses `mcp-adapter` with Clerk's verification. ```typescript import { verifyClerkToken } from '@clerk/mcp-tools/next'; import { auth, clerkClient } from '@clerk/nextjs/server'; import { createMcpHandler, experimental_withMcpAuth as withMcpAuth } from 'mcp-adapter'; const clerk = await clerkClient(); const handler = createMcpHandler((server) => { server.tool( 'get-clerk-user-data', 'Gets data about the Clerk user that authorized this request', {}, // tool parameters here if present async (_, { authInfo }) => { // non-null assertion is safe here, authHandler ensures presence const userId = authInfo!.extra!.userId! as string; const userData = await clerk.users.getUser(userId); return { content: [{ type: 'text', text: JSON.stringify(userData) }], }; }, ); }); const authHandler = withMcpAuth( handler, async (_, token) => { const clerkAuth = await auth({ acceptsToken: 'oauth_token' }); // Note: OAuth tokens are machine tokens. Machine token usage is free // during our public beta period but will be subject to pricing once // generally available. Pricing is expected to be competitive and below // market averages. return verifyClerkToken(clerkAuth, token); }, { required: true, resourceMetadataPath: '/.well-known/oauth-protected-resource/mcp', }, ); export { authHandler as GET, authHandler as POST }; ``` -------------------------------- ### Get Client by Session ID Source: https://context7.com/clerk/mcp-tools/llms.txt Reconstructs an MCP client from a persisted session. Allows tool calls after the initial auth flow. Pass `state` for PKCE verification. Requires a store implementation. ```typescript import { getClientBySessionId } from '@clerk/mcp-tools/client'; import { createSqliteStore } from '@clerk/mcp-tools/stores/sqlite'; const store = createSqliteStore({ dbPath: './data/mcp.db' }); export async function callTool(sessionId: string, toolName: string, args: Record) { const { client, connect } = await getClientBySessionId({ sessionId, store }); // Re-connect using the stored tokens (no re-auth needed if token is valid) await connect(); const result = await client.callTool({ name: toolName, arguments: args }); // result.content contains the tool's response console.log('Tool result:', result.content); return result; } // Usage await callTool('550e8400-e29b-41d4-a716-446655440000', 'list_emails', { limit: 10 }); ``` -------------------------------- ### Initialize File System Store (Development) Source: https://github.com/clerk/mcp-tools/blob/main/README.md Use the file system store for local development and testing. It's fast and easy to set up but not recommended for production environments due to potential data loss. ```typescript import fsStore from '@clerk/mcp-tools/stores/fs'; ``` -------------------------------- ### Initialize Postgres Store (Production) Source: https://github.com/clerk/mcp-tools/blob/main/README.md Set up the Postgres store for production environments. Provide a valid DATABASE_URL connection string to your PostgreSQL database. ```typescript import { createPostgresStore } from '@clerk/mcp-tools/stores/postgres'; const store = createPostgresStore({ connectionString: process.env.DATABASE_URL, }); ``` -------------------------------- ### createFsStore — File System Store (Development) Source: https://context7.com/clerk/mcp-tools/llms.txt Persists session data to a local JSON file. Fast and zero-dependency for local development, but not suitable for production. ```APIDOC ## `createFsStore` — File System Store (Development) Persists session data to a local JSON file. Fast and zero-dependency for local development, but not suitable for production (data is not shared across processes and may be lost on restart). ### Usage ```typescript import { createFsStore } from '@clerk/mcp-tools/stores/fs'; const store = createFsStore({ filePath: './tmp/mcp-sessions.json', // defaults to os.tmpdir()/__mcp_demo }); // Use with any client function await store.write('my-key', { foo: 'bar' }); const value = await store.read('my-key'); // { foo: 'bar' } const deleted = await store.delete('my-key'); // true const allKeys = await store.keys(); // sorted by creation time const stats = await store.stats(); // { totalKeys, fileSize, filePath } ``` ``` -------------------------------- ### Initialize Redis Store (Production) Source: https://github.com/clerk/mcp-tools/blob/main/README.md Configure the Redis store for production use. Ensure your Redis server is accessible and the REDIS_URL environment variable is correctly set. ```typescript import { createRedisStore } from '@clerk/mcp-tools/stores/redis'; const store = createRedisStore({ url: process.env.REDIS_URL, }); ``` -------------------------------- ### Initialize SQLite Store (Production) Source: https://github.com/clerk/mcp-tools/blob/main/README.md Configure the SQLite store for production use. Specify the filename for the SQLite database file. ```typescript import { createSqliteStore } from '@clerk/mcp-tools/stores/sqlite'; const store = createSqliteStore({ filename: './mcp-sessions.db', }); ``` -------------------------------- ### Create Framework-Agnostic MCP Client Source: https://github.com/clerk/mcp-tools/blob/main/README.md Use this to create a core MCP client that can be integrated into any framework. Ensure you implement the redirect logic specific to your environment and provide a suitable store adapter. ```typescript import { createDynamicallyRegisteredMcpClient } from '@clerk/mcp-tools/client'; import { createRedisStore } from '@clerk/mcp-tools/stores/redis'; // Create a persistent store (use appropriate store for your environment) const store = createRedisStore({ url: process.env.REDIS_URL }); export async function initializeMCPConnection(mcpEndpoint: string) { const { connect, sessionId } = createDynamicallyRegisteredMcpClient({ mcpEndpoint, oauthScopes: 'openid profile email', oauthRedirectUrl: 'https://yourapp.com/oauth_callback', oauthClientUri: 'https://yourapp.com', mcpClientName: 'My App MCP Client', mcpClientVersion: '0.0.1', redirect: (url: string) => { // Implement redirect logic for your framework window.location.href = url; }, store, }); // Connect to the MCP endpoint await connect(); return { sessionId }; } ``` -------------------------------- ### createSqliteStore Source: https://context7.com/clerk/mcp-tools/llms.txt Creates a SQLite store for persisting session data. This store uses `better-sqlite3` and is ideal for single-server deployments or edge environments that support the filesystem. ```APIDOC ## `createSqliteStore` ### Description Initializes a persistent store using a local SQLite database file. This is suitable for single-server or edge environments where filesystem access is available. ### Usage ```typescript import { createSqliteStore } from '@clerk/mcp-tools/stores/sqlite'; const store = createSqliteStore({ dbPath: './data/mcp-sessions.db', tableName: 'sessions', enableWal: true, // WAL mode for better concurrent read performance enableForeignKeys: false, timeout: 5000, }); // Example operations: await store.write('sess-001', { authComplete: true, accessToken: 'tok_abc' }); const session = await store.read('sess-001'); const stats = await store.stats(); await store.cleanup(14); // remove sessions older than 14 days await store.disconnect(); // closes the SQLite file handle ``` ### Parameters - **`dbPath`** (string) - Required - The file path for the SQLite database. - **`tableName`** (string) - Required - The name of the table to use for storing sessions. - **`enableWal`** (boolean) - Optional - Enables Write-Ahead Logging (WAL) mode for improved concurrent read performance. Defaults to `true`. - **`enableForeignKeys`** (boolean) - Optional - Enables foreign key constraints. Defaults to `false`. - **`timeout`** (number) - Optional - The timeout in milliseconds for database operations. Defaults to `5000`. ### Methods - **`write(key: string, value: JsonSerializable): Promise`** Writes a key-value pair to the store. - **`read(key: string): Promise`** Reads the value associated with a given key from the store. - **`stats(): Promise<{ totalKeys: number; dbSize: string; dbPath: string }>`** Retrieves statistics about the database, including the total number of keys, database size, and file path. - **`cleanup(daysOlderThan: number): Promise`** Removes sessions older than the specified number of days. - **`disconnect(): Promise`** Closes the connection to the SQLite database file. ``` -------------------------------- ### Create File System Store Adapter Source: https://context7.com/clerk/mcp-tools/llms.txt Creates a file system store adapter for persisting session data to a local JSON file. This is suitable for local development due to its speed and zero-dependency nature, but not recommended for production environments as data is not shared across processes and may be lost on restart. ```typescript import { createFsStore } from '@clerk/mcp-tools/stores/fs'; const store = createFsStore({ filePath: './tmp/mcp-sessions.json', // defaults to os.tmpdir()/__mcp_demo }); // Use with any client function await store.write('my-key', { foo: 'bar' }); const value = await store.read('my-key'); // { foo: 'bar' } const deleted = await store.delete('my-key'); // true const allKeys = await store.keys(); // sorted by creation time const stats = await store.stats(); // { totalKeys, fileSize, filePath } ``` -------------------------------- ### Create SQLite Store for Session Persistence Source: https://context7.com/clerk/mcp-tools/llms.txt Use `createSqliteStore` to persist session data in a local SQLite database file. Ideal for single-server or edge environments with filesystem access. Configure WAL mode for better concurrency and set a timeout for database operations. ```typescript import { createSqliteStore } from '@clerk/mcp-tools/stores/sqlite'; const store = createSqliteStore({ dbPath: './data/mcp-sessions.db', tableName: 'sessions', enableWal: true, // WAL mode for better concurrent read performance enableForeignKeys: false, timeout: 5000, }); await store.write('sess-001', { authComplete: true, accessToken: 'tok_abc' }); const session = await store.read('sess-001'); // { authComplete: true, accessToken: "tok_abc" } const stats = await store.stats(); // { totalKeys: 5, dbSize: "12.34 KB", dbPath: "./data/mcp-sessions.db" } await store.cleanup(14); // remove sessions older than 14 days await store.disconnect(); // closes the SQLite file handle ``` -------------------------------- ### Create PostgreSQL Store Adapter Source: https://context7.com/clerk/mcp-tools/llms.txt Creates a PostgreSQL store adapter for persisting session data in a PostgreSQL table, utilizing JSONB for efficient storage. This adapter supports connection strings or individual configuration options and automatically creates the `mcp_store` table if it doesn't exist. ```typescript import { createPostgresStore } from '@clerk/mcp-tools/stores/postgres'; const store = createPostgresStore({ connectionString: process.env.DATABASE_URL, // Or use individual options: // host: 'db.example.com', port: 5432, database: 'myapp', user: 'app', password: '...', ssl: true, tableName: 'mcp_sessions', connectionTimeoutMillis: 5000, }); await store.write('session-xyz', { mcpEndpoint: 'https://example.com/mcp', clientId: 'cid_...' }); const data = await store.read('session-xyz'); const keys = await store.keys(); // ordered by created_at const stats = await store.stats(); // { totalKeys: 42, tableSize: "256 kB", dbInfo: "PostgreSQL 16.1" } await store.cleanup(7); // delete sessions older than 7 days await store.disconnect(); ``` -------------------------------- ### completeAuthWithCode Source: https://github.com/clerk/mcp-tools/blob/main/README.md Designed to be used in the OAuth callback route. Passing in the code, state, and your store will finish the auth process. ```APIDOC ## completeAuthWithCode ### Description Designed to be used in the OAuth callback route. Passing in the code, state, and your store will finish the auth process. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Arguments #### `code` (string) - Required The authorization code returned from the auth provider via querystring. See: https://datatracker.ietf.org/doc/html/rfc6749#section-4.1 #### `state` (string) - Required The state returned from the auth provider via querystring. See: https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1 #### `store` (McpClientStore) - Required A persistent store for auth data. See: https://github.com/clerk/mcp-tools?tab=readme-ov-file#stores ### Return Type ```typescript interface CompleteAuthWithCodeReturnType { transport: StreamableHTTPClientTransport; sessionId: string; } ``` ``` -------------------------------- ### Create Dynamically Registered MCP Client Source: https://context7.com/clerk/mcp-tools/llms.txt Use this function to create an MCP client that automatically registers itself with the authorization server on first use. This is recommended when you don't have pre-existing OAuth credentials. Ensure you have a session store adapter configured. ```typescript import { createDynamicallyRegisteredMcpClient } from '@clerk/mcp-tools/client'; import { createRedisStore } from '@clerk/mcp-tools/stores/redis'; const store = createRedisStore({ url: process.env.REDIS_URL }); // Called when the user initiates an MCP connection (e.g., submits a form with the MCP endpoint) export async function initiateMcpConnection(mcpEndpoint: string) { const { connect, sessionId } = await createDynamicallyRegisteredMcpClient({ mcpEndpoint, oauthRedirectUrl: 'https://myapp.com/oauth/callback', oauthClientName: 'My App', oauthClientUri: 'https://myapp.com', oauthScopes: 'openid profile email', oauthPublicClient: false, mcpClientName: 'my-app-mcp-client', mcpClientVersion: '1.0.0', redirect: (url: string) => { // Framework-specific redirect — in Next.js use redirect(), in Express use res.redirect() window.location.href = url; }, store, }); // Triggers dynamic registration + redirects user to the authorization server await connect(); // Persist the sessionId so it can be retrieved in the OAuth callback return { sessionId }; } ``` -------------------------------- ### createKnownCredentialsMcpClient Source: https://github.com/clerk/mcp-tools/blob/main/README.md Creates an MCP client using pre-existing OAuth client credentials. This method is recommended when dynamic client registration is not desired, but it may increase user friction. ```APIDOC ## createKnownCredentialsMcpClient ### Description If dynamic client registration is not desirable, and your interface can collect a client id and secret from an existing OAuth client, you can create a MCP client with this function. Though it does increase friction in the user experience, we recommend allowing MCP services that do not enable dynamic client registration, since it comes with several security/fraud risks that not every provider wants to take on. ### Parameters #### Arguments - **clientId** (string) - Required - OAuth client id, expected to be collected via user input - **clientSecret** (string) - Required - OAuth client secret, expected to be collected via user input - **oauthRedirectUrl** (string) - Required - OAuth redirect URL - after the user consents, this route will get back the authorization code and state. - **oauthScopes** (string) - Optional - OAuth scopes that you'd like to request access to - **mcpEndpoint** (string) - Required - The endpoint of the MCP service, expected to be collected via user input - **mcpClientName** (string) - Required - Name passed to the client created by the MCP SDK - **mcpClientVersion** (string) - Required - Version number passed to the client created by the MCP SDK - **redirect** (function) - Required - A function that, when called with a url, will redirect to the given url - **store** (McpClientStore) - Required - A persistent store for auth data ### Return Type - **sessionId** (string) - Represents a session associated with the connected MCP service endpoint. - **connect** (function) - Calling this function will initialize a connect to the MCP service. - **transport** (StreamableHTTPClientTransport) - Lower level primitive, likely not necessary for use - **client** (Client) - Lower level primitive, likely not necessary for use - **authProvider** (OAuthClientProvider) - Lower level primitive, likely not necessary for use ``` -------------------------------- ### Generate Authorization Server Metadata with Custom Endpoints Source: https://github.com/clerk/mcp-tools/blob/main/README.md Generate authorization server metadata with custom endpoint configurations. Pass `false` for endpoints not supported by your authorization server, such as dynamic client registration. ```typescript // return this result from /.well-known/oauth-authorization-server import { generateAuthorizationServerMetadata } from '@clerk/mcp-tools/server'; const result = generateAuthorizationServerMetadata({ authServerUrl: 'https://auth.example.com', authorizationEndpoint: 'foo/bar/authorize', registrationEndpoint: false, tokenEndpoint: 'tokens', scopes: ['email', 'profile', 'openid', 'foobar'], }); ``` -------------------------------- ### fetchClerkAuthorizationServerMetadata Source: https://github.com/clerk/mcp-tools/blob/main/README.md Fetches OAuth 2.0 Authorization Server Metadata from Clerk's servers based on your publishable key. This returns the actual metadata from Clerk's authorization server rather than generating it locally. ```APIDOC ## fetchClerkAuthorizationServerMetadata ### Description Fetches OAuth 2.0 Authorization Server Metadata from Clerk's servers based on your publishable key. This returns the actual metadata from Clerk's authorization server rather than generating it locally. ### Arguments ```ts interface FetchClerkAuthorizationServerMetadataParams { /** * Your Clerk publishable key (e.g., pk_test_... or pk_live_...) */ publishableKey: string; } ``` ### Return Type ```ts Promise<{ issuer: string; authorization_endpoint: string; token_endpoint: string; userinfo_endpoint: string; jwks_uri: string; registration_endpoint?: string; scopes_supported: string[]; response_types_supported: string[]; response_modes_supported: string[]; grant_types_supported: string[]; subject_types_supported: string[]; id_token_signing_alg_values_supported: string[]; token_endpoint_auth_methods_supported: string[]; claims_supported: string[]; code_challenge_methods_supported: string[]; [key: string]: any; // Additional metadata from Clerk }>; ``` ``` -------------------------------- ### Custom MCP Client Store Interface Source: https://github.com/clerk/mcp-tools/blob/main/README.md Define your own store implementation by adhering to this interface. Only the `write` and `read` methods are strictly required for basic functionality. ```typescript type JsonSerializable = | null | boolean | number | string | JsonSerializable[] | { [key: string]: JsonSerializable }; interface McpClientStore { write: (key: string, data: JsonSerializable) => Promise; read: (key: string) => Promise; } ``` -------------------------------- ### Create Redis Store Adapter Source: https://context7.com/clerk/mcp-tools/llms.txt Creates a Redis store adapter for persisting session data in Redis, with support for optional TTL-based expiry. This adapter is ideal for distributed or serverless deployments, offering features like TLS, custom key prefixes, and connection pooling. ```typescript import { createRedisStore } from '@clerk/mcp-tools/stores/redis'; const store = createRedisStore({ host: 'redis.example.com', port: 6379, password: process.env.REDIS_PASSWORD, db: 0, keyPrefix: 'myapp:mcp:', ttl: 86400, // 24 hours; omit for no expiry tls: true, connectTimeout: 5000, }); await store.write('session-abc', { userId: 'user_123', accessToken: 'tok_...' }); const session = await store.read('session-abc'); const exists = await store.exists('session-abc'); // true // Maintenance helpers const deleted = await store.cleanup(30); // delete entries older than 30 days const stats = await store.stats(); // { totalKeys, memoryUsage, redisInfo } await store.disconnect(); ``` -------------------------------- ### Serve Clerk Authorization Server Metadata Source: https://github.com/clerk/mcp-tools/blob/main/express/README.md Use `authServerMetadataHandlerClerk` to serve OAuth authorization server metadata for Clerk. This handler requires `CLERK_PUBLISHABLE_KEY` to be set. ```typescript import { authServerMetadataHandlerClerk } from '@clerk/mcp-tools/express'; // Serve authorization server metadata at the standard well-known location app.get('/.well-known/oauth-authorization-server', authServerMetadataHandlerClerk); ``` -------------------------------- ### Fetch Clerk Authorization Server Metadata Source: https://github.com/clerk/mcp-tools/blob/main/README.md Fetches OAuth 2.0 Authorization Server Metadata directly from Clerk's servers using your publishable key. This retrieves the live metadata instead of generating it locally. ```typescript interface FetchClerkAuthorizationServerMetadataParams { /** * Your Clerk publishable key (e.g., pk_test_... or pk_live_...) */ publishableKey: string; } ``` ```typescript Promise<{ issuer: string; authorization_endpoint: string; token_endpoint: string; userinfo_endpoint: string; jwks_uri: string; registration_endpoint?: string; scopes_supported: string[]; response_types_supported: string[]; response_modes_supported: string[]; grant_types_supported: string[]; subject_types_supported: string[]; id_token_signing_alg_values_supported: string[]; token_endpoint_auth_methods_supported: string[]; claims_supported: string[]; code_challenge_methods_supported: string[]; [key: string]: any; // Additional metadata from Clerk }>; ``` -------------------------------- ### MCP Client: Generic Protected Resource Metadata Handler Source: https://github.com/clerk/mcp-tools/blob/main/next/README.md Provides a generic Next.js route handler for OAuth protected resource metadata. Use this when integrating with any OAuth authorization server. ```typescript import { protectedResourceHandler } from '@clerk/mcp-tools/next'; const handler = protectedResourceHandler({ authServerUrl: 'https://auth.example.com', }); export { handler as GET }; ``` -------------------------------- ### authServerMetadataHandlerClerk (Next.js) Source: https://context7.com/clerk/mcp-tools/llms.txt A Next.js route handler factory that proxies Clerk's live RFC 8414 Authorization Server Metadata with proper CORS headers, serving it from your app's `/.well-known/oauth-authorization-server` endpoint. ```APIDOC ## `authServerMetadataHandlerClerk` (Next.js) A Next.js route handler factory that proxies Clerk's live RFC 8414 Authorization Server Metadata with proper CORS headers, serving it from your app's `/.well-known/oauth-authorization-server` endpoint. ### Usage ```typescript // app/.well-known/oauth-authorization-server/route.ts import { authServerMetadataHandlerClerk, metadataCorsOptionsRequestHandler } from '@clerk/mcp-tools/next'; export const GET = authServerMetadataHandlerClerk(); export const OPTIONS = metadataCorsOptionsRequestHandler(); ``` ``` -------------------------------- ### createPostgresStore — PostgreSQL Store (Production) Source: https://context7.com/clerk/mcp-tools/llms.txt Persists session data in a PostgreSQL table (auto-created as `mcp_store` by default) using JSONB for efficient storage. Supports connection strings or individual config options. ```APIDOC ## `createPostgresStore` — PostgreSQL Store (Production) Persists session data in a PostgreSQL table (auto-created as `mcp_store` by default) using JSONB for efficient storage. Supports connection strings or individual config options. ### Usage ```typescript import { createPostgresStore } from '@clerk/mcp-tools/stores/postgres'; const store = createPostgresStore({ connectionString: process.env.DATABASE_URL, // Or use individual options: // host: 'db.example.com', port: 5432, database: 'myapp', user: 'app', password: '...', ssl: true, tableName: 'mcp_sessions', connectionTimeoutMillis: 5000, }); await store.write('session-xyz', { mcpEndpoint: 'https://example.com/mcp', clientId: 'cid_...' }); const data = await store.read('session-xyz'); const keys = await store.keys(); // ordered by created_at const stats = await store.stats(); // { totalKeys: 42, tableSize: "256 kB", dbInfo: "PostgreSQL 16.1" } await store.cleanup(7); // delete sessions older than 7 days await store.disconnect(); ``` ``` -------------------------------- ### createDynamicallyRegisteredMcpClient Source: https://github.com/clerk/mcp-tools/blob/main/README.md Creates a new MCP client by dynamically registering an OAuth client with the authorization server on-demand. This method is suitable when an OAuth client does not already exist. ```APIDOC ## createDynamicallyRegisteredMcpClient ### Description Creates a new MCP client given only an MCP endpoint url. Registers an OAuth client with the authorization server on-demand via [OAuth 2.0 Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591). ### Parameters #### Arguments - **mcpEndpoint** (string) - Required - The endpoint of the MCP service, expected to be collected via user input - **oauthRedirectUrl** (string) - Required - OAuth redirect URL - after the user consents, this route will get back the authorization code and state. - **oauthClientName** (string) - Optional - The name of the OAuth client to be created with the authorization server - **oauthClientUri** (string) - Optional - The URI of the OAuth client to be created with the authorization server - **oauthScopes** (string) - Optional - OAuth scopes that you'd like to request access to - **oauthPublicClient** (boolean) - Optional - Whether the OAuth client is public or confidential - **mcpClientName** (string) - Required - Name passed to the client created by the MCP SDK - **mcpClientVersion** (string) - Required - Version number passed to the client created by the MCP SDK - **redirect** (function) - Required - A function that, when called with a url, will redirect to the given url - **store** (McpClientStore) - Required - A persistent store for auth data ``` -------------------------------- ### Create MCP Client with Known Credentials Source: https://github.com/clerk/mcp-tools/blob/main/README.md Use this function when dynamic client registration is not desired and you can collect an existing OAuth client ID and secret. This method is recommended for MCP services that do not support dynamic client registration due to potential security and fraud risks. ```typescript interface CreateKnownCredentialsMcpClientParams { /** * OAuth client id, expected to be collected via user input */ clientId: string; /** * OAuth client secret, expected to be collected via user input */ clientSecret: string; /** * OAuth redirect URL - after the user consents, this route will get * back the authorization code and state. */ oauthRedirectUrl: string; /** * OAuth scopes that you'd like to request access to */ oauthScopes?: string; /** * The endpoint of the MCP service, expected to be collected via user input */ mcpEndpoint: string; /** * Name passed to the client created by the MCP SDK * @see https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#writing-mcp-clients */ mcpClientName: string; /** * Version number passed to the client created by the MCP SDK * @see https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#writing-mcp-clients */ mcpClientVersion: string; /** * A function that, when called with a url, will redirect to the given url */ redirect: (url: string) => void; /** * A persistent store for auth data * @see https://github.com/clerk/mcp-tools?tab=readme-ov-file#stores */ store: McpClientStore; } ``` ```typescript interface McpClientReturnType { /** * Represents a session associated with the connected MCP service endpoint. */ sessionId: string; /** * Calling this function will initialize a connect to the MCP service. */ connect: () => void; /** * Lower level primitive, likely not necessary for use * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/streamableHttp.ts#L119 */ transport: StreamableHTTPClientTransport; /** * Lower level primitive, likely not necessary for use * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/index.ts#L81 */ client: Client; /** * Lower level primitive, likely not necessary for use * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/auth.ts#L13 */ authProvider: OAuthClientProvider; } ``` -------------------------------- ### completeOAuthHandler (Next.js) Source: https://context7.com/clerk/mcp-tools/llms.txt A Next.js route handler factory for the OAuth callback endpoint. Parses `code` and `state` from the query string, completes the token exchange, and invokes a callback function on success. ```APIDOC ## `completeOAuthHandler` (Next.js) A Next.js route handler factory for the OAuth callback endpoint. Parses `code` and `state` from the query string, completes the token exchange, and invokes a callback function on success. ### Usage ```typescript // app/oauth/callback/route.ts import { completeOAuthHandler } from '@clerk/mcp-tools/next'; import { createRedisStore } from '@clerk/mcp-tools/stores/redis'; import { redirect } from 'next/navigation'; const store = createRedisStore({ url: process.env.REDIS_URL! }); export const GET = completeOAuthHandler({ store, callback: ({ sessionId }) => { // Called after tokens are successfully stored // Redirect the user back to the page that initiated the MCP connection redirect(`/dashboard?mcp_session=${sessionId}`); }, }); ``` ``` -------------------------------- ### Create MCP Client with Known Credentials Source: https://context7.com/clerk/mcp-tools/llms.txt Use this function to create an MCP client with pre-existing OAuth client ID and secret, bypassing dynamic registration. This is suitable when the MCP server does not support dynamic client registration. A session store adapter is required. ```typescript import { createKnownCredentialsMcpClient } from '@clerk/mcp-tools/client'; import { createPostgresStore } from '@clerk/mcp-tools/stores/postgres'; const store = createPostgresStore({ connectionString: process.env.DATABASE_URL, tableName: 'mcp_sessions', }); export async function initiateWithKnownCredentials( mcpEndpoint: string, clientId: string, clientSecret: string, ) { const { connect, sessionId } = await createKnownCredentialsMcpClient({ clientId, clientSecret, mcpEndpoint, oauthRedirectUrl: 'https://myapp.com/oauth/callback', oauthScopes: 'openid profile email', mcpClientName: 'my-app-mcp-client', mcpClientVersion: '1.0.0', redirect: (url: string) => { // Redirect user to the authorization server window.location.href = url; }, store, }); await connect(); return { sessionId }; } ``` -------------------------------- ### Generate Standard Authorization Server Metadata Source: https://github.com/clerk/mcp-tools/blob/main/README.md Use this to generate standard authorization server metadata. It assumes default endpoints for authorization, registration, token, userinfo, and JWKS. ```typescript // return this result from /.well-known/oauth-authorization-server import { generateAuthorizationServerMetadata } from '@clerk/mcp-tools/server'; const result = generateAuthorizationServerMetadata({ authServerUrl: 'https://auth.example.com', scopes: ['email', 'profile', 'openid'], }); ``` -------------------------------- ### createKnownCredentialsMcpClient Source: https://context7.com/clerk/mcp-tools/llms.txt Creates an MCP client using pre-existing OAuth client ID and secret, bypassing dynamic registration. Use this when the MCP server does not support dynamic registration and credentials are provided manually. ```APIDOC ## Client API — `@clerk/mcp-tools/client` ### `createKnownCredentialsMcpClient` Creates an MCP client using a pre-existing OAuth `client_id` and `client_secret`, skipping dynamic registration. Use this when the MCP server does not support dynamic client registration and the user provides credentials manually. ```typescript import { createKnownCredentialsMcpClient } from '@clerk/mcp-tools/client'; import { createPostgresStore } from '@clerk/mcp-tools/stores/postgres'; const store = createPostgresStore({ connectionString: process.env.DATABASE_URL, tableName: 'mcp_sessions', }); export async function initiateWithKnownCredentials( mcpEndpoint: string, clientId: string, clientSecret: string, ) { const { connect, sessionId } = await createKnownCredentialsMcpClient({ clientId, clientSecret, mcpEndpoint, oauthRedirectUrl: 'https://myapp.com/oauth/callback', oauthScopes: 'openid profile email', mcpClientName: 'my-app-mcp-client', mcpClientVersion: '1.0.0', redirect: (url: string) => { // Redirect user to the authorization server window.location.href = url; }, store, }); await connect(); return { sessionId }; } ``` ``` -------------------------------- ### Next.js Adapter: Protected Resource Handler with Clerk Source: https://context7.com/clerk/mcp-tools/llms.txt A Next.js route handler factory for /.well-known/oauth-protected-resource, automatically configured for Clerk using NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY. Includes proper CORS and cache headers. ```typescript // app/.well-known/oauth-protected-resource/route.ts import { protectedResourceHandlerClerk, metadataCorsOptionsRequestHandler } from '@clerk/mcp-tools/next'; export const GET = protectedResourceHandlerClerk({ service_documentation: 'https://myapp.com/docs', }); export const OPTIONS = metadataCorsOptionsRequestHandler(); ``` -------------------------------- ### Create MCP Client with Dynamic Registration Source: https://github.com/clerk/mcp-tools/blob/main/README.md This function creates a new MCP client by registering an OAuth client with the authorization server on-demand using the OAuth 2.0 Dynamic Client Registration Protocol. It requires only the MCP endpoint URL. ```typescript interface CreateDynamicallyRegisteredMcpClientParams { /** * The endpoint of the MCP service, expected to be collected via user input */ mcpEndpoint: string; /** * OAuth redirect URL - after the user consents, this route will get * back the authorization code and state. */ oauthRedirectUrl: string; /** * The name of the OAuth client to be created with the authorization server */ oauthClientName?: string; /** * The URI of the OAuth client to be created with the authorization server */ oauthClientUri?: string; /** * OAuth scopes that you'd like to request access to */ oauthScopes?: string; /** * Whether the OAuth client is public or confidential * @see https://datatracker.ietf.org/doc/html/rfc6749#section-2.1 */ oauthPublicClient?: boolean; /** * Name passed to the client created by the MCP SDK * @see https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#writing-mcp-clients */ mcpClientName: string; /** * Version number passed to the client created by the MCP SDK * @see https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#writing-mcp-clients */ mcpClientVersion: string; /** * A function that, when called with a url, will redirect to the given url */ redirect: (url: string) => void; /** * A persistent store for auth data * @see https://github.com/clerk/mcp-tools?tab=readme-ov-file#stores */ store: McpClientStore; } ``` -------------------------------- ### Make MCP Tool Calls Source: https://github.com/clerk/mcp-tools/blob/main/README.md Once authenticated, use this function to retrieve an MCP client by session ID and invoke a specific tool. Ensure the store is accessible and the session ID is valid. ```typescript import { getClientBySessionId } from '@clerk/mcp-tools/client'; export async function callMCPTool(sessionId: string, toolName: string, args: any) { const { client, connect } = getClientBySessionId({ sessionId, store, }); await connect(); const toolResponse = await client.callTool({ name: toolName, arguments: args, }); return toolResponse; } ``` -------------------------------- ### createRedisStore — Redis Store (Production) Source: https://context7.com/clerk/mcp-tools/llms.txt Persists session data in Redis with optional TTL-based expiry. Supports TLS, custom key prefixes, and connection pooling. Best for distributed/serverless deployments. ```APIDOC ## `createRedisStore` — Redis Store (Production) Persists session data in Redis with optional TTL-based expiry. Supports TLS, custom key prefixes, and connection pooling. Best for distributed/serverless deployments. ### Usage ```typescript import { createRedisStore } from '@clerk/mcp-tools/stores/redis'; const store = createRedisStore({ host: 'redis.example.com', port: 6379, password: process.env.REDIS_PASSWORD, db: 0, keyPrefix: 'myapp:mcp:', ttl: 86400, // 24 hours; omit for no expiry tls: true, connectTimeout: 5000, }); await store.write('session-abc', { userId: 'user_123', accessToken: 'tok_...' }); const session = await store.read('session-abc'); const exists = await store.exists('session-abc'); // true // Maintenance helpers const deleted = await store.cleanup(30); // delete entries older than 30 days const stats = await store.stats(); // { totalKeys, memoryUsage, redisInfo } await store.disconnect(); ``` ``` -------------------------------- ### Configure Clerk Authentication Middleware for Express Source: https://github.com/clerk/mcp-tools/blob/main/express/README.md Use `mcpAuthClerk` for pre-configured OAuth token verification. It automatically handles authentication state and adds Clerk auth data to `req.auth`. ```typescript import { mcpAuthClerk, streamableHttpHandler } from '@clerk/mcp-tools/express'; // No additional configuration needed - uses Clerk's built-in token verification app.post('/mcp', mcpAuthClerk, streamableHttpHandler(server)); ``` -------------------------------- ### protectedResourceHandlerClerk (Next.js) Source: https://context7.com/clerk/mcp-tools/llms.txt A Next.js route handler factory for `/.well-known/oauth-protected-resource`, automatically configured for Clerk. ```APIDOC ## protectedResourceHandlerClerk (Next.js) ### Description A Next.js route handler factory for `/.well-known/oauth-protected-resource`, automatically configured for Clerk using `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`. Includes proper CORS and cache headers. ### Method GET, OPTIONS ### Endpoint `app/.well-known/oauth-protected-resource/route.ts` (Next.js route handler) ### Parameters #### Path Parameters None. #### Query Parameters None. #### Request Body None. ### Request Example ```typescript // app/.well-known/oauth-protected-resource/route.ts import { protectedResourceHandlerClerk, metadataCorsOptionsRequestHandler } from '@clerk/mcp-tools/next'; export const GET = protectedResourceHandlerClerk({ service_documentation: 'https://myapp.com/docs', }); export const OPTIONS = metadataCorsOptionsRequestHandler(); ``` ### Response #### Success Response (200) Returns resource metadata, including CORS and cache headers. ``` -------------------------------- ### Proxy Clerk's Auth Server Metadata with CORS (Next.js) Source: https://context7.com/clerk/mcp-tools/llms.txt Use this factory to create a Next.js route handler that proxies Clerk's RFC 8414 Authorization Server Metadata. It ensures proper CORS headers are included when serving from your app's `/.well-known/oauth-authorization-server` endpoint. ```typescript import { authServerMetadataHandlerClerk, metadataCorsOptionsRequestHandler } from '@clerk/mcp-tools/next'; export const GET = authServerMetadataHandlerClerk(); export const OPTIONS = metadataCorsOptionsRequestHandler(); ``` -------------------------------- ### getClientBySessionId Source: https://github.com/clerk/mcp-tools/blob/main/README.md Given an existing session id, constructs an MCP client that matches the information used to create the client/session initially. Intended to be used in OAuth callback routes and any subsequent MCP calls once the service has been initialized. ```APIDOC ## getClientBySessionId ### Description Given an existing session id, constructs an MCP client that matches the information used to create the client/session initially. Intended to be used in OAuth callback routes and any subsequent MCP calls once the service has been initialized. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Arguments #### `sessionId` (string) - Required The session id to retrieve the client details for. #### `store` (McpClientStore) - Required A persistent store for auth data. See: https://github.com/clerk/mcp-tools?tab=readme-ov-file#stores #### `state` (string) - Optional If using this function in the OAuth callback route, pass in the state to ensure that PKCE can run correctly. ### Return Type ```typescript interface McpClientReturnType { sessionId: string; connect: () => void; transport: StreamableHTTPClientTransport; client: Client; authProvider: OAuthClientProvider; } ``` ``` -------------------------------- ### Express.js Adapter: Streamable HTTP Handler with Clerk Auth Source: https://context7.com/clerk/mcp-tools/llms.txt Wires an MCP McpServer instance to the Streamable HTTP transport for an Express route, handling all MCP protocol communication. It includes Clerk authentication middleware and exposes protected resource metadata. ```typescript import express from 'express'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { streamableHttpHandler, mcpAuthClerk, protectedResourceHandlerClerk } from '@clerk/mcp-tools/express'; const app = express(); app.use(express.json()); // 1. Expose protected resource metadata app.get('/.well-known/oauth-protected-resource', protectedResourceHandlerClerk()); // 2. Define the MCP server with tools const server = new McpServer({ name: 'my-gmail-server', version: '1.0.0' }); server.tool('list_emails', { limit: z.number().optional() }, async ({ limit = 10 }, { authInfo }) => { // authInfo.extra.userId is the authenticated Clerk user const emails = await fetchEmailsForUser(authInfo!.extra!.userId as string, limit); return { content: [{ type: 'text', text: JSON.stringify(emails) }] }; }); // 3. Mount MCP endpoint with Clerk auth middleware app.all('/mcp', mcpAuthClerk, streamableHttpHandler(server)); app.listen(3000, () => console.log('MCP server running on port 3000')); ``` -------------------------------- ### Create Generic Protected Resource Metadata Handler Source: https://github.com/clerk/mcp-tools/blob/main/express/README.md Implement `protectedResourceHandler` to return OAuth protected resource metadata for any OAuth authorization server. Configure with `authServerUrl` and optional `properties`. ```typescript import { protectedResourceHandler } from '@clerk/mcp-tools/express'; app.get( '/.well-known/oauth-protected-resource', protectedResourceHandler({ authServerUrl: 'https://auth.example.com', properties: { service_documentation: 'https://example.com/docs', custom_property: 'custom_value', }, }), ); ``` -------------------------------- ### Express App with Clerk Authentication Source: https://github.com/clerk/mcp-tools/blob/main/express/README.md Sets up an Express application with Clerk authentication middleware and MCP server integration. Includes handlers for protected resources and MCP POST requests. ```ts import 'dotenv/config'; import express from 'express'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { createClerkClient, MachineAuthObject, clerkMiddleware } from '@clerk/express'; import { mcpAuthClerk, protectedResourceHandlerClerk, authServerMetadataHandlerClerk, streamableHttpHandler, } from '@clerk/mcp-tools/express'; const app = express(); app.use(clerkMiddleware()); app.use(express.json()); const server = new McpServer({ name: 'clerk-mcp-server', version: '1.0.0', }); const clerk = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY! }); server.tool( 'get_clerk_user_data', 'Gets data about the Clerk user that authorized this request', {}, async (_, { authInfo }) => { const clerkAuthInfo = authInfo as unknown as MachineAuthObject<'oauth_token'>; if (!clerkAuthInfo?.userId) { return { content: [{ type: 'text', text: 'Error: user not authenticated' }], }; } const user = await clerk.users.getUser(clerkAuthInfo.userId); return { content: [{ type: 'text', text: JSON.stringify(user) }], }; }, ); app.get('/.well-known/oauth-protected-resource', protectedResourceHandlerClerk()); app.get( '/.well-known/oauth-protected-resource/mcp', protectedResourceHandlerClerk({ scopes_supported: ['profile', 'email'], }), ); app.get('/.well-known/oauth-authorization-server', authServerMetadataHandlerClerk); app.post('/mcp', mcpAuthClerk, streamableHttpHandler(server)); app.listen(3000); ``` -------------------------------- ### Custom Authentication Handler for Next.js Source: https://github.com/clerk/mcp-tools/blob/main/next/README.md When using a custom authentication system in Next.js, utilize this generic protected resource handler. You must provide the URL of your authentication server. ```typescript // app/.well-known/oauth-protected-resource/route.ts import { protectedResourceHandler } from '@clerk/mcp-tools/next'; const handler = protectedResourceHandler({ authServerUrl: 'https://your-auth-server.com', }); export { handler as GET }; ```