关于 MCP Tools
MCP Tools 是基于 MCP SDK 的 TypeScript 库,供开发者为应用添加带认证的 MCP 支持。它提供客户端连接和服务端点工具,包括 OAuth 流程、持久化会话存储及反馈收集。
主要功能
- 01客户端与服务端工具
- 02OAuth 客户端连接流程
- 03受保护资源元数据生成
- 04Express、Hono 和 Next.js 适配器
- 05Redis、Postgres、SQLite 与文件存储
- 06Agent 反馈提交工具
适用场景
- 01为应用添加带认证的 MCP 支持
- 02通过 OAuth 将用户连接到 MCP 端点
- 03使用框架适配器构建 MCP 端点
- 04跨请求持久化客户端会话
MCP 相关
该库提供 MCP 两端的工具:客户端连接和工具调用,以及带认证支持的服务端点。服务端功能包括受保护资源元数据和可选的 Agent 反馈工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
MCP 工具
一个基于 MCP TypeScript SDK 构建的库,让你更轻松地将带有身份验证的 MCP 集成到 MCP 客户端和/或服务中。
什么是 MCP?
MCP 是一种协议,可让 Claude、ChatGPT、Cursor 等 AI 应用请求你的许可,以访问一些私人信息。通常,你需要登录账号才能访问这些信息,例如电子邮件或私有 GitHub 仓库等。
这样一来,你就能为 AI 应用提供它们原本无法访问的上下文和能力。例如,你可以让 AI 应用将私有仓库中的代码作为上下文来回答问题,也可以让它代表你撰写并发送电子邮件,当然,发送前你可以先审核。大致如下:

我们认为这很有价值,因为它让人们能够使用 AI 访问以前无法访问的更多信息,同时也确保安全:作为用户,你可以控制 AI 能访问哪些内容、能执行哪些操作。随着 MCP 的普及,我们很期待看到更多新的 AI 用例成为可能。我们构建这个库,就是希望帮助人们更轻松地将 MCP 集成到自己的应用中。
客户端与服务端的用法
MCP 涉及两个参与方:
- 客户端:希望访问另一项服务的一方。在上面的示例中,客户端是希望访问 Gmail 的 Claude。
- 服务端:拥有客户端希望访问的内容的一方。在上面的示例中,这就是 Gmail。有时也称为“资源服务”或“MCP 服务”。
这个库为这两类参与方都提供了工具,因此第一步是明确你要构建客户端还是服务端。我们会分别介绍这两种用例。
NOTE: 在 Web 开发中,“客户端”和“服务端”通常指前端(浏览器)和后端(Web 服务)。但这里并非如此,请注意不要混淆!
特定框架的文档
有关适用于你所用框架的详细实现指南和示例,请参阅:
- Express.js 集成 - 使用 Express.js 构建 MCP 服务的完整指南
- Hono 集成 - 使用 Hono 和边缘运行时构建 MCP 服务的完整指南
- Next.js 集成 - 使用 Next.js 构建 MCP 服务和客户端的完整指南
目录
指南:构建服务端
如果你要构建一个希望支持 MCP 的服务,请使用 @clerk/mcp-tools/server 导入路径。
受保护资源元数据
为了让 MCP 规范中最新的身份验证流程 正常运行,您的服务需要公开一个名为“受保护资源元数据”的静态元数据文件,该文件由 RFC 9728 定义。
此库提供了一个工具,可快速为您生成这样的元数据文件。下面是一个使用示例:
import { generateProtectedResourceMetadata } from '@clerk/mcp-tools/server';
const result = generateProtectedResourceMetadata({
resourceUrl: 'https://myapp.com/current-route',
authServerUrl: 'https://auth.example.com',
});
您需要在 .well-known/oauth-protected-resource 设置一个路由,并确保服务在该路由中返回此结果。
如果您的应用使用 Clerk 进行身份验证,我们提供了一个辅助工具,让此操作更简单:
import { generateClerkProtectedResourceMetadata } from '@clerk/mcp-tools/server';
const result = generateClerkProtectedResourceMetadata({
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
resourceUrl: 'https://myapp.com/current-route',
});
有关特定框架的受保护资源元数据处理程序实现,请参阅:
授权服务器元数据
注意: 此功能尚未完全实现
MCP 规范的较早版本 要求 MCP 服务发布单独的“授权服务器元数据”文档,该文档由 RFC 8414 定义。大多数部署在发布受保护资源元数据并使用具有自身元数据端点的授权服务后,不再需要此端点。对于自定义或嵌入式授权服务器,或较旧的 MCP 客户端,您可能仍然需要此端点。
如果您使用 Clerk 进行身份验证,请从 Clerk Frontend API 获取元数据,并通过授权服务器元数据端点返回。
import { fetchClerkAuthorizationServerMetadata } from '@clerk/mcp-tools/server';
// Return this result from <your-app>/.well-known/oauth-authorization-server
const result = await fetchClerkAuthorizationServerMetadata({
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
});
有关特定框架的实现,请参阅:
创建 MCP 端点
要创建用于处理实际 MCP 协议通信的 MCP 端点,您需要使用特定框架的适配器,因为每种框架处理请求和响应对象的方式各不相同,而这些对象是实现 MCP 协议的关键部分:
- Express.js:使用
@clerk/mcp-tools/express中的streamableHttpHandler,请参阅 Express.js 指南 - Hono:使用
@clerk/mcp-tools/hono中的streamableHttpHandler,请参阅 Hono 指南 - Next.js:使用 Vercel 的 MCP 适配器和 Next.js 路由处理程序,请参阅 Next.js 指南
这些适配器负责处理 MCP 协议细节,并与您的身份验证系统集成。
收集来自 Agent 的反馈
使用你的 MCP 服务的 Agent 有时会遇到阻碍、需要变通方法,或觉得某个工具令人困惑。@clerk/mcp-tools/feedback 添加了一个 submit_feedback 工具,Agent 可以调用它来提交反馈。报告会存储在你的 Clerk 实例中,并显示在 Clerk Dashboard 实例的 反馈 标签页上。
import { submitFeedbackTool } from '@clerk/mcp-tools/feedback';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
function createServer() {
const server = new McpServer({ name: 'my-app', version: '1.0.0' });
server.registerTool(...submitFeedbackTool({ secretKey: process.env.CLERK_SECRET_KEY! }));
// ...register your own tools
return server;
}
secretKey必须是报告所属 Clerk 实例的密钥(sk_...)。如果它为空,submitFeedbackTool会抛出异常,因此缺少环境变量会导致启动失败。- Agent 会描述任务、问题类型(
missing、broken、confusing或idea)、任务如何结束,以及它们尝试了什么、遇到了什么问题。 - 每份报告都会将你的服务标记为来源:默认使用请求的主机名,也可以传入
server: { name, version }自行设置名称。 - 每份报告都会根据 MCP 客户端随请求发送的客户端信息标记 Agent;如果没有,则使用 HTTP
User-Agent标头。通用 HTTP 库和浏览器(例如node或Mozilla)不会用作名称,而只在连接时才声明身份的客户端(在 stdio 场景中很常见)将不会显示名称。 - 如果请求通过
verifyClerkToken进行身份验证(例如通过mcpAuthClerk),则每份报告都会附带已登录用户的 ID 和 OAuth 客户端 ID。verifyClerkToken会使用extra.verifiedBy: 'clerk'标记其结果(使用@clerk/mcp-tools/server中的isClerkAuthInfo检查);不会发送任何其他验证器提供的身份信息。 - Agent 无需先征求用户同意即可提交报告。报告包含 Agent 对用户请求的摘要、它调用的工具以及任何错误;如果附带了用户 ID,报告还会与该 ID 关联。请在向用户提供的隐私信息中说明这一点。
- Clerk 会移除其检测到的报告中的密钥,并且每个实例每小时最多接受 100 份报告。
- 在没有身份验证的公共 MCP 端点上,任何人都可以调用此工具、提交误导性报告,并耗尽实例每小时 100 份报告的限额。请尽可能通过身份验证或其他访问控制来保护它。
- 如果报告无法存储,该工具会告知 Agent 不要重试,并使用
console.error记录响应状态。向 Clerk 发送的请求会在 10 秒后超时。 - 此模块需要
zod(3.25 或更高版本,或 4);MCP SDK 本身也需要它。
指南:构建客户端
在 AI 应用中实现 MCP 兼容性的第一步,是允许用户连接到 MCP 服务。只需提供 MCP 兼容服务的 URL 即可启动连接,例如 https://example.com/mcp。通常,你的应用会实现一个文本输入框,让用户输入 MCP 端点;或者提供预置集成,让用户点击按钮后,通过预先配置的端点 URL 启动 MCP 连接流程。
然而,使用 SDK 实际建立 MCP 连接的过程相当繁琐,因此我们提供了一些工具来简化这一过程。
创建与框架无关的客户端
下面介绍如何使用核心实用工具创建 MCP 客户端:
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 };
}
处理 OAuth 回调
用户完成 OAuth 流程后,你需要处理回调:
import { completeAuthWithCode } from '@clerk/mcp-tools/client';
export async function handleOAuthCallback(code: string, state: string) {
const result = await completeAuthWithCode({
state,
code,
store,
});
// OAuth flow is now complete
return result;
}
调用 MCP 工具
身份验证完成后,你可以调用 MCP 工具:
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;
}
如需查看包含可运行示例的完整框架专属实现,请参阅:
存储
要在客户端中实现 MCP 功能,需要持久化存储。这是因为:
- MCP 流程至少涉及三个不同的服务端点(MCP 客户端初始化、OAuth 回调、MCP 请求),而这些服务端点可能部署在不同的无服务器/边缘函数上,且彼此之间没有共享内存池。
- MCP 连接旨在长期运行,因此必须维护一个“会话”。依赖内存存储来管理长期会话通常是个非常糟糕的主意 ™️,因为随着应用扩展,这会无限增加内存需求;而且,任何清除内存的操作(例如重启服务器)都会立即使所有会话失效。
因此,每个客户端函数都要求传入一个存储适配器。以下提供了几个内置存储适配器:
文件系统存储(开发环境)
import fsStore from '@clerk/mcp-tools/stores/fs';
此存储使用临时文件,速度快、易于使用,足以满足本地开发和测试需求。不过,它不适用于生产环境,因为文件可能随时被删除。
生产环境存储
对于生产环境,请使用以下任一持久化存储:
Redis 存储
import { createRedisStore } from '@clerk/mcp-tools/stores/redis';
const store = createRedisStore({
url: process.env.REDIS_URL,
});
Postgres 存储
import { createPostgresStore } from '@clerk/mcp-tools/stores/postgres';
const store = createPostgresStore({
connectionString: process.env.DATABASE_URL,
});
SQLite 存储
import { createSqliteStore } from '@clerk/mcp-tools/stores/sqlite';
const store = createSqliteStore({
filename: './mcp-sessions.db',
});
自定义存储实现
如果你希望使用其他类型的存储,可以通过实现以下简单接口来自行实现:
type JsonSerializable =
| null
| boolean
| number
| string
| JsonSerializable[]
| { [key: string]: JsonSerializable };
interface McpClientStore {
write: (key: string, data: JsonSerializable) => Promise<void>;
read: (key: string) => Promise<JsonSerializable>;
}
内置存储还有一些可能有用的额外方法,但要使其正常工作,只需实现 read 和 write。
参考文档
以上示例更像是如何实现这些工具的_指南_。对于想要深入了解的读者,本节将介绍此包公开的每个工具、它可以接受的参数,以及它会返回的内容。
范围:@clerk/mcp-tools/client
-
createKnownCredentialsMcpClient-
说明: 如果不希望使用动态客户端注册,并且你的界面可以从现有 OAuth 客户端收集客户端 ID 和密钥,则可以使用此函数创建 MCP 客户端。虽然这会增加用户体验中的操作步骤,但我们建议允许使用未启用动态客户端注册的 MCP 服务,因为动态客户端注册存在若干安全/欺诈风险,并非每个提供方都愿意承担这些风险。
-
参数:
interface CreateKnownCredentialsMcpClientParams { /** * OAuth 客户端 ID,预期通过用户输入获取 */ clientId: string; /** * OAuth 客户端密钥,预期通过用户输入获取 */ clientSecret: string; /** * OAuth 重定向 URL——用户同意后,此路由将收到授权码和 state。 */ oauthRedirectUrl: string; /** * 希望申请访问权限的 OAuth 范围 */ oauthScopes?: string; /** * MCP 服务的端点,预期通过用户输入获取 */ mcpEndpoint: string; /** * 传递给 MCP SDK 创建的客户端的名称 * @see https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#writing-mcp-clients */ mcpClientName: string; /** * 传递给 MCP SDK 创建的客户端的版本号 * @see https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#writing-mcp-clients */ mcpClientVersion: string; /** * 调用时将重定向到指定 URL 的函数 */ redirect: (url: string) => void; /** * 用于存储身份验证数据的持久化存储 * @see https://github.com/clerk/mcp-tools?tab=readme-ov-file#stores */ store: McpClientStore; } -
返回类型:
interface McpClientReturnType { /** * 表示与已连接的 MCP 服务端点关联的会话。 */ sessionId: string; /** * 调用此函数将启动与 MCP 服务的连接。 */ connect: () => void; /** * 底层原语,可能不需要使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/streamableHttp.ts#L119 */ transport: StreamableHTTPClientTransport; /** * 底层原语,可能不需要使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/index.ts#L81 */ client: Client; /** * 底层原语,可能不需要使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/auth.ts#L13 */ authProvider: OAuthClientProvider; }
-
-
createDynamicallyRegisteredMcpClient-
描述: 仅提供 MCP 端点 URL 即可创建新的 MCP 客户端。通过 OAuth 2.0 Dynamic Client Registration Protocol,按需向授权服务器注册 OAuth 客户端。
-
参数:
interface CreateDynamicallyRegisteredMcpClientParams { /** * MCP 服务的端点,预期通过用户输入收集 */ mcpEndpoint: string; /** * OAuth 重定向 URL——用户同意后,此路由将接收授权码和状态。 */ oauthRedirectUrl: string; /** * 要向授权服务器创建的 OAuth 客户端名称 */ oauthClientName?: string; /** * 要向授权服务器创建的 OAuth 客户端 URI */ oauthClientUri?: string; /** * 希望请求访问的 OAuth 作用域 */ oauthScopes?: string; /** * OAuth 客户端是公开客户端还是机密客户端 * @see https://datatracker.ietf.org/doc/html/rfc6749#section-2.1 */ oauthPublicClient?: boolean; /** * 传递给 MCP SDK 创建的客户端的名称 * @see https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#writing-mcp-clients */ mcpClientName: string; /** * 传递给 MCP SDK 创建的客户端的版本号 * @see https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#writing-mcp-clients */ mcpClientVersion: string; /** * 调用时接收 URL 并重定向到该 URL 的函数 */ redirect: (url: string) => void; /** * 用于存储身份验证数据的持久化存储 * @see https://github.com/clerk/mcp-tools?tab=readme-ov-file#stores */ store: McpClientStore; } -
返回类型:
interface McpClientReturnType { /** * 表示与已连接的 MCP 服务端点关联的会话。 */ sessionId: string; /** * 调用此函数将启动与 MCP 服务的连接。 */ connect: () => void; /** * 底层原语,可能不需要使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/streamableHttp.ts#L119 */ transport: StreamableHTTPClientTransport; /** * 底层原语,可能不需要使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/index.ts#L81 */ client: Client; /** * 底层原语,可能不需要使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/auth.ts#L13 */ authProvider: OAuthClientProvider; }
-
-
getClientBySessionId- 描述: 给定现有的会话 ID,构建一个 MCP 客户端,其信息与最初创建客户端/会话时使用的信息相匹配。此方法旨在用于 OAuth 回调路由,以及服务初始化后的任何后续 MCP 调用。
- 参数:
interface GetClientBySessionIdParams { /** * The session id to retrieve the client details for */ sessionId: string; /** * A persistent store for auth data * @see https://github.com/clerk/mcp-tools?tab=readme-ov-file#stores */ store: McpClientStore; /** * If using this function in the OAuth callback route, pass in the state to * ensure that PKCE can run correctly. */ state?: string; }-
返回类型:
interface McpClientReturnType { /** * 表示与已连接的 MCP 服务端点关联的会话。 */ sessionId: string; /** * 调用此函数将初始化与 MCP 服务的连接。 */ connect: () => void; /** * 底层原语,通常无需使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/streamableHttp.ts#L119 */ transport: StreamableHTTPClientTransport; /** * 底层原语,通常无需使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/index.ts#L81 */ client: Client; /** * 底层原语,通常无需使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/auth.ts#L13 */ authProvider: OAuthClientProvider; }
-
completeAuthWithCode-
描述: 专为 OAuth 回调路由设计。传入代码、状态和存储即可完成身份验证流程。
-
参数:
interface CompleteAuthWithCodeParams { /** * 通过查询字符串从身份验证提供方返回的授权代码。 * @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1 */ code: string; /** * 通过查询字符串从身份验证提供方返回的状态。 * @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1 */ state: string; /** * 用于存储身份验证数据的持久化存储 * @see https://github.com/clerk/mcp-tools?tab=readme-ov-file#stores */ store: McpClientStore; } -
返回类型:
interface CompleteAuthWithCodeReturnType { /** * 底层原语,通常无需使用 * @see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/streamableHttp.ts#L119 */ transport: StreamableHTTPClientTransport; /** * 表示与已连接的 MCP 服务端点关联的会话。 */ sessionId: string; }
-
作用域:@clerk/mcp-tools/server
-
generateProtectedResourceMetadata-
描述: 生成 RFC 9728 定义的 OAuth 2.0 受保护资源元数据。此元数据可帮助 OAuth 客户端了解如何向资源服务进行身份验证。
-
参数:
interface GenerateProtectedResourceMetadataParams { /** * OAuth 授权服务的 URL */ authServerUrl: string; /** * 此元数据适用的资源服务 URL */ resourceUrl: string; /** * 要包含在元数据中的其他属性 */ properties?: Record<string, any>; } -
返回类型:
{ 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-
**描述:**生成专为 Clerk 身份验证配置的 OAuth 2.0 受保护资源元数据。这是
generateProtectedResourceMetadata的便捷封装,会根据你的 Clerk 可发布密钥自动推导授权服务器 URL。 -
参数:
interface GenerateClerkProtectedResourceMetadataParams { /** * 你的 Clerk 可发布密钥(例如,pk_test_... 或 pk_live_...) */ publishableKey: string; /** * 元数据适用的资源服务器 URL */ resourceUrl: string; } -
**返回类型:**与
generateProtectedResourceMetadata相同
-
-
fetchClerkAuthorizationServerMetadata-
**描述:**根据你的可发布密钥,从 Clerk 的服务器获取 OAuth 2.0 授权服务器元数据。此函数返回 Clerk 授权服务器的实际元数据,而不是在本地生成元数据。
-
参数:
interface FetchClerkAuthorizationServerMetadataParams { /** * 你的 Clerk 可发布密钥(例如,pk_test_... 或 pk_live_...) */ publishableKey: string; } -
返回类型:
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; // Clerk 提供的其他元数据 }>;
-
-
isClerkAuthInfo- **描述:**当
AuthInfo对象来自verifyClerkToken时返回true。该函数会在结果中标记extra.verifiedBy: 'clerk'。可用此函数区分 Clerk 用户和客户端 ID 与自定义验证器生成的 ID。 - 参数:
authInfo: AuthInfo | undefined - 返回值:
boolean
- **描述:**当
-
corsHeaders-
**描述:**为 OAuth 元数据端点预先配置的 CORS 标头。这些标头允许跨源请求访问你的 OAuth 元数据端点,这是基于 Web 的 MCP 客户端所必需的。
-
值:
{ "Access-Control-Allow-Origin": "*"; "Access-Control-Allow-Methods": "GET, OPTIONS"; "Access-Control-Allow-Headers": "*"; "Access-Control-Max-Age": "86400"; }
-
有关服务器实用工具和特定框架实现的详细文档,请参阅:
特定框架的实用工具
有关特定框架的实用工具和处理程序,请参阅:
- Express.js:参阅 Express.js 参考文档
- Hono:参阅 Hono 参考文档
- Next.js:参阅 Next.js 参考文档
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。