返回市场
数据中心备份-MCP服务器

数据中心备份-MCP服务器

作者:riccardo-larosa0 星标更新:2025-11-15

项目介绍

Docebo MCP OAuth2 代理服务器

作为Docebo的OAuth2授权服务器代理的多租户MCP(模型上下文协议)服务器。类似于mcp.zapier.com,此服务器允许MCP客户端通过单一端点发现并验证多个Docebo租户。

功能

  • OAuth2 代理:充当授权服务器,代理到Docebo租户
  • 多租户:支持具有独立凭据的多个Docebo租户
  • RFC兼容:实现RFC 8414(授权服务器元数据)和RFC 9728(受保护资源元数据)
  • 自动发现:MCP客户端自动发现OAuth2端点
  • 无状态:不存储会话,所有状态都在OAuth参数中
  • MCP协议:最新版本2025-03-26

架构

MCP客户端(Claude、ChatGPT、MCP Inspector等)
    ↓
    ↓ 1. 发现:GET /mcp/riccardo-lr-test/.well-known/oauth-authorization-server
    ↓
mcp.docebosaas.com(此服务器)
    ↓ 返回:特定租户的端点
    ↓   授权端点:/mcp/riccardo-lr-test/oauth2/authorize
    ↓   令牌端点:/mcp/riccardo-lr-test/oauth2/token
    ↓
    ↓ 2. OAuth流程:GET /mcp/riccardo-lr-test/oauth2/authorize
    ↓ 服务器从URL路径中提取租户
    ↓ 转向:
    ↓
riccardo-lr-test.docebosaas.com/oauth2/authorize
    ↓
    ↓ 3. 用户授权,回调代码
    ↓
    ↓ 4. 令牌交换:POST /mcp/riccardo-lr-test/oauth2/token
    ↓ 服务器从URL路径中提取租户
    ↓ 使用租户配置值覆盖redirect_uri
    ↓ 注入租户凭据(client_id,client_secret)
    ↓ 代理到:
    ↓
riccardo-lr-test.docebosaas.com/oauth2/token
    ↓ 返回访问令牌
    ↓
    ↓ 5. MCP调用:POST /mcp/riccardo-lr-test
    ↓ 带有:Authorization: Bearer <token>
    ↓ 服务器调用:
    ↓
riccardo-lr-test.docebosaas.com/manage/v1/*
    ↓ 返回数据给客户端

先决条件

  • Node.js 22.x或更高版本
  • 配置了OAuth2应用的Docebo LMS实例
  • 每个租户的OAuth2客户端凭据
  • (可选)ngrok用于本地测试

安装

npm install

配置

1. 服务器配置

复制示例环境文件:

cp .env.example .env

编辑.env

# 服务器公共URL(使用ngrok URL进行本地测试)
SERVER_PUBLIC_URL=https://mcp.docebosaas.com
# 或者用于本地测试:
# SERVER_PUBLIC_URL=https://abc123.ngrok.io

PORT=3000
ALLOWED_ORIGINS=*
ALLOW_LOCAL_DEV=true

2. 租户配置

为每个Docebo租户添加凭据:

# 格式:TENANT_{UPPERCASE_TENANT_ID}_CLIENT_ID
#        TENANT_{UPPERCASE_TENANT_ID}_CLIENT_SECRET
#        TENANT_{UPPERCASE_TENANT_ID}_REDIRECT_URI

# 示例:租户 "riccardo-lr-test"
TENANT_RICCARDO_LR_TEST_CLIENT_ID=my-mcp-server
TENANT_RICCARDO_LR_TEST_CLIENT_SECRET=abc123secret...
TENANT_RICCARDO_LR_TEST_REDIRECT_URI=https://mcp.docebosaas.com/oauth/callback

# 示例:租户 "acme-corp"
TENANT_ACME_CORP_CLIENT_ID=acme-oauth-app
TENANT_ACME_CORP_CLIENT_SECRET=xyz789secret...
TENANT_ACME_CORP_REDIRECT_URI=https://mcp.docebosaas.com/oauth/callback

重要REDIRECT_URI必须与在Docebo OAuth2应用中注册的一致。服务器会在令牌交换期间用此值覆盖客户端的redirect_uri,以确保与MCP客户端兼容。

注意:租户ID格式转换:

  • URL格式:riccardo-lr-test
  • 环境变量格式:RICCARDO_LR_TEST
  • 服务器自动在两种格式之间转换

3. Docebo OAuth2 应用设置

对于每个租户,在Docebo中创建一个OAuth2应用:

  1. 登录到Docebo租户管理
  2. 进入管理菜单API & SSOAPI凭证
  3. 点击添加OAuth2应用
  4. 配置:
    • 客户端ID:选择一个名称(例如,“mcp-server”)
    • 客户端密钥:由Docebo自动生成
    • 授权类型:选择“授权码”和“刷新令牌”
    • 重定向URLhttps://mcp.docebosaas.com/callback(或您的公共URL)
    • 范围api
  5. 保存并复制客户端ID和客户端密钥
  6. 使用上述格式添加到.env文件中

动态客户端注册(DCR)-概念验证实现

⚠️ 警告:这是仅供测试的概念验证实现。不适合生产使用。

此服务器实现了虚拟DCR层,允许OAuth客户端(如MCP Inspector、ChatGPT、Claude Desktop)动态“注册”自己,即使Docebo本身不支持RFC 7591动态客户端注册。

工作原理

  1. 客户端注册:MCP客户端调用POST /mcp/<租户>/oauth2/register,携带客户端元数据
  2. 虚拟客户端创建:服务器生成一个虚拟client_id(UUID),并将映射存储在virtual-clients.txt
  3. 凭据返回:服务器返回虚拟client_idclient_secret给客户端
  4. OAuth流程:客户端在其OAuth授权/令牌请求中使用虚拟凭据
  5. 凭据翻译:服务器将虚拟凭据翻译成实际租户凭据
  6. Docebo代理:所有请求都通过实际预配置的凭据代理到Docebo

示例DCR流程

# 1. 注册新客户端
curl -X POST 'https://abc123.ngrok.io/mcp/riccardo-lr-test/oauth2/register' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_name": "我的MCP客户端",
    "redirect_uris": ["http://localhost:8080/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"]
  }'

# 响应:
{
  "client_id": "550e8400-e29b-41d4-a716-446655440000",
  "client_secret": "abc123...",
  "client_id_issued_at": 1234567890,
  ...
}

# 2. 在OAuth流程中使用虚拟client_id
# 服务器将自动翻译为实际租户凭据

存储格式

虚拟客户端映射存储在virtual-clients.txt(纯文本,已git忽略)中:

# 格式:虚拟client_id|租户id|创建时间|客户端名称|重定向URI
550e8400-e29b-41d4-a716-446655440000|riccardo-lr-test|2025-10-22T10:00:00Z|我的MCP客户端|http://localhost:8080/callback

安全限制(⚠️仅概念验证)

**不要在生产环境中使用此实现。**它存在严重的安全限制:

  • 明文存储:虚拟客户端映射存储在未加密的文本文件中
  • 无身份验证:任何人都可以注册客户端(没有API密钥,没有验证)
  • 无速率限制:易受滥用和DoS攻击
  • 无法撤销客户端:无法撤销或删除虚拟客户端
  • 无过期:虚拟客户端永久存在
  • 基于文件的存储:不适合并发访问或多服务器
  • 可预测的秘密:客户端密钥由client_id派生(HMAC-SHA256)
  • 无审计日志:无法跟踪谁注册了什么
  • 无客户端管理:没有列出、更新或删除客户端的API

生产使用

要在生产环境中使用DCR,您需要:

  1. 数据库存储(PostgreSQL、MySQL、Redis)
  2. 注册端点的身份验证(API密钥、OAuth)
  3. 速率限制和防止滥用
  4. 客户端撤销和管理API
  5. 适当的秘密存储(加密,不是派生)
  6. 所有DCR操作的审计日志
  7. 客户端过期和清理机制
  8. 访问控制(谁可以注册客户端)
  9. 监控和警报

为什么存在这个概念验证

Docebo不支持RFC 7591动态客户端注册。某些MCP客户端(如ChatGPT、Claude Desktop)可能期望支持DCR。此概念验证允许您在本地测试这些客户端,而无需修改它们,即使Docebo本身不支持DCR。

对于生产部署,请考虑:

  • 手动在Docebo中预先注册OAuth应用
  • 向MCP客户端提供静态凭据
  • 如果确实需要,实现带有数据库后端的适当DCR

开发

使用ngrok进行本地开发

  1. 启动ngrok隧道:

    ngrok http 3000
    
  2. 更新.env中的ngrok URL:

    SERVER_PUBLIC_URL=https://abc123.ngrok.io
    
  3. 启动开发服务器:

    npm run dev
    
  4. 服务器将在以下地址可用:

    • https://abc123.ngrok.io(公开)
    • http://localhost:3000(本地)

MCP客户端配置

配置MCP客户端(例如,MCP Inspector)指向您服务器的特定租户端点:

# MCP Inspector
npx @modelcontextprotocol/inspector \
  --transport http \
  --server-url https://abc123.ngrok.io/mcp/riccardo-lr-test

关键点

  • URL路径中的租户/mcp/<租户id>(非查询字符串)
  • MCP客户端将从/mcp/<租户id>/.well-known/oauth-authorization-server自动发现OAuth2端点
  • 客户端将自动处理完整的OAuth2流程
  • 每个租户都有自己的隔离MCP端点

注意:Claude Desktop目前仅支持stdio传输(不支持HTTP),因此还不能连接到此服务器。使用MCP Inspector进行测试。

API端点

所有端点都是特定于租户的,并且包含URL路径中的租户ID。

发现端点

GET /mcp/<租户id>/.well-known/oauth-authorization-server(RFC 8414)

返回特定租户的OAuth2授权服务器元数据:

{
  "issuer": "https://mcp.docebosaas.com/mcp/riccardo-lr-test",
  "authorization_endpoint": "https://mcp.docebosaas.com/mcp/riccardo-lr-test/oauth2/authorize",
  "token_endpoint": "https://mcp.docebosaas.com/mcp/riccardo-lr-test/oauth2/token",
  "scopes_supported": ["api"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token", "password"],
  "code_challenge_methods_supported": ["S256"]
}

GET /mcp/<租户id>/.well-known/oauth-protected-resource(RFC 9728)

返回特定租户的受保护资源元数据:

{
  "resource": "https://mcp.docebosaas.com/mcp/riccardo-lr-test",
  "authorization_servers": ["https://mcp.docebosaas.com/mcp/-riccardo-lr-test"]
}

OAuth2端点

GET /mcp/<租户id>/oauth2/authorize

代理OAuth2授权请求到Docebo租户。

参数

  • 标准OAuth2参数:client_idresponse_typeredirect_uriscopestatecode_challenge
  • 从URL路径中提取租户ID(非查询字符串)

流程

  1. 服务器从URL路径中提取租户
  2. 转向https://{租户}.docebosaas.com/oauth2/authorize
  3. 用户在Docebo中授权
  4. Docebo带授权code回传

POST /mcp/<租户id>/oauth2/token

代理OAuth2令牌请求到Docebo租户。

正文参数(application/x-www-form-urlencoded):

  • grant_typeauthorization_coderefresh_tokenpassword
  • code:授权码(对于authorization_code授权)
  • redirect_uri:客户端的重定向URI(服务器用租户配置值覆盖)
  • code_verifier:PKCE验证器(可选)
  • 其他授权特定参数

流程

  1. 服务器从URL路径中提取租户
  2. 使用租户配置值覆盖redirect_uri
  3. 注入租户的client_idclient_secret
  4. 代理到https://{租户}.docebosaas.com/oauth2/token
  5. 将令牌响应返回给客户端

重要:服务器自动用租户配置的REDIRECT_URI覆盖redirect_uri参数,以确保与Docebo注册一致。

MCP端点

POST /mcp/<租户id>

特定租户的MCP JSON-RPC端点。

头信息

  • Authorization: Bearer <access_token>
  • Content-Type: application/json

示例请求

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "docebo.list_users",
    "arguments": {
      "page_size": 10
    }
  }
}

MCP工具

docebo.list_users

列出Docebo LMS中的用户。

参数

参数类型描述
pagenumber页码(从1开始)
page_sizenumber每页用户数(默认:200,最大:200)
sort_attrstring排序属性(例如,“user_id”,“username”)
sort_dirstring排序方向:“asc”或“desc”
search_textstring用户名或电子邮件搜索过滤器

测试

测试发现端点

curl https://abc123.ngrok.io/.well-known/oauth-authorization-server | jq .

测试OAuth2流程(手动)

  1. 测试发现端点

    curl https://abc123.ngrok.io/mcp/riccardo-lr-test/.well-known/oauth-authorization-server | jq .
    
  2. 启动授权(将此URL粘贴到浏览器中):

    https://abc123.ngrok.io/mcp/riccardo-lr-test/oauth2/authorize?client_id=test&response_type=code&redirect_uri=https://abc123.ngrok.io/oauth/callback&scope=api&code_challenge=CHALLENGE&code_challenge_method=S256
    
  3. 交换授权码获取令牌(授权后):

    curl -X POST https://abc123.ngrok.io/mcp/riccardo-lr-test/oauth2/token \
      -H 'Content-Type: application/x-www-form-urlencoded' \
      -d "grant_type=authorization_code" \
      -d "code=<授权码>" \
      -d "code_verifier=<验证器>" \
      -d "redirect_uri=https://abc123.ngrok.io/oauth/callback"
    
  4. 调用MCP端点

    TOKEN="<步骤3中的访问令牌>"
    
    curl -X POST "https://abc123.ngrok.io/mcp/riccardo-lr-test" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
          "name": "docebo.list_users",
          "arguments": {"page_size": 5}
        }
      }'
    

生产部署

环境变量

SERVER_PUBLIC_URL=https://mcp.docebosaas.com
PORT=3000
ALLOWED_ORIGINS=*
ALLOW_LOCAL_DEV=false

# 添加所有租户凭据
TENANT_<ID>_CLIENT_ID=...
TENANT_<ID>_CLIENT_SECRET=...

构建和运行

npm run build
npm start

部署检查表

  • 设置ALLOW_LOCAL_DEV=false
  • 使用HTTPS(OAuth2所需)
  • [ ]