MCP证书代理
模型上下文协议(MCP)服务器的安全凭证管理层。通过浏览器验证提供商-没有硬编码的API密钥,没有粘贴到聊天中的令牌。
为什么使用这个?
如果你正在构建需要访问外部API(GitHub、Google、Azure等)的MCP服务器,你可能已经将API密钥硬编码在环境变量中,或者将令牌粘贴到聊天中。该经纪人通过以下方式解决了这个问题:
- 通过浏览器OAuth2对提供者进行身份验证——您只需登录,代理即可处理其余事务
- 发布短期引用,而不是向代理公开原始令牌
- 在单个会话中集中所有MCP服务器的凭据管理
运作原理
You say: "List my GitHub repos"
Agent:
1. Checks if github-token is already stored
2. If not → triggers browser OAuth flow → you log in → token stored
3. Gets a short-lived reference to the token
4. Resolves the reference to the actual value (never shown to you)
5. Passes the token to your GitHub MCP tool代理通过包含的规则文件自动处理所有这些——您永远不会粘贴令牌。
安装
npm install @ars-system/mcp-credentials-broker或者克隆并从源代码构建:
git clone https://github.com/ars-system/mcp-credentials-broker.git
cd mcp-credentials-broker
npm install
npm run build配置
步骤1--获取提供商凭据(一次性)
经纪人需要 client_id 和 client_secret 对于您要使用的每个提供商。这些被设置为环境变量一次——代理永远不会看到或要求它们。
GitHub
- 首选
- 点击 OAuth应用程序 → 新建OAuth应用程序
- 填写:
- 应用程序名称: MCP Credentials Broker (或任何东西) - 主页网址: http://localhost - 授权回调URL: http://localhost:9876/oauth/callback
- 点击 注册应用程序
- 复制 客户端ID
- 点击 生成新的客户端密钥 并复制它
GITHUB_CLIENT_ID=your-client-id
GITHUB_CLIENT_SECRET=your-client-secret谷歌
- 首选 console.cloud.google.com/apis/credentials
- 点击 创建凭据 → OAuth客户端ID
- 应用程序类型: Web应用程序
- 添加 授权重定向URI:
http://localhost:9876/oauth/callback - 复制 客户端ID 和 客户端密钥
GCP_CLIENT_ID=your-client-id
GCP_CLIENT_SECRET=your-client-secretAzure
- 首选 portal.azure.com → Azure Active Directory → 应用程序注册
- 点击 新注册
- 随便命名,选择 任何组织目录中的帐户和个人Microsoft帐户
- 将重定向URI设置为:
http://localhost:9876/oauth/callback(类型:Web) - 创建后,转到 证书和秘密 → 新客户机密
- 复制 应用程序(客户端)ID 以及秘密值
AZURE_CLIENT_ID=your-client-id
AZURE_CLIENT_SECRET=your-client-secret八月
- 转到Okta管理控制台→ 应用程序 → 创建应用程序集成
- 选择 OIDC-OpenID连接 → Web应用程序
- 添加
http://localhost:9876/oauth/callback到 登录重定向URI - 复制 客户端ID 和 客户端密钥
- 同时设置您的Okta域名:
OKTA_CLIENT_ID=your-client-id
OKTA_CLIENT_SECRET=your-client-secret
OKTA_DOMAIN=your-org.okta.com______________________________________________________________________
步骤2——配置MCP客户端
将代理添加到其他MCP服务器旁边。在中传递提供程序env变量 env 块:
{
"mcpServers": {
"credentials-broker": {
"command": "node",
"args": ["/path/to/mcp-credentials-broker/dist/index.js"],
"env": {
"GITHUB_CLIENT_ID": "your-github-client-id",
"GITHUB_CLIENT_SECRET": "your-github-client-secret",
"GCP_CLIENT_ID": "your-gcp-client-id",
"GCP_CLIENT_SECRET": "your-gcp-client-secret"
}
},
"your-github-mcp": {
"command": "node",
"args": ["/path/to/your-github-mcp/dist/index.js"]
}
}
}仅配置您实际使用的提供程序。你不需要所有这些。
______________________________________________________________________
步骤3——添加代理规则(适用于亚马逊Q/Claude/Cursor)
将以下规则添加到代理配置中(例如 .amazonq/rules/credentials-broker.md 或您代理的自定义规则文件)。这些规则确保代理始终自动使用代理,从不要求您提供令牌。
复制以下整个部分:
# Credentials Broker — Agent Rules
You have access to a `credentials-broker` MCP server. Follow these rules strictly.
## Rule 1 — Never ask the user for API tokens, passwords, or secrets
If a task requires a token (GitHub, Google, Azure, AWS, etc.), use the broker to obtain it.
Never ask the user to paste a token into the chat.
## Rule 2 — Check if a token is already stored before authenticating
Before triggering an OAuth flow, always check if the token already exists:get_secret(名称:“ -令牌”,目的:“检查”)
If it succeeds, use that reference. Only call `start_oauth_flow` if the secret is missing or expired.
## Rule 3 — OAuth flow requires no credentials from the user
Call `start_oauth_flow` with only `provider`, `scopes`, and `secret_name`.
The broker reads `client_id` and `client_secret` from its own environment — you must NOT ask the user for these.
start_oauth_flow( 提供者:“github”, 作用域:\[“repo”,“read:user”\], secret_name:“github令牌” )
Tell the user: "A browser window will open for you to log in. Come back here once done."
## Rule 4 — Standard token retrieval pattern
Every time you need a token to pass to another MCP tool, follow this exact sequence:
**Step 1** — Get a short-lived reference:get_secret(名称:“github令牌”,目的:“\”,ttl_seconds:3600) → 返回{reference:{id:“ref uuid”}}
**Step 2** — Resolve the reference to the actual value:resolve_secret(reference_id:“ref uuid”) → 返回{值:“gho_actualtoken…”}
**Step 3** — Pass `value` to the target MCP tool's token/auth parameter.
## Rule 5 — Never log or display raw token values
After calling `resolve_secret`, use the value directly in the next tool call.
Do not print it, summarize it, or include it in any response to the user.
## Rule 6 — Naming convention for stored secrets
Use consistent names so tokens can be reused across tool calls in the same session:
| Provider | secret_name |
|----------|--------------------|
| GitHub | `github-token` |
| Google | `google-token` |
| Azure | `azure-token` |
| Okta | `okta-token` |
| Custom | `-token` |
## Rule 7 — Provider configuration errors
If `start_oauth_flow` fails with "not configured", tell the user:
> "The broker needs `
_CLIENT_ID` and `
_CLIENT_SECRET` set as environment variables where the broker is running. These are set once by you — I won't ask for them again."
## Summary flow
需要代币吗? └─ get_secret(“github令牌”)→ 存在? → resolve_secret→ 使用它 → 失踪? → start_oauth_flow→ get_secret→ resolve_secret→ 使用它
______________________________________________________________________
可用工具
start_oauth_flow
打开浏览器供您登录。将生成的令牌存储在 secret_name.不需要您提供凭据--代理读取 client_id 和 client_secret 从它的环境。
| 参数 | 必填 | 说明 |
|---|---|---|
provider | 是的 | github, google, azure, okta, oauth2 |
scopes | yes | 要请求的OAuth2作用域列表 |
secret_name | yes | 用于存储令牌的名称 |
authorization_endpoint | no | 自定义身份验证URL(仅适用于 okta / oauth2) |
token_endpoint | no | 自定义令牌URL(仅适用于 okta / oauth2) |
{
"provider": "github",
"scopes": ["repo", "read:user"],
"secret_name": "github-token"
}______________________________________________________________________
get_secret
对存储的秘密发出短暂的引用。返回一个引用ID,而不是原始值。
| 参数 | 必填 | 说明 |
|---|---|---|
name | yes | 存储秘密的名称 |
purpose | 是 | 你为什么要求(审计) |
ttl_seconds | no | 引用的有效期(默认值:3600) |
{
"name": "github-token",
"purpose": "listing repositories",
"ttl_seconds": 3600
}答复:
{
"reference": {
"id": "ref-uuid",
"name": "github-token",
"expiresIn": 3600
}
}______________________________________________________________________
resolve_secret
将引用ID解析为实际令牌值。代理在将令牌传递给另一个MCP工具之前立即使用。
| 参数 | 必填 | 说明 |
|---|---|---|
reference_id | 是 | id 返回由 get_secret |
{ "reference_id": "ref-uuid" }答复:
{ "value": "gho_actualtoken..." }______________________________________________________________________
store_secret
手动存储秘密(例如静态API密钥)。使用 get_secret + resolve_secret 以便稍后检索。
| 参数 | 必填 | 说明 |
|---|---|---|
name | yes | 秘密的标识符 |
value | yes | 秘密值 |
tags | 无 | 组织的键值标签 |
______________________________________________________________________
mint_token
生成一个作用域为提供者的基于JWT的短期令牌。当您想要代理颁发的令牌而不是原始OAuth令牌时非常有用。
| 参数 | 必填 | 说明 |
|---|---|---|
provider | 是的 | github, aws, gcp, azure, oauth2, okta |
scopes | yes | 范围/权限列表 |
resource | 否 | 资源标识符 |
ttl_seconds | no | 令牌生存期(默认值:提供程序默认值) |
______________________________________________________________________
revoke_token
立即使铸造的令牌无效。
| 参数 | 必填 | 说明 |
|---|---|---|
token_id | yes | 要撤销的令牌的ID |
______________________________________________________________________
get_broker_stats
返回活动令牌、活动引用和存储秘密的计数。
______________________________________________________________________
端到端示例
You: "Create a GitHub issue in my repo"
Agent: 1. get_secret("github-token") → not found
2. start_oauth_flow( → browser opens
provider: "github",
scopes: ["repo"],
secret_name: "github-token"
) → you log in → token stored
3. get_secret("github-token", → { id: "ref-abc" }
purpose: "create issue")
4. resolve_secret("ref-abc") → { value: "gho_..." } ← never shown to you
5. github-mcp/create_issue( → issue created ✓
token: "gho_...",
title: "..."
)______________________________________________________________________
提供程序TTL限制
| 提供程序 | 默认TTL | 最大TTL |
|---|---|---|
| GitHub | 1小时 | 8小时 |
| AWS | 1小时 | 12小时 |
| GCP | 1小时 | 12小时 |
| Azure | 1小时 | 12小时 |
| 秋田 | 1小时 | 12小时 |
| OAuth2(通用) | 1小时 | 24小时 |
______________________________________________________________________
建筑
┌──────────────────────────────────────────────────────┐
│ MCP Credentials Broker │
├──────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ OAuth Web Flow │ │
│ │ - Spins up local HTTP server on :9876 │ │
│ │ - Opens browser to provider auth URL │ │
│ │ - Receives callback with auth code │ │
│ │ - Exchanges code for access token │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Credentials Manager │ │
│ │ - In-memory secret storage │ │
│ │ - Short-lived reference issuance │ │
│ │ - Token lifecycle & auto-expiry │ │
│ │ - Provider config from env vars │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ MCP Server Interface │ │
│ │ - Tool definitions & request handling │ │
│ └─────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────┘______________________________________________________________________
安全说明
- 代币被存储 仅在内存中 --当代理进程重新启动时,它们会丢失
- 原始令牌值从不由返回
get_secret--仅参考ID - 代理规则文件指示代理永远不要显示已解析的令牌值
- 集
JWT_SECRETenv-var在生产环境中安全地对代理发行的令牌进行签名 - OAuth回调服务器仅在活动期间运行
start_oauth_flow呼叫,然后关闭
______________________________________________________________________
发展
npm run watch # TypeScript watch mode
npm run build # Build
npm run dev # Build + run
npm run lint # Lint______________________________________________________________________
贡献
欢迎投稿!请遵循现有的TypeScript模式并保持正确的类型定义。
许可证
MIT——有关详细信息,请参阅LICENSE文件
资源
______________________________________________________________________
