MCP托管平台
Ubuntu EC2的多租户MCP托管控制平面:
- 公共URL模式:
${PUBLIC_BASE_URL}/mcp/{UNIQUE_SOLUTION} - 每个MCP的内部端口(默认池
30001-30200) - 平台认证(
X-API-Key或持有人),加上可选的浏览器电子邮件/密码登录以访问仪表板 - Postgres-based注册表+管理员API+健康检查程序+仪表板
- Redis/BullMQ配置队列+Docker支持的运行时工作器
- OIDC/JWT认证+RBAC(
admin,publisher,viewer)+审计日志 - 定额计量(
request_counters)每分钟/每天执行 - Prometheus指标+结构化日志+可选的OpenTetry跟踪
- 通过AWS SSM/Secrets Manager进行秘密引用(
commandEnvSecrets) - 根据MCP具有身份验证要求的公共注册表和元数据端点
- Nginx反向代理配置已针对类似HTTP/SSE的流式响应进行了优化
建筑
flowchart TB
User[Cursor / Agent] --> Proxy[Nginx reverse proxy]
Proxy --> Platform[MCP Platform service]
Platform --> Registry[(Postgres registry)]
Platform --> Backends[MCP backend services by internal ports]
Platform --> Dash[Dashboard + index]快速入门(本地)
- 安装依赖项:
- npm install
- 启动平台:
- npm run start
- 打开:
- http://127.0.0.1:8080/dashboard - http://127.0.0.1:8080/mcp/index.json
- 注册示例后端:
- POST /admin/servers 带有id echo,目标 http://127.0.0.1:30001 - 从以下内容开始 POST /admin/servers/echo/start
环境变量
PORT(默认值8080)HOST(默认值0.0.0.0)PUBLIC_BASE_URL代码段/索引中显示的公共基础URLPLATFORM_AUTH_DESCRIPTION平台身份验证指南如所示/registryPLATFORM_SIGNUP_URL用户访问平台的可选链接PLATFORM_API_KEYS平台身份验证的逗号分隔键WEB_ADMIN_EMAIL可选的浏览器登录电子邮件/dashboardWEB_ADMIN_PASSWORD的可选浏览器登录密码/dashboardWEB_SESSION_COOKIE_NAME浏览器登录的会话cookie名称(mcp_session默认)WEB_SESSION_TTL_MS浏览器会话生存期(毫秒)(默认为12小时)JWT_ISSUER预期JWT发行人JWT_AUDIENCE预计JWT观众JWT_JWKS_URIOIDC JWKS端点(用于RS256/ES256验证)JWT_HS256_SECRETHS256令牌的共享密钥替代方案JWT_ROLES_CLAIM包含用户角色的声明名称(默认roles)DATABASE_URLPostgres连接URLREDIS_URL配置队列的Redis连接URLPROVISIONING_QUEUE_NAMEBullMQ队列名称IMPORT_JOB_TIMEOUT_MS超时import-repo作业(默认600000)IMPORT_FETCH_TIMEOUT_MS每个尝试分支的GitHub tarball下载超时(45000默认)IMPORT_FETCH_STREAM_TIMEOUT_MStarball体流不活动超时(45000默认)IMPORT_FETCH_TOTAL_TIMEOUT_MS硬帽,用于完整的tarball下载持续时间(180000默认)IMPORT_FETCH_MAX_BYTEStarball大小的硬上限(以字节为单位)(262144000默认值=250MB)GITHUB_TOKEN回购导入期间API利率上限更高的可选GitHub代币DOCKER_SOCKETworker的Docker套接字路径(/var/run/docker.sock)DOCKER_NETWORK已推出MCP集装箱的集装箱网络模式DOCKER_IMAGE_PULL是否在开始前拉取图像REQUESTS_PER_MINUTE_PER_SUB每位租户+主题分钟配额REQUESTS_PER_DAY_PER_SUB每位租户+主题日配额IMPORT_REQUESTS_PER_MINUTE每个主题的导入请求速率限制(5违约,0禁用)LOG_LEVEL结构化日志级别(info默认情况下)OTEL_ENABLED启用OpenTetry(true/false)OTEL_EXPORTER_OTLP_ENDPOINTOTLP导出器端点AWS_REGIONSSM/秘密管理器秘密解析区域POSTGRES_DB/POSTGRES_USER/POSTGRES_PASSWORD(组成默认值)PORT_MIN/PORT_MAX内部端口分配范围HEALTH_INTERVAL_MS定期健康检查间隔
核心终点
GET /health整体平台状态GET /metricsPrometheus指标端点GET /mcp/index.json托管MCP的公共索引GET /mcp/:serverId/meta.json一个MCP的公共元数据(auth-docs+代码段)GET /registry带有身份验证要求和代码段的公共HTML注册表GET /dashboard托管MCP列表+可复制的MCP.json代码段GET /login仪表板会话身份验证的浏览器登录页面GET /api/servers经过身份验证的服务器列表GET /api/auth/whoami检查当前令牌的已解决主题/角色GET /api/audit-logs最近的管理员审核事件(admin角色)GET /api/provisioning-jobs最近排队的启动/停止作业GET /api/import-jobs最近的GitHub导入作业GET /api/import-jobs/:id导入作业状态/结果以进行轮询GET /api/usage/current?serverId=...受试者的当前分钟/天计数器(admin角色)GET /api/usage/summary聚合每台服务器的分钟/天使用率+运行状况和24小时作业计数(publisher/admin)GET /api/analytics/summary?hours=24请求事件分析摘要(参与者、租户、IP、延迟、错误率)GET /api/analytics/top-servers?hours=24&limit=10按请求量和质量列出的顶级MCP路由POST /admin/servers创建并注册MCP服务器POST /admin/import-repo将GitHub仓库导入排队(githubUrl,可选branch/subdir/serverId,autoStart)PATCH /admin/servers/:id更新元数据/标头策略DELETE /admin/servers/:id删除服务器POST /admin/servers/:id/start启动托管进程POST /admin/servers/:id/stop停止管理进程POST /admin/servers/:id/restart重新启动服务器({ "recreate": true, "forcePull": false }支持)POST /admin/analytics/retention清理旧请求事件(admin角色、身体{ "days": 30 })ALL /mcp/:serverId和ALL /mcp/:serverId/*代理MCP呼叫GET /dashboard包括GitHub导入、服务器操作(启动/停止/删除)、代码段和可折叠作业/审核部分
公共注册和授权要求
- 访问
GET /registry获取托管MCP的公共列表。 - 平台级身份验证指南来自:
- PLATFORM_AUTH_DESCRIPTION - PLATFORM_SIGNUP_URL (可选)
- 每个MCP身份验证详细信息来自每个服务器定义:
- requiredHeaders - authType - authInstructions - docsUrl - signupUrl
- 对于每台服务器的深度链接,请使用
GET /mcp/:serverId/meta.json.
添加新的托管MCP
使用管理员端点(或 scripts/register-server.ps1):
.\scripts\register-server.ps1 `
-Id "n8n" `
-Name "n8n MCP" `
-Description "Hosted n8n MCP endpoint" `
-TargetUrl "http://127.0.0.1:30020" `
-RequiredHeaders @("Authorization") `
-ForwardHeaders @("authorization","x-tenant-id") `
-ApiKey "
"如果满足以下条件,平台将分配内部端口 TargetUrl / internalPort 省略。
光标 mcp.json 示例
看 examples/cursor.mcp.json:
{
"mcpServers": {
"echoHosted": {
"url": "https://mcp.your-real-domain.com/mcp/echo",
"headers": {
"X-API-Key": "
",
"Authorization": "Bearer "
}
}
}
}测试和验证托管MCP身份
使用此顺序以避免 401 Unauthorized 验证托管MCP时:
- 首先需要平台身份验证 为了
/mcp/:serverId:
- X-API-Key: 或 - Authorization: Bearer 或 - 浏览器会话cookie来自 /login
- 上游身份验证是独立的 如果需要,应转发到MCP后端(例如
Authorization: Bearer和x-portfolio-id). - 在
/dashboard:
- 填充 仪表板请求身份验证 (可选API密钥/承载器)。 - 按服务器设置 测试/发现标头JSON 您的MCP使用的上游集管。 - 点击 测试连接 运行一个 initialize 请求通过 /mcp/:serverId 并验证端到端身份验证。 - 点击 发现工具 跑 initialize + tools/list 使用相同的测试头直接对抗目标MCP。
- 对于外部客户端(Cursor、Trimble Agent Studio等),始终在客户端配置中包含平台身份验证标头。如果MCP需要,包括上游集管。
部署(Ubuntu EC2)
选项A:Docker编写
- 将仓库复制到
/opt/mcp-servers. - 复制
.env.example到.env并设置实际值:
- PUBLIC_BASE_URL=https://mcp.your-real-domain.com - DATABASE_URL=postgres://postgres:postgres@postgres:5432/mcp_hosting - PLATFORM_API_KEYS=key1,key2
- 运行:
- docker compose up -d --build
- 可选的旧版导入:
- npm run migrate:json -- ./data/servers.json
- Nginx配置:
- deploy/nginx/nginx.conf - deploy/nginx/conf.d/mcp-platform.conf
- 在中添加证书
deploy/nginx/certs(或在主机和挂载证书路径上使用certbot)。
这将启动:
mcp-platform(API/网关)mcp-worker(为MCP服务器启动/停止Docker容器的队列工作器)postgres(注册表+审计+作业记录)redis(队列代理)nginx(边缘代理)
注册服务器时:
command应该是Docker镜像(例如。ghcr.io/your-org/my-mcp:latest)commandArgs作为容器传递CmdcommandEnv变为容器环境变量(加号PORT)commandEnvSecrets支持秘密引用:
- ssm:///path/to/parameter - secretsmanager://secret-id - secretsmanager://secret-id#jsonKey
authType可以是bearer,api_key,oauth,或customauthInstructions告诉用户如何获取凭证和格式头docsUrl和signupUrl公开展示于/registry和/mcp/index.json- start/stop是异步的并返回
queuedJobId
选项B:systemd+主机nginx
- 复制服务文件
deploy/systemd/mcp-platform.service到/etc/systemd/system/.
- 也复制 deploy/systemd/mcp-worker.service 用于异步配置。
- 添加env文件
/etc/mcp-platform.env:
- PLATFORM_API_KEYS=... - REDIS_URL=redis://127.0.0.1:6379 - DATABASE_URL=postgres://...
- 启动服务:
- sudo systemctl daemon-reload - sudo systemctl enable --now mcp-platform - sudo systemctl enable --now mcp-worker
- 从以下位置应用nginx vhost
deploy/systemd/nginx-mcp.conf.example.
安全/操作检查表
- 保持MCP后端绑定到
127.0.0.1或仅限专用网络。 - 在边缘使用HTTPS,旋转密钥并记录请求ID。
- 在Nginx或网关上使用每路径/每密钥速率限制。
- 保持转发策略的一致性,以避免凭据泄漏。
- 在扩展到100-200台服务器之前,添加中央日志+指标。
Auth+RBAC快速设置
角色从JWT声明中读取(默认声明: roles):
viewer:可以浏览仪表板并使用托管的MCP路由publisher:可以创建/更新/启动/停止MCP服务器admin:完全控制,包括删除+审核日志
示例 .env OIDC/JWKS验证:
JWT_ISSUER=https://YOUR_AUTH_DOMAIN/
JWT_AUDIENCE=mcp-platform-api
JWT_JWKS_URI=https://YOUR_AUTH_DOMAIN/.well-known/jwks.json
JWT_ROLES_CLAIM=roles仅用于本地测试,您仍然可以使用 PLATFORM_API_KEYS 退路。
浏览器登录(可选)可以通过以下方式启用:
WEB_ADMIN_EMAIL=charles_forey@trimble.com
WEB_ADMIN_PASSWORD=replace-me配置后,浏览器访问 /dashboard* 重定向到 /login 登录后接收HttpOnly会话cookie。 将Nginx设置为代理两者 /dashboard 和 /login (加 /logout)到平台服务,并重定向 / 到 /dashboard.
GitOps入职培训
将MCP定义存储在 servers/*.yaml.
- 在本地验证清单:
- npm run gitops:validate
- 向平台API提交清单:
- ADMIN_API_BASE_URL=https://mcp.your-real-domain.com ADMIN_API_KEY=... npm run gitops:submit
- CI工作流程:
- .github/workflows/gitops-onboarding.yml - PR验证清单 - 推至 main 验证后将清单提交给 /admin/servers
请参阅示例清单: servers/example-echo.yaml.
队列+Docker运行时说明
POST /admin/servers/:id/start和POST /admin/servers/:id/stop现在回来202随着queuedJobId.- Worker消耗队列作业并管理名为的容器
mcp-server-{id}. - 检查进度
GET /api/provisioning-jobs. - 对于GitHub摄取流,请调用
POST /admin/import-repo和投票GET /api/import-jobs/:id直到completed/failed. - 导入管道具有弹性:它首先尝试存储库
Dockerfile如果存在,并在repo Docker构建失败时自动重试生成的运行时Dockerfile。 - 如果在repo根目录中找不到运行时文件,import还会自动检测可能嵌套的子目录(用于单repo样式布局),并从那里继续。
- 配置/导入队列作业现在使用唯一的ID(基于UUID),以避免Redis重启后出现过时的状态/结果冲突。
操作和扩展
- API/代理节点是无状态的;在负载平衡器后面水平缩放。
- 共享州居住在Postgres(
servers、作业、审计、请求计数器)和Redis(BullMQ队列)。 - 运行多个worker(
npm run worker)以获得更高的启动/停止/导入吞吐量。 - 随着API/工作副本计数的增长,请使用连接池(例如PgBouncer)。
- 定期备份Postgres,并记录您环境的恢复过程。
- 保持队列/作业表有界(定期清理旧表
provisioning_jobs/import_jobs行)。 - 定期清理未使用的本地Docker镜像,以恢复工作主机上的磁盘。
- 服务器删除流程为:
POST /admin/servers/:id/stop(可选)然后DELETE /admin/servers/:id.
分析、警报和保留
- 代理现在将每个请求的事件写入Postgres(
request_events)包含服务器id、租户id、参与者子、客户端IP、状态代码、路径和延迟。 - Prometheus现在包括每服务器代理延迟直方图和每服务器状态代码计数器:
- mcp_platform_mcp_proxy_latency_ms{server_id,status_code} - mcp_platform_mcp_proxy_status_code_total{server_id,status_code}
- 仪表板包括一个分析块,用于:
- 请求量 - p95潜伏期 - 错误率 - 独特的演员/租户/IP - 按流量划分的顶级服务器
- 建议的Grafana面板:
- 请求/秒 server_id - p95潜伏期 server_id - 4xx/5xx费率 server_id - 随时间变化的活动流 - 顶级演员/租户(来自 /api/analytics/summary)
- 建议警报:
- p95潜伏期>2000ms,持续5m - 5m误差率>5% - 10m内服务器不健康大于0 - 身份验证失败峰值>基线
- 保留:
- 跑 POST /admin/analytics/retention 随着 {"days":30} 每日(cron/作业调度程序) - 保持高基数原始事件比聚合计数器短
冒烟测试
在本地运行烟雾检查:
npm test对已部署的实例运行:
BASE_URL=https://mcp.your-real-domain.com API_KEY=
MCP_SERVER_ID=echo node scripts/smoke-test.jsMCP_SERVER_ID 是可选的;设置后,烟雾测试还会检查MCP代理路径,并断言它不会返回 502.
