MCP Tools
A library built on top of the MCP TypeScript SDK that makes it easier to implement MCP with auth into your MCP client and/or server.
What is MCP?
It's a protocol that enables AI applications like Claude, ChatGPT, Cursor, etc to ask you for permission to access some of your private information that normally you'd need to sign in with your account to access. For example, your emails, or your private github repositories, etc.
This allows you to provide AI applications with context and abilities that it would normally not have access to. You could, for example, have an AI application use some code in a private repo as context to answer your questions, or have it write and send an email on your behalf, after you review it. It's kind of like this:

We think this is valuable because it enables people to use AI to access a bunch of extra information that it wasn't able to access before, and does so in a safe way where you as the user are in control over what it has access to and what it can do. We're excited to see what new AI use cases become possible as MCP adoption grows, and we built this library to try to help make it easier for people to integrate MCP into their applications.
Client vs Server usage
There are two parties involved in MCP:
- The client, which is the one that wants to get access to another service. In the above example would be Claude, which wants to get access to Gmail.
- The server, which is the one that has something that a client wants access to. In the above example, this would be Gmail. This is sometimes referred to as the "resource server" or "MCP server".
This library has tools for both of these parties, so step one is to be clear on whether you are building a client or server. We'll address each of these use cases separately.
NOTE: In web development, the terms "client" and "server" are often used to refer to the frontend (browser) and backend (web server). This is not the case in this situation, so try not to confuse them!
Framework-Specific Documentation
For detailed implementation guides and examples specific to your framework, see:
Table of Contents
Guide: building a server
If you are building a server that you'd like to introduce MCP support for, you will want to use the @clerk/mcp-tools/server
import path.
Protected resource metadata
In order for the most up to date authentication flow in the MCP spec to work correctly, your server will need to expose a static metadata file called "protected resource metadata", which is defined by RFC 9728.
This library exposes a tool that can quickly generate such a metadata file for you. Here's an example of how to use it:
import { generateProtectedResourceMetadata } from "@clerk/mcp-tools/server";
const result = generateProtectedResourceMetadata({
resourceUrl: "https://myapp.com/current-route",
authServerUrl: "https://auth.example.com",
});
You will want to set up a route at .well-known/oauth-protected-resource
and make sure to return this result from that route on your server.
If you are using Clerk for authentication in your app, we have a helper that makes this easier:
import { generateClerkProtectedResourceMetadata } from "@clerk/mcp-tools/server";
const result = generateClerkProtectedResourceMetadata({
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
resourceUrl: "https://myapp.com/current-route",
});
For framework-specific implementations of protected resource metadata handlers, see:
Authorization server metadata
NOTE: This is not yet fully implemented
There is an older version of the MCP spec that specified that the MCP server should be responsible for authentication on its own and instead it should implement a different static metadata file called "authorization server metadata", defined by RFC 8414. While it should not be necessary as long as you have implemented protected resource metadata and are using an authorization service that has properly implemented a authorization server metadata route, there are some scenarios where this might be necessary if you are building your own authorization server, if your authorization server is part of your app directly, or if you are interfacing with a client that has an outdated implementation. This library also provides utilities for this use case.
import { generateAuthorizationServerMetadata } from "@clerk/mcp-tools/server";
const result = generateAuthorizationServerMetadata({
authServerUrl: "https://auth.example.com",
scopes: ["email", "profile", "openid"],
});
In the most standard case, the above example will work, but it does make some assumptions about the authorization server, namely that:
- The authorization endpoint is:
<authServerUrl>/authorize
- The registration endpoint is:
<authServerUrl>/register
- The token endpoint is:
<authServerUrl>/token
- The userInfo endpoint is:
<authServerUrl>/userinfo
- The jwks endpoint is:
<authServerUrl>/.well-known/jwks.json
If this isn't the case, you can pass in overrides for any of these values. Passing in false will omit the value, which can be useful in some cases, like if your authorization server does not support dynamic client registration:
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"],
});
If you are using Clerk for authentication in your app, you can use the following helper to fetch Clerk's metadata from your Clerk frontend API and return it.
import { generateClerkAuthorizationServerMetadata } from "@clerk/mcp-tools/server";
const result = generateClerkAuthorizationServerMetadata();
For framework-specific implementations, see:
Creating an MCP endpoint
To create an MCP endpoint that handles the actual MCP protocol communication, you'll need to use framework-specific adapters, since each framework has its own way of handling request and response objects, which are critical parts of implementing the MCP protocol:
- Express.js: Use the
streamableHttpHandler
from @clerk/mcp-tools/express
- see Express.js guide
- Next.js: Use Vercel's MCP adapter with Next.js route handlers - see Next.js guide
These adapters handle the MCP protocol details and integrate with your authentication system.
Guide: building a client
The first step to building MCP compatibility into your AI application is allowing your users to connect with an MCP service. This can be kicked off simply with the URL of an MCP-compatible server, like https://example.com/mcp
. Normally, your app would implement a text field where the user can enter an MCP endpoint, or have a pre-built integration where clicking a button would trigger an MCP connection flow with a baked-in endpoint URL.
The process of actually making the MCP connection using the SDK, however, is fairly arduous, so we expose some tools that can help make this easier.
Framework-agnostic client creation
Here's how you can create an MCP client using the core utilities:
import { createDynamicallyRegisteredMcpClient } from "@clerk/mcp-tools/client";
import { createRedisStore } from "@clerk/mcp-tools/stores/redis";
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) => {
window.location.href = url;
},
store,
});
await connect();
return { sessionId };
}
OAuth callback handling
After the user completes the OAuth flow, you'll need to handle the callback:
import { completeAuthWithCode } from "@clerk/mcp-tools/client";
export async function handleOAuthCallback(code: string, state: string) {
const result = await completeAuthWithCode({
state,
code,
store,
});
return result;
}
Making MCP tool calls
Once authentication is complete, you can call MCP tools:
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;
}
For complete framework-specific implementations with working examples, see:
Stores
In order to implement MCP functionality in a client, persistent storage is required. This is because:
- The MCP flow operates across a minimum of three distinct server endpoints (initialization of MCP client, OAuth callback, MCP request), and these server endpoints could be deployed to distinct serverless/edge functions without a shared memory pool.
- Since the MCP connection is intended to be long-running, it must maintain a "session". Relying on in-memory storage for long-running sessions is generally a very bad idea ™️, since it would bloat memory requirements indefinitely as the app scales, and any sort of clearing of memory like a server restart would immediately invalidate all sessions.
As such, each of the client functions require that you pass in a store adapter. There are several built-in store adapters available:
File System Store (Development)
import fsStore from "@clerk/mcp-tools/stores/fs";
This uses a temporary file and is fast, easy, and adequate for local development and testing. However, it's not suitable for production since the file could be deleted at any time.
Production Stores
For production environments, use one of these persistent stores:
Redis Store
import { createRedisStore } from "@clerk/mcp-tools/stores/redis";
const store = createRedisStore({
url: process.env.REDIS_URL,
});
Postgres Store
import { createPostgresStore } from "@clerk/mcp-tools/stores/postgres";
const store = createPostgresStore({
connectionString: process.env.DATABASE_URL,
});
SQLite Store
import { createSqliteStore } from "@clerk/mcp-tools/stores/sqlite";
const store = createSqliteStore({
filename: "./mcp-sessions.db",
});
Custom Store Implementation
If you wish to use a different kind of store, you can implement your own by complying with this simple interface:
type JsonSerializable =
| null
| boolean
| number
| string
| JsonSerializable[]
| { [key: string]: JsonSerializable };
interface McpClientStore {
write: (key: string, data: JsonSerializable) => Promise<void>;
read: (key: string) => Promise<JsonSerializable>;
}
The built-in stores have a few extra methods that may be useful, but only read
and write
are required for this to work.
Reference docs
The above examples are more of a guide for how to implement the tools, but for those digging deeper, this section covers each tool that is exposed out of this package, what it can take in as arguments, and what it will return.
Scope: @clerk/mcp-tools/client
-
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.
-
Arguments:
interface CreateKnownCredentialsMcpClientParams {
clientId: string;
clientSecret: string;
oauthRedirectUrl: string;
oauthScopes?: string;
mcpEndpoint: string;
mcpClientName: string;
mcpClientVersion: string;
redirect: (url: string) => void;
store: McpClientStore;
}
-
Return Type:
interface McpClientReturnType {
sessionId: string;
connect: () => void;
transport: StreamableHTTPClientTransport;
client: Client;
authProvider: OAuthClientProvider;
}
-
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.
-
Arguments:
interface CreateDynamicallyRegisteredMcpClientParams {
mcpEndpoint: string;
oauthRedirectUrl: string;
oauthClientName?: string;
oauthClientUri?: string;
oauthScopes?: string;
oauthPublicClient?: boolean;
mcpClientName: string;
mcpClientVersion: string;
redirect: (url: string) => void;
store: McpClientStore;
}
-
Return Type:
interface McpClientReturnType {
sessionId: string;
connect: () => void;
transport: StreamableHTTPClientTransport;
client: Client;
authProvider: OAuthClientProvider;
}
-
getClientBySessionId
- Description: Given an existing session id, constructs a 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.
- Arguments:
interface GetClientBySessionIdParams {
sessionId: string;
store: McpClientStore;
state?: string;
}
-
completeAuthWithCode
-
Description: Designed to be used in the OAuth callback route. Passing in the code, state, and your store will finish the auth process
-
Arguments:
interface CompleteAuthWithCodeParams {
code: string;
state: string;
store: McpClientStore;
}
-
Return Type:
interface CompleteAuthWithCodeReturnType {
transport: StreamableHTTPClientTransport;
sessionId: string;
}
Scope: @clerk/mcp-tools/server
-
generateProtectedResourceMetadata
-
Description: Generates OAuth 2.0 Protected Resource Metadata as defined by RFC 9728. This metadata helps OAuth clients understand how to authenticate with your resource server.
-
Arguments:
interface GenerateProtectedResourceMetadataParams {
authServerUrl: string;
resourceUrl: string;
properties?: Record<string, any>;
}
-
Return Type:
{
resource: string;
authorization_servers: string[];
token_types_supported: string[];
token_introspection_endpoint: string;
token_introspection_endpoint_auth_methods_supported: string[];
jwks_uri: string;
authorization_data_types_supported: string[];
authorization_data_locations_supported: string[];
key_challenges_supported: Array<{
challenge_type: string;
challenge_algs: string[];
}>;
[key: string]: any;
}
-
generateClerkProtectedResourceMetadata
-
Description: Generates OAuth 2.0 Protected Resource Metadata specifically configured for Clerk authentication. This is a convenience wrapper around generateProtectedResourceMetadata
that automatically derives the auth server URL from your Clerk publishable key.
-
Arguments:
interface GenerateClerkProtectedResourceMetadataParams {
publishableKey: string;
resourceUrl: string;
}
-
Return Type: Same as generateProtectedResourceMetadata
-
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:
interface FetchClerkAuthorizationServerMetadataParams {
publishableKey: string;
}
-
Return Type:
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;
}>;
-
corsHeaders
-
Description: Pre-configured CORS headers for OAuth metadata endpoints. These headers allow cross-origin requests to your OAuth metadata endpoints, which is necessary for web-based MCP clients.
-
Value:
{
"Access-Control-Allow-Origin": "*";
"Access-Control-Allow-Methods": "GET, OPTIONS";
"Access-Control-Allow-Headers": "*";
"Access-Control-Max-Age": "86400";
}
For detailed documentation on server utilities and framework-specific implementations, see:
Framework-Specific Utilities
For framework-specific utilities and handlers, see: