MCPHub
by FlameZerg
README.md
# MCPHub
**聚合远程 MCP 工具,按场景分发访问凭据,在自己的基础设施上管理 AI 工具入口。**
MCPHub 是一个基于 Next.js 的 Model Context Protocol 服务管理平台,将远程服务管理、工具发现、分类访问、Google 登录与调用分析放在同一个 Web 应用中。它既提供面向 MCP 客户端的统一入口,也提供供维护者管理上游服务的界面。
适合希望集中管理多个远程 MCP 服务、减少客户端重复配置,以及研究 MCP 代理与 OAuth 接入流程的开发者和自托管团队。
> 本仓库提供应用源码,不提供托管服务、共享账号、数据库或上游 API 配额。公开配置为空值或示例,需要自行准备基础设施与凭据。当前实现包含需要部署者进一步评估的安全边界,不应将开源发布视为生产安全认证。
## 导航
- [功能概览](#功能概览)
- [架构与技术栈](#架构与技术栈)
- [本地开始](#本地开始)
- [环境变量](#环境变量)
- [接入远程服务](#接入远程服务)
- [连接 MCP 客户端](#连接-mcp-客户端)
- [部署与运维](#部署与运维)
- [安全与隐私](#安全与隐私)
- [常见问题](#常见问题)
- [项目结构](#项目结构)
- [贡献与许可证](#贡献与许可证)
## 功能概览
| 能力 | 当前实现 |
| --- | --- |
| 远程服务管理 | 添加、编辑、启停远程 MCP 服务,维护分类、上游凭据与自定义请求头 |
| 工具聚合 | 发现上游工具、缓存工具元数据,通过统一 MCP 入口路由调用 |
| 远程传输 | 上游客户端包含 SSE 与 Streamable HTTP 接入实现 |
| 场景分类 | 编程开发、网络搜索、办公效率、生活服务四类远程工具分发 |
| 登录与会话 | Google OAuth 登录、Auth.js 与 PostgreSQL 数据库会话 |
| 访问凭据 | 分类长期令牌、24 小时临时令牌,以及 OAuth 授权相关令牌 |
| OAuth 接入 | 授权码、刷新令牌、PKCE 参数处理及授权服务器元数据端点 |
| 管理与观测 | 服务同步状态、调用统计、响应时间和安全事件界面 |
| 界面 | 中英文切换、亮暗主题及工具配置复制 |
| 文件输出 | 可选 R2 上传与部分工具响应中的文件路径转换 |
应用还内置数值计算、文本处理等示例工具。远程服务需要部署者自行添加;空的 `mcpconfig.json` 不代表数据库中已经配置服务,也不会自动导入任何私人服务。
分类作用于远程工具筛选,不应视为上游执行环境的安全沙箱。底层代理模块具有资源与提示词相关方法,但统一入口目前以工具聚合为主,不承诺所有 MCP 能力均被完整透传。
## 架构与技术栈
```text
浏览器管理界面 MCP 客户端
│ │
└────────── Next.js 应用 ──────────┘
登录 / 令牌 / 分类
│
MCP 代理层
┌──────┼──────┐
│ │ │
PostgreSQL KV 远程 MCP 服务
配置与会话 缓存 SSE / HTTP
│
可选 R2 文件输出
```
| 层级 | 仓库使用的技术 |
| --- | --- |
| 应用 | Next.js 15 App Router、React 19、TypeScript |
| 协议 | MCP SDK、Vercel MCP Adapter、Zod |
| 身份 | Auth.js / NextAuth v5 beta、Prisma Adapter、Google |
| 数据 | PostgreSQL、Prisma |
| 缓存 | `@vercel/kv`;MCP Adapter 另接收 `REDIS_URL` |
| 界面 | Tailwind CSS、Radix UI、Lucide、Recharts、Motion |
| 可选集成 | Cloudflare R2、缓存清理、Vercel Analytics / Speed Insights |
具体依赖与版本以 [package.json](package.json) 和对应锁文件为准。KV 的 REST 配置与 Adapter 的 Redis 连接不是同一种连接串,不能相互替代。
## 本地开始
以下命令是供部署者自行执行的操作指引,不代表已在你的环境中验证通过。
### 1. 准备依赖服务
开始前准备:
- 与当前 Next.js、Prisma 依赖兼容的 Node.js 环境和包管理器。仓库尚未通过 `engines` 固定 Node.js 版本。
- 独立的 PostgreSQL 数据库,以及可用于应用访问和结构初始化的连接信息。
- 自己的 Google OAuth Web 应用凭据。
- 使用远程工具缓存与同步时需要的 KV REST 服务地址和读写令牌。
R2、Cloudflare 缓存清理和 ModelScope 密钥按使用场景配置,无需为了启动界面而全部启用。
### 2. 配置本地环境
在项目根目录复制配置模板:
```powershell
Copy-Item .env.example .env
```
编辑 `.env`,至少替换数据库、Google OAuth、认证密钥、管理员邮箱与 Cron 密钥。使用 `.env` 是为了同时供 Next.js 与 Prisma CLI 读取;不要只把数据库配置放在 `.env.local` 后假定 Prisma 命令也能读取。
本地地址保持一致,且不带尾部斜杠:
```dotenv
AUTH_URL="http://localhost:3000"
NEXTAUTH_URL="http://localhost:3000"
CANONICAL_URL="http://localhost:3000"
```
使用本地 Node.js 生成随机密钥的示例:
```powershell
node -e "console.log(require('node:crypto').randomBytes(32).toString('base64'))"
```
将生成值写入 `AUTH_SECRET`;若同时设置兼容变量 `NEXTAUTH_SECRET`,让两者保持一致。`CRON_SECRET` 使用另一份独立随机值。不要把生成结果提交到仓库。
在 Google OAuth 应用中配置与本地地址对应的回调:
```text
http://localhost:3000/api/auth/callback/google
```
根据 Google OAuth 应用的发布状态配置允许登录的测试用户。`ADMIN_EMAIL` 目前建议填写与登录账号一致的**单个小写邮箱**;不同权限辅助函数对逗号分隔多邮箱的处理并不一致。
### 3. 安装与初始化空数据库
下面以仓库中的 npm 锁文件为例:
```powershell
npm ci
npm run db:push
```
`npm ci` 的 `postinstall` 会生成 Prisma Client。运行数据库命令前,确认 `DATABASE_URL` 与 `DIRECT_URL` 都指向你准备使用的独立数据库;数据库用户名或密码中的特殊字符需要进行连接串编码。
> `db:push` 会修改目标数据库结构,只适用于这里的全新开发数据库流程。不要对已有生产库直接照做,也不要追加 `--accept-data-loss` 来绕过警告。
当前 `prisma/migrations/` 中只有分类升级与回滚 SQL,没有完整的标准初始迁移链。`npm run db:migrate` 执行的是 `prisma migrate deploy`,不能代替首次建库。已有数据库或正式上线需要先审阅 schema、备份数据,并建立适合自身环境的迁移基线。
### 4. 启动应用
```powershell
npm run dev
```
用浏览器打开本地 `http://localhost:3000`,登录后按角色使用以下页面:
| 路径 | 用途 |
| --- | --- |
| `/` | 平台入口与导航 |
| `/mcp` | 远程服务管理界面,管理操作需要管理员权限 |
| `/tokens` | 生成与查看分类长期令牌 |
| `/mcp-verify` | 获取 24 小时临时访问配置 |
| `/analytics` | 管理员分析与安全事件界面 |
## 环境变量
完整变量模板见 [.env.example](.env.example)。模板值不是可用凭据,不能直接用于上线。
| 变量 | 配置说明 |
| --- | --- |
| `DATABASE_URL` | 应用使用的 PostgreSQL 连接;是否使用连接池参数取决于数据库服务 |
| `DIRECT_URL` | Prisma schema 指定的直连地址,用于数据库结构操作 |
| `AUTH_SECRET` / `NEXTAUTH_SECRET` | 显式设置的随机认证密钥;不要依赖源码中的缺省派生逻辑 |
| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | 自有 Google OAuth 应用凭据 |
| `ADMIN_EMAIL` | 与实际登录账号一致的单个管理员邮箱 |
| `AUTH_URL` / `NEXTAUTH_URL` / `CANONICAL_URL` | 统一的站点根地址;生产改为自己的 HTTPS 域名 |
| `AUTH_TRUST_HOST` | 代理主机信任设置;必须结合部署入口与转发头信任边界评估 |
| `ENFORCE_CANONICAL_HOST` | 设为 `true` 时,在生产模式强制跳转到规范域名 |
| `CRON_SECRET` | 定时同步等接口的鉴权密钥,上线前必须设置 |
| `KV_REST_API_URL` / `KV_REST_API_TOKEN` | 远程工具 KV 缓存与同步所用的 REST 地址及读写令牌 |
| `REDIS_URL` | 传给 MCP Adapter 的 Redis 连接;需要相关传输能力时按环境配置 |
| `MODELSCOPE_API_KEY` | ModelScope 上游服务没有单独配置密钥时使用的可选环境密钥 |
| `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ZONE_ID` | 可选的 Cloudflare 缓存清理配置 |
| `R2_ACCOUNT_ID` / `R2_ACCESS_KEY_ID` / `R2_SECRET_ACCESS_KEY` | 可选的 R2 账户与上传凭据 |
| `R2_BUCKET_NAME` / `R2_PUBLIC_DOMAIN` | R2 存储桶与实际可访问的公开域名;域名仅填主机名,不含 `https://` |
| `NEXT_PUBLIC_ENABLE_SPEED_INSIGHTS` | 控制 Speed Insights;不等于关闭所有分析采集 |
| `SKIP_DB_MIGRATION` / `SKIP_REMOTE_SYNC` | 构建后脚本开关,设为字符串 `true` 才生效,详见部署说明 |
模板中的 `PRISMA_DATABASE_URL` 供兼容性诊断参考;当前 Prisma datasource 实际使用的是 `DATABASE_URL` 与 `DIRECT_URL`。`NODE_ENV`、`VERCEL_URL`、`VERCEL_ENV` 通常由运行环境提供,不需要填入私人部署标识作为源码默认值。
## 接入远程服务
以管理员登录,在 `/mcp` 中添加自己有权限使用的远程服务。配置时需要明确服务名称、地址、传输类型,以及至少一个分类:
| 分类值 | 场景 |
| --- | --- |
| `develop` | 编程开发 |
| `search` | 网络搜索 |
| `office` | 办公效率 |
| `life` | 生活服务 |
一个服务可以归属多个分类。通过管理 API 提交时,配置结构如下;这只是示例请求体,并不会自动导入数据库:
```json
{
"name": "example-search",
"displayName": "示例搜索服务",
"url": "https://example.com/mcp",
"type": "streamable_http",
"categories": ["search"],
"enabled": true,
"timeout": 30000,
"retryAttempts": 3
}
```
请替换示例端点。需要鉴权的上游通过管理界面配置自己的 `apiKey` 或 `headers`,不要写入 README、截图或公开 JSON。远程 `type` 常用值为 `sse`、`streamable_http`;具体请求字段以管理路由实现为准。
添加后使用界面同步操作更新工具列表,并检查服务状态、工具数量和错误信息。管理 API 使用登录会话与管理员校验,MCP 调用令牌不等同于管理 API 的登录凭据。
## 连接 MCP 客户端
### 分类长期令牌
在 `/tokens` 生成令牌后,选择需要的分类,将该分类的令牌放入支持 HTTP MCP 与自定义请求头的客户端。以开发类为例:
```json
{
"mcpServers": {
"mcphub-develop": {
"url": "http://localhost:3000/mcp/mcp",
"type": "streamable_http",
"headers": {
"Authorization": "Bearer YOUR_DEVELOP_TOKEN"
}
}
}
}
```
生产使用自己的 HTTPS 域名。其他分类使用相同入口、更换对应令牌即可;客户端配置字段名称可能不同,以客户端实际支持的配置格式为准。
当前普通用户长期令牌有效期为 365 天,管理员为超长期令牌。重新生成会删除该用户此前的长期访问令牌并更新客户端密钥,因此原客户端配置需要同步替换。
### 24 小时临时令牌
在 `/mcp-verify` 获取临时令牌,使用专用请求头:
```json
{
"mcpServers": {
"mcphub-search-temp": {
"url": "http://localhost:3000/mcp/mcp",
"type": "streamable_http",
"headers": {
"TempAuthorization": "YOUR_SEARCH_TEMP_TOKEN"
}
}
}
}
```
不要在同一配置中同时发送两种鉴权头:服务端优先检查 `TempAuthorization`,显式提供的临时令牌无效时不会继续使用长期令牌。普通用户在滚动 24 小时内最多刷新 5 组临时令牌;刷新会停用之前的临时令牌。
### OAuth 客户端
源码提供下列发现与授权端点:
| 路径 | 用途 |
| --- | --- |
| `/.well-known/oauth-authorization-server` | 授权服务器元数据 |
| `/.well-known/oauth-protected-resource` | 受保护资源元数据 |
| `/api/oauth/register` | OAuth 客户端注册 |
| `/oauth/authorize` | 授权页面 |
| `/api/oauth/token` | 授权码交换与刷新令牌 |
Google 登录负责平台用户身份,以上 OAuth 端点负责 MCP 客户端授权,两者不是同一组客户端凭据。客户端兼容性、回调地址、PKCE 与资源约束需要针对具体客户端验证;这里不宣称已通过完整 OAuth 2.1 合规或互操作认证。
## 部署与运维
### 自托管与 Vercel
应用需要能运行 Next.js 服务端路由的环境,不是纯静态站点。自托管可在完成配置、数据库初始化后自行执行:
```powershell
npm run build
npm run start
```
注意 `npm run build` 会触发 npm 的 `postbuild` 生命周期,现有脚本会尝试数据库迁移,并在配置 KV 后尝试调用远程工具同步接口。构建不是纯本地、无副作用的打包操作。
仓库的 [vercel.json](vercel.json) 则指定 `pnpm run vercel-build`。使用该配置时准备与 pnpm 锁文件相匹配的工具链;不要假定它与上面的 npm 构建流程完全相同。
上线前逐项确认:
1. 在部署平台设置自己的环境变量,不上传真实 `.env`。
2. 统一三个站点地址变量,并在 Google OAuth 应用登记实际 HTTPS 回调地址。
3. 使用独立数据库、缓存与最小权限的上游凭据,预先完成数据库结构准备。
4. 核实反向代理保留必要的认证头、Host 与协议信息,且只信任受控入口设置的客户端 IP 头。
5. 在预发布环境自行完成登录、令牌生成、工具发现、调用和续期验证,再开放外网。
`SKIP_DB_MIGRATION=true` 会让 `scripts/postbuild.js` 提前退出,也跳过其中的远程同步;`SKIP_REMOTE_SYNC=true` 只跳过该脚本的同步步骤。二者都**不会**取消 `vercel-build` 命令中独立执行的 `prisma migrate deploy`,不能将它们当成全局数据库写入禁用开关。
### 定时任务与文件输出
`vercel.json` 声明每日数据库健康检查与远程工具同步任务。其他部署环境需要自行接入调度器;工具同步请求使用 `Authorization: Bearer <CRON_SECRET>`。调度配置存在不代表目标平台一定会执行,也不保证数据库结构已初始化。
R2 是可选输出通道。需要启用时,配置实际可访问的 `R2_PUBLIC_DOMAIN` 并验证存储桶访问策略;不要假定默认拼接的开发域名一定可用。上传后的 URL 可能公开访问,不能用来无审查地分发内部文件。
`cloudflare-worker.js` 是可选缓存示例,不是部署应用的必要步骤。上线时结合 `middleware.ts`、`vercel.json` 与反向代理规则逐项检查最终缓存行为,避免登录态、令牌响应或用户数据被共享缓存。
## 安全与隐私
本项目包含认证、权限检查和安全事件记录代码,但这些机制不构成“所有接口均已安全加固”的保证。公开源码与公开运行服务是两个不同的风险边界。
正式暴露服务前至少处理以下事项:
- **密钥与调度入口**:显式设置随机认证密钥与 `CRON_SECRET`。部分 Cron 路由在未设置密钥时存在放行分支,不要以缺省配置部署公网服务。
- **诊断与模拟入口**:审查 `/api/debug*`、`/api/diagnose*`、`/api/test*` 及 `/api/analytics/generate-threats`。部分接口未见登录校验,且可能写入模拟分析数据;应在生产入口禁用、隔离或进一步加固。
- **OAuth 与资源校验**:生产使用前审查重定向、PKCE、令牌受众及域名兼容分支;源码存在宽松兼容处理,不能据此假定租户或域名之间严格隔离。
- **敏感数据存储**:数据库模型保存上游 API Key、自定义请求头和访问令牌等敏感字段,不应假定这些字段已自动加密。限制数据库、备份与管理员读取权限。
- **出站访问与文件权限**:远程服务地址与响应属于外部输入。限制可连接的域名、网络和文件路径,评估 SSRF、工具权限与公开文件上传风险。
- **日志与个人数据**:应用可能记录邮箱、IP、User-Agent、调用元数据和凭据片段。审查日志、诊断响应、采集范围、保留期限与清理调度。
- **可选第三方服务**:布局包含 Vercel Analytics,另有 Speed Insights 与 IP 地理位置查询相关代码。部署前评估数据流与告知要求;关闭 Speed Insights 不会关闭所有采集。
`.gitignore` 已排除真实环境文件、常见密钥/数据库导出、旧 `site/` 构建产物及私人截图。忽略规则不清理已跟踪文件、历史提交、压缩包或手工上传内容。提交前仍需检查最终发布文件;曾泄露的凭据应撤销或轮换,而不是只删除文本。
## 常见问题
**Google 登录提示回调地址不匹配?**
检查 Google OAuth 应用登记的回调是否与实际访问域名、协议和 `/api/auth/callback/google` 完全对应。预览部署、规范域名与本机地址需要分别考虑,站点地址变量不要带尾部斜杠。
**管理员页面可见,但管理接口拒绝访问?**
将 `ADMIN_EMAIL` 配置为与实际登录账号一致的单个小写邮箱。当前不同权限辅助函数的多邮箱处理不一致,不能以某个界面的显示结果代替接口权限判断。
**数据库提示表不存在?**
核对应用与 CLI 连接的是不是同一个数据库。新开发库按初始化流程从 schema 建表;已有数据库应先制定迁移方案。构建成功或迁移步骤被跳过,不代表数据表已经齐全。
**远程工具列表为空?**
检查服务是否启用、分类是否与令牌一致、上游端点和密钥是否有效,以及 KV 配置和同步状态。`mcpconfig.json` 是空的公开配置,不是远程服务种子数据。
**客户端持续收到 401?**
确认令牌未过期或被重新生成替换,且请求头与令牌类型对应。移除失效的 `TempAuthorization`;客户端缓存了旧令牌时,需要更新配置并重新连接。
**文档站能否直接发布?**
仓库保留 MkDocs 配置和 GitHub Pages 工作流,但目前 `docs/` 不含导航中列出的全部页面。根目录 README 是当前上手入口;补齐页面和站点元数据前,不应把旧 `site/` 当作完整、最新文档发布。
## 项目结构
```text
app/ 页面、登录、OAuth 与 API 路由
mcp/ 远程服务管理及 MCP 传输入口
tokens/ 长期访问令牌界面
mcp-verify/ 临时令牌界面
analytics/ 分析界面
components/ 通用界面与工具管理组件
contexts/ 语言等客户端上下文
hooks/ 客户端状态逻辑
lib/
mcp-proxy/ 远程通信、配置、工具缓存与分类处理
analytics-db.ts 分析数据处理
security-monitor.ts 安全事件检测与记录
r2-uploader.ts 可选对象存储上传
prisma/ 数据模型及现有分类升级 SQL
scripts/postbuild.js 构建后的迁移与同步流程
docs/ 现存文档源文件
.env.example 不含真实凭据的环境模板
mcpconfig.json 空的公开 MCP 配置
```
## 贡献与许可证
欢迎通过仓库 Issues 反馈可复现问题,或提交范围清晰的 Pull Request。反馈时提供复现步骤、相关版本与脱敏后的错误信息;不要附带真实令牌、数据库连接串、管理员邮箱或私人服务 URL。
涉及凭据泄露、权限绕过或其他安全问题时,不要在公开 Issue 中发布可利用细节;如仓库已启用私密漏洞报告,优先使用该渠道,否则先向维护者询问私密联络方式。
本项目使用 [Apache License 2.0](LICENSE)。再分发时请保留适用的许可证与版权声明;仓库中已有署名不代表相关个人或组织为你的部署提供服务或安全担保。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues