MCP密钥服务
的共享API密钥管理服务 TechMavie MCP服务器用户通过门户进行订阅,安全地存储他们的MCP服务器凭据,并接收单个 usr_... 每个连接的API密钥。MCP服务器在运行时解析这些密钥以检索解密的凭据。
实时门户: mcpkeys.techmavie.数字
建筑
该项目有两个组成部分:
| 组件 | 堆栈 | 端口 | 描述 |
|---|---|---|---|
后端 (/src) | Express+SQLite | 8090 | 凭证存储、加密、密钥解析、管理员API |
门户 (/portal) | Next.js 15 | 3000 | 用户仪表板、Stripe计费、连接管理 |
两者都作为Docker容器运行,并通过内部Docker网络进行通信。门户代理向后端请求凭据操作。
特性
后端
- 用于存储凭据的AES-256-GCM加密
- 用于API密钥查找的SHA-256哈希(从未存储原始密钥)
- WAL模式的SQLite存储
- 每个连接器的凭据验证和动态字段模式
- 通过承载令牌进行每台服务器的内部身份验证
- 用于用户管理、密钥吊销和使用统计的管理端点
- 内置IP速率限制,用于公共注册和轮换
门户
- Firebase身份验证(谷歌和GitHub登录)
- Google/GitHub账号链接(链接多种登录方式)
- 条纹订阅计费,支持促销代码
- 用于订阅管理的条纹计费门户
- 带有连接管理的仪表板(创建、查看、撤销)
- 用于用户和密钥管理的管理面板
- 暗/亮主题支持
- 无Firebase的开发预览模式
部署
- Docker Compose采用多阶段构建
- GitHub Actions CI/CD(推送到main时自动部署)
- 对两个容器进行健康检查
- 仅本地主机端口绑定(专为反向代理设计)
支持的连接器
| 连接器 | 标签 | 所需凭据 |
|---|---|---|
nextcloud | Nextcloud | 主机URL、用户名、应用密码 |
ghost-cms | ghost CMS | 站点URL,管理员API密钥 |
keywords-everywhere | 关键词无处不在 | API密钥 |
grabmaps | GrabMaps | GrabMaps API密钥,AWS访问密钥,机密,区域 |
github | GitHub | 个人访问令牌 |
brave-search | 勇敢的搜索 | API密钥 |
exa | Exa.ai | neneneba API密钥 |
perplexity | 困惑 | API密钥 |
reddit | 客户端ID,客户端密码 | |
openwebui | 打开WebUI | URL,API密钥 |
datagovmy | 马来西亚开放数据 | 谷歌地图密钥、GrabMaps密钥、AWS证书(均为可选) |
ltadatamallsg | 新加坡LTA数据商城 | API密钥(可选) |
youtube | YouTube | API密钥 |
连接器定义已上线 src/connectors.ts门户根据这些模式动态呈现凭证表单。
运作原理
User (Claude, etc.)
│
│ Connects with api_key in URL
▼
MCP Server (mcp.techmavie.digital/{server}/mcp?api_key=usr_...)
│
│ POST /internal/resolve (Bearer: server-token)
▼
MCP Key Service → decrypts credentials → returns to MCP server
│
▼
MCP Server uses credentials to call the actual service (Nextcloud, GitHub, etc.)- 用户通过谷歌或GitHub登录门户网站。
- 用户通过Stripe结账进行订阅。
- 用户通过选择连接器并输入凭据来创建连接。
- 后端对凭据进行加密并返回
usr_...API密钥。 - 用户配置其MCP客户端URL:
https://mcp.techmavie.digital/{server}/mcp?api_key=usr_... - 当MCP服务器收到请求时,它会调用
/internal/resolve拥有自己的持有者代币。
当MCP服务器可以直接访问Docker网络时,使用 http://mcp-key-service:8090/internal/resolve. 对于外部呼叫者,请使用 https://mcpkeys.techmavie.digital/internal/resolve,它代理后端服务。
- 后端验证服务器的身份,解密凭据,并返回它们。
有关详细的集成说明,请参阅 docs/mcp-server集成.md.
环境变量
必需
| 变量 | 描述 |
|---|---|
ADMIN_API_KEY | 持有者代币 /admin/* 端点。生成方式 openssl rand -hex 32 |
KEY_ENCRYPTION_SECRET | AES-256-GCM的64个十六进制字符。生成方式 openssl rand -hex 32 |
INTERNAL_SERVER_TOKENS | 逗号分隔 server_id:token 成对(见下文) |
FIREBASE_API_KEY | Firebase客户端SDK-API密钥(在门户构建时使用) |
FIREBASE_AUTH_DOMAIN | Firebase客户端SDK——认证域 |
FIREBASE_PROJECT_ID | Firebase客户端SDK--项目ID |
FIREBASE_ADMIN_PROJECT_ID | Firebase管理SDK--项目ID |
FIREBASE_ADMIN_CLIENT_EMAIL | Firebase管理SDK--服务帐户电子邮件 |
FIREBASE_ADMIN_PRIVATE_KEY | Firebase管理SDK——服务帐户私钥 |
STRIPE_SECRET_KEY | Stripe API密钥 |
STRIPE_WEBHOOK_SECRET | Stripe webhook签名密钥 |
STRIPE_PRICE_ID | 订阅产品的条纹价格ID |
可选的
| 变量 | 默认值 | 描述 |
|---|---|---|
PORT | 8090 | 后端端口 |
HOST | 0.0.0.0 | 后端绑定地址 |
DATA_DIR | ./data | SQLite数据库目录 |
TRUST_PROXY | 0 | 设置为 1 当位于nginx/反向代理之后时 |
ADMIN_UIDS | -- | 逗号分隔的Firebase UID作为管理员种子 |
服务器令牌格式
INTERNAL_SERVER_TOKENS=nextcloud:token1,ghost-cms:token2,github:token3,...支持的服务器ID: nextcloud, ghost-cms, keywords-everywhere, grabmaps, github, brave-search, exa, perplexity, reddit, openwebui, datagovmy, ltadatamallsg, youtube
生成每个令牌 openssl rand -hex 32.
本地开发
cp .env.sample .env
# Fill in values (see above)
npm install
npm run dev对于门户:
cd portal
cp .env.sample .env.local # if exists, or create from root .env.sample
npm install
npm run dev门户网站运行 http://localhost:3000 后端打开 http://localhost:8090.
预览模式: 如果未设置Firebase客户端配置,门户将在以下位置以预览模式运行(仅限开发) http://localhost:3000/dashboard?preview=1 使用模拟数据。
脚本
npm run dev--启动后端tsx(热重新加载)npm run build--将TypeScript编译为dist/npm start--运行已编译的后端npm test--构建并运行烟雾测试套件
门户页面
| 路线 | 描述 |
|---|---|
/ | 登录Google/GitHub的登录页面 |
/dashboard | 连接管理、订阅状态、链接帐户 |
/admin | 管理面板(用户、密钥、统计数据)——需要管理员角色 |
/success | 结账后成功页面 |
门户网站API路线
| 路线 | 方法 | 描述 |
|---|---|---|
/api/user/sync | POST | 将Firebase用户同步到后端 |
/api/connections | GET | 列出用户的连接 |
/api/connections | POST | 创建新连接 |
/api/connections/[prefix] | DELETE | 撤消连接 |
/api/rotate | POST | 旋转API键 |
/api/connectors-info | GET | 列出可用连接器及其字段 |
/api/stripe/create-checkout | POST | 创建Stripe结账会话 |
/api/stripe/create-portal | POST | 创建Stripe计费门户会话 |
/api/stripe/webhook | POST | 处理Stripe webhook事件 |
/api/admin/users | GET | 列出所有用户(管理员) |
/api/admin/keys | GET | 列出所有密钥(管理员) |
/api/admin/stats | GET | 服务统计(管理员) |
/api/claim | POST | 声明用户帐户的预先存在的密钥 |
后端API
公共
GET /health
Docker和正常运行时间监视器的Healthcheck端点。
GET /api/connectors
返回所有可用的连接器模式(标签、字段、服务器ID)。
POST /api/register
为连接器创建新的API密钥。需要Firebase身份验证。
{
"label": "My Nextcloud",
"connector_id": "nextcloud",
"credentials": {
"nextcloud_host": "https://cloud.example.com",
"nextcloud_username": "user",
"nextcloud_password": "app-password"
}
}POST /api/rotate
旋转现有 usr_... 密钥,撤销旧密钥。
内部
POST /internal/resolve
仅由MCP服务器调用。每个服务器都使用自己的承载令牌进行身份验证。 后端路由位于 http://mcp-key-service:8090/internal/resolve Docker内部。 公共门户网站也公开了 https://mcpkeys.techmavie.digital/internal/resolve 作为后端路由的瘦代理。
Authorization: Bearer { "key": "usr_..." }答复:
{
"valid": true,
"credentials": { "nextcloud_host": "...", "nextcloud_username": "...", "nextcloud_password": "..." },
"label": "My Nextcloud",
"connector_id": "nextcloud"
}管理员
所有管理路线都需要 Authorization: Bearer 或 x-admin-key: .
| 路线 | 方法 | 描述 |
|---|---|---|
GET /admin/keys | GET | 列出活动密钥元数据 |
DELETE /admin/keys/:prefix | DELETE | 按精确前缀撤销密钥 |
GET /admin/stats | GET | 使用统计 |
GET /admin/users | GET | 列出所有用户 |
PUT /admin/users/:uid/subscription | PUT | 更新订阅状态 |
POST /admin/users/:uid/reactivate-keys | POST | 重新激活挂起的密钥 |
POST /admin/users/:uid/suspend-keys | POST | 暂停用户密钥 |
条纹集成
该门户使用Stripe进行订阅计费:
- 结账: 创建支持促销代码的订阅签出会话
- 计费门户: 允许用户管理其订阅、更新付款方式、取消
- Webhooks: 手柄
customer.subscription.created/updated/deleted和invoice.payment_failed/succeeded - 价格筛选: Webhook事件按以下方式筛选
STRIPE_PRICE_ID防止与同一帐户上的其他Stripe产品发生串扰
Docker部署
docker compose up -d --buildcompose文件运行两个容器:
mcp-key-service(后端)--绑定到127.0.0.1:8090mcp-key-portal(Next.js)--绑定到127.0.0.1:3001
两个容器都连接一个外部 mcp-network 用于服务间通信。
重要提示: Firebase客户端配置(FIREBASE_API_KEY等)必须在Docker上可用 构建时间 对于门户网站。compose文件将这些作为构建参数传递。
CI/CD
GitHub Actions在推送时自动部署 main:
- SSH进入VPS
- 提取最新代码
- 使用以下工具重建容器
docker compose build --no-cache - 启动容器并等待健康检查
- 如果任一容器在30秒内未通过健康检查,则部署失败
所需的GitHub机密: VPS_HOST, VPS_USERNAME, VPS_SSH_KEY, VPS_SSH_PORT
这 .env VPS上的文件手动创建一次,并在部署过程中持续存在。
引擎X
反向代理配置示例:
# Portal (mcpkeys.techmavie.digital)
server {
server_name mcpkeys.techmavie.digital;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Backend stays on localhost only.
# The public /internal/resolve endpoint is served by the Next.js portal
# and proxied onward to the backend container.集 TRUST_PROXY=1 在nginx后面运行时。
数据存储
SQLite数据库路径:
- 当地:
./data/keys.db - 集装箱:
/app/data/keys.db(通过Docker卷持久化key-data)
存储的记录包括:
- 哈希API密钥(SHA-256)
- 显示前缀(
usr_XXXXXXXX...XXXX) - 连接器ID和标签
- 加密凭据(AES-256-GCM,每条记录IV)
- 用户所有权(Firebase UID)
- 使用计数器和时间戳
- 撤销状态
- 审核日志条目
原始API密钥在注册后不会存储。
安全架构
凭证存储
用户凭据从不以明文形式存储。该服务使用 分裂秘密 设计:
| 图层 | 存储内容 | 位置 |
|---|---|---|
| API密钥 | 仅SHA-256哈希 | SQLite key_hash 列 |
| 凭证 | AES-256-GCM密文 | SQLite credentials_encrypted 列 |
| 加密密钥 | KEY_ENCRYPTION_SECRET | .env VPS上的文件(从不在数据库中) |
| IV+身份验证标签 | 每条记录唯一随机12字节IV | SQLite credentials_iv 和 credentials_tag 列 |
要解密任何凭据,攻击者需要同时具备以下两个条件:
- SQLite数据库文件(位于VPS文件系统/Docker卷上)
- 这
KEY_ENCRYPTION_SECRET从.env文件
两者都没有用处——没有密钥的加密数据是无法解读的,没有数据库的密钥也无法解密任何东西。
API密钥处理
- 原始API密钥(
usr_...)生成一次,显示给用户,以及 从未存储 - 仅保留SHA-256哈希值以供查找
/internal/resolve电话 - 即使完全访问数据库,API键也无法从其哈希中反转
加密详细信息
- 算法: AES-256-GCM(经过身份验证的加密——与银行和政府系统使用的标准相同)
- 密钥大小: 256位(64个十六进制字符)
- 四、 每条记录生成唯一的随机12字节IV(防止跨条目的模式分析)
- 身份验证标签: 每条记录存储的GCM身份验证标签(检测篡改)
网络安全
- Docker端口绑定到
127.0.0.1只是——后端和门户不直接暴露在互联网上 - 后端仅保留在本地主机端口上;外部MCP服务器应在以下位置使用门户代理
https://mcpkeys.techmavie.digital/internal/resolve /internal/resolve需要每个服务器的承载令牌——每个MCP服务器都有自己的令牌- 强制连接器访问:服务器只能解析其允许的连接器的凭据
TRUST_PROXY默认为0防止伪造客户端IP
应用安全
- 所有面向用户的操作都需要Firebase身份验证
- 按以下条件筛选的Stripe webhook事件
STRIPE_PRICE_ID防止交叉产品干扰 - 管理端点需要单独的
ADMIN_API_KEY - 公共注册和轮换端点的速率受到每个IP的限制
- 管理员密钥吊销仅使用完全匹配(不使用部分前缀匹配)
操作建议
如果您自托管此服务:
- SSH访问: 仅使用基于密钥的身份验证,禁用密码登录
.env文件权限: 仅限所有者(chmod 600 .env)- 防火墙: 仅公开端口80/443(nginx)——所有服务端口应仅为localhost
- 更新: 保持Docker、Node.js和操作系统包更新以获取安全补丁
- 备份: 备份Docker卷(
key-data)以及.env分别进行--两者都需要恢复 - 代币轮换: 生成强随机令牌(
openssl rand -hex 32)为了所有的秘密
验证
烟雾测试 scripts/smoke-test.mjs 验证:
- 健康终点
- 注册页面接线
- 注册流程
- 内部解决流程
- 旋转流量
- 旧密钥失效
- 精确前缀撤销行为
- 防止伪造内部呼叫者身份
- 在以下情况下防止绕过速率限制
TRUST_PROXY=0
许可证
该项目根据 MIT许可证.
由...创建
TechMavie数字 --人工智能集成、MCP服务器开发和传输数据中间件。
