Dataverse集成服务

Dataverse集成服务实现了ChatGPT与Microsoft Dataverse之间的OAuth认证和API流集成,支持多种数据操作和工具调用。

  • by BharathVyaas
  • JavaScript
  • 本地部署
  • 更新于
在 GitHub 查看 BharathVyaas/MCP-Test

使用说明

WBMCP集成规范

本文档仅描述了此存储库中实现的ChatGPT<->OAuth<->MCP<->的SOAP集成设计。 它有意关注身份、协议、工具、权限和API流。

1) 整合参与者

  1. ChatGPT连接器运行时
  2. 此MCP服务器(/mcp、OAuth元数据、OAuth代理端点)
  3. 微软Entra应用程序: ChatGPT-MCP-Client (公共客户端/PKC的SPA)
  4. 微软Entra应用程序: MCP-Dataverse-Service (海外建筑运营管理局保密服务应用程序)
  5. Dataverse Web API(https://<org>.crm*.dynamics.com/api/data/v9.2)

Entra应用程序之间的角色划分:

  • ChatGPT-MCP-Client ChatGPT在授权码+PKCE登录/同意期间使用。
  • MCP-Dataverse-Service 此服务器使用它来代表登录用户执行OBO和调用Webex。

2) 端到端流程

ChatGPT -> MCP /.well-known/*                (discover OAuth + MCP metadata)
ChatGPT -> MCP /register                     (DCR shim -> fixed client_id)
ChatGPT -> MCP /oauth/authorize              (proxy to Entra authorize endpoint)
Entra   -> ChatGPT redirect_uri?code=...     (user login + consent complete)
ChatGPT -> MCP /oauth/token                  (proxy token redemption to Entra)
ChatGPT -> MCP /mcp (Bearer access token)    (MCP initialize + tool calls)
MCP     -> Entra /token (OBO)                (assertion=inbound token)
MCP     -> Dataverse Web API                 (tool-specific operation)
MCP     -> ChatGPT                            (JSON-RPC tool result)

3) OAuth和注册界面

GET /.well-known/oauth-protected-resource

返回MCP保护的资源元数据:

  • resource
  • authorization_servers
  • scopes_supported (包括 MCP_SCOPE, offline_access)

GET /.well-known/oauth-protected-resource/mcp

特定于资源的别名为返回相同的元数据形状 /mcp.

GET /.well-known/oauth-authorization-server

GET /.well-known/openid-configuration

返回ChatGPT使用的授权服务器元数据:

  • issuer
  • authorization_endpoint -> /oauth/authorize
  • token_endpoint -> /oauth/token
  • registration_endpoint -> /register
  • jwks_uri ->Entra密钥端点
  • 授权/响应方法和范围

GET /oauth/authorize

Entra授权端点的代理:

  • 复制传入的查询参数
  • 移除 resource 参数(Entra v2不兼容)
  • 通过重定向到Entra授权URL进行响应

POST /oauth/token

Entra令牌端点的代理:

  • 接受 application/x-www-form-urlencoded
  • 删除传入 resource
  • 将表单体转发到Entra令牌端点
  • 将Entra状态/正文/内容类型转发回呼叫者

GET|POST /register

动态客户端注册垫片:

  • Entra不支持此用例的RFC7591 DCR
  • 服务器返回ChatGPT的预配置客户端记录
  • 用途 CHATGPT_CLIENT_ID,可选 CHATGPT_CLIENT_SECRET

4) MCP端点行为

POST /mcp

使用JSON响应模式的MCP流式HTTP端点。

身份验证门:

  • 如果 MCP_REQUIRE_AUTH=1,请求必须包括 Authorization: Bearer <token>
  • 如果缺少令牌,服务器将返回 401 随着 WWW-Authenticate 挑战包含 resource_metadata

会话模型:

  • 无状态模式 MCP_STATELESS=1 (或 VERCEL 设置)
  • 状态模式否则为 mcp-session-id 运输地图
  • 捕获入站承载令牌并将其传递给OBO的工具执行

GET /mcp 和 DELETE /mcp

总是 405 Method Not Allowed.

5) WAXTool模型(GPT可以做什么)

工具在中明确声明 src/mcp/server.js 通过 server.registerTool(...). 只有这些工具暴露于GPT:

基本操作

  1. dataverse_whoami
  • Webex呼叫: GET WhoAmI()
  • 目的:验证令牌和身份上下文
  1. dataverse_list_tables
  • Webex呼叫: GET EntityDefinitions?$select=...
  • 适用于 customOnly, logicalNameContains, top 在服务器代码中过滤
  1. dataverse_create_table
  • Webex呼叫: POST EntityDefinitions
  • 可选发布步骤: POST PublishAllXml
  1. dataverse_list_rows
  • Webex呼叫: GET /<entitySet>?$select&$filter&$orderby&$expand&$top&$count
  1. dataverse_get_row
  • Webex呼叫: GET /<entitySet>(<guid>)
  1. dataverse_create_row
  • Webex呼叫: POST /<entitySet>
  1. dataverse_update_row
  • Webex呼叫: PATCH /<entitySet>(<guid>)
  1. dataverse_delete_row
  • Webex呼叫: DELETE /<entitySet>(<guid>)

高级操作

  1. dataverse_fetch_xml
  • Webex呼叫: GET /<entitySet>?fetchXml=...
  • 目的:执行复杂的聚合和多表连接。
  1. dataverse_execute_action
  • Webex呼叫: POST /<actionName>
  • 目的:触发未绑定的WAXActions或自定义API。
  1. dataverse_list_relationships
  • Webex呼叫: GET /EntityDefinitions(LogicalName='...')?$expand=ManyToManyRelationships...
  • 目的:帮助LLM发现父表和子表是如何链接的。
  1. dataverse_global_search
  • Webex呼叫: POST /search
  • 目的:跨索引表执行全局文本搜索。
  1. dataverse_create_mda (实验)
  • Rubycall:多次调用 appmodules 和 AddAppComponents
  • 目的:生成一个新的模型驱动应用程序界面,其中包含所请求的表。

6) 工具响应合同

所有工具都返回具有文本和结构化有效负载的MCP兼容响应对象。

成功形状:

{
  "content": [{ "type": "text", "text": "{ ...pretty JSON... }" }],
  "structuredContent": { "...": "..." }
}

错误形状:

{
  "isError": true,
  "content": [{ "type": "text", "text": "Error message" }]
}

BLOB调用包装器返回:

  • status:来自BLOB的HTTP状态
  • data:解析的JSON(或文本回退)
  • etag:响应 etag 标题(如果存在)
  • entityId:响应 odata-entityid 标题(如果存在)

7) OBO(代表)代币交易所

每次工具执行都会使用入站ChatGPT承载令牌执行OBO:

  • 端点: https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
  • 赠款: urn:ietf:params:oauth:grant-type:jwt-bearer
  • requested_token_use=on_behalf_of
  • assertion=<inbound bearer token>
  • scope=<DATAVERSE_SCOPE>

这将生成用于Dataverse Web API调用的Dataverse访问令牌。

8) 环境变量及其使用位置

整合 .env 合同(应该存在什么)

PUBLIC_BASE_URL=https://your-mcp-domain.example.com
AZURE_TENANT_ID=<tenant-guid>
CHATGPT_CLIENT_ID=<chatgpt-mcp-client-app-id>
MCP_SERVICE_APP_ID=<mcp-dataverse-service-app-id>
MCP_SERVICE_APP_CLIENT_SECRET=<service-app-secret-value>
MCP_SCOPE=api://<mcp-dataverse-service-app-id>/mcp.access
DATAVERSE_URL=https://<org>.crm8.dynamics.com
DATAVERSE_SCOPE=https://<org>.crm8.dynamics.com/user_impersonation
DATAVERSE_API_VERSION=v9.2
MCP_REQUIRE_AUTH=1
MCP_STATELESS=1

秘密笔记:

  • MCP_SERVICE_APP_CLIENT_SECRET 一定是秘密 价值,不是秘密ID。
  • 代码中的秘密回退顺序为:
    • MCP_SERVICE_APP_CLIENT_SECRET
    • MCP_SERVICE_CLIENT_SECRET
    • AZURE_CLIENT_SECRET

核心OAuth/MCP(src/index.js)

  • PUBLIC_BASE_URL:元数据端点和挑战中使用的规范库
  • AZURE_TENANT_ID:构建Entra授权/令牌/JWKS端点
  • MCP_SERVICE_APP_ID:的默认来源 MCP_SCOPE
  • MCP_SCOPE:OAuth元数据和资源元数据中公开的作用域
  • CHATGPT_CLIENT_ID:返回者 /register
  • CHATGPT_CLIENT_SECRET:可选;将DCR身份验证方法更改为 client_secret_post
  • CHATGPT_REDIRECT_URIS:返回者 /register
  • MCP_REQUIRE_AUTH:强制执行持票人要求 /mcp
  • OAUTH_DEBUG:日志 /oauth/token 请求/响应详细信息
  • OAUTH_TOKEN_ORIGIN:覆盖默认转发 Origin 到Entra令牌端点

网络日志/OBO(src/mcp/server.js)

  • AZURE_TENANT_ID:OBO令牌端点租户
  • MCP_SERVICE_APP_ID型号:OBO client_id
  • MCP_SERVICE_APP_CLIENT_SECRET型号:OBO client_secret 主要的,重要的
  • MCP_SERVICE_CLIENT_SECRET:回退秘密变量
  • AZURE_CLIENT_SECRET:回退秘密变量
  • DATAVERSE_URL:基本数据库URL
  • DATAVERSE_SCOPE:目标OBO范围;默认 <DATAVERSE_URL>/user_impersonation
  • DATAVERSE_API_VERSION:默认为 v9.2
  • DATAVERSE_DEBUG:记录Webex请求成功的详细信息

运输/安保(src/index.js, src/auth.js, src/mcp/mountMcp.js)

  • MCP_STATELESS:无状态传输模式切换
  • VERCEL:自动启用无状态模式(如果存在)
  • MCP_API_KEY:非承载呼叫者的可选x-api-key检查
  • ALLOWED_ORIGINS:可选的原产地列表 /mcp (无记名)
  • CORS_ALLOWED_ORIGINS:CORS响应策略
  • CORS_ALLOW_CREDENTIALS:CORS凭据行为
  • ALLOWED_HOSTS:主机标头允许列表
  • RENDER_EXTERNAL_HOSTNAME:可选主机分配列表输入
  • BIND_PUBLIC:强制公共绑定模式

遗留标志(不属于BLOB集成)

  • ENABLE_CATS_API
  • REQUIRE_DB_ON_STARTUP

9) GPT权限是如何声明的

GPT可用的权限受两层限制:

  1. OAuth作用域层
  • 通过暴露 .well-known 元数据(MCP_SCOPE)
  • Entra为此作用域铸造的访问令牌
  1. 工具暴露层
  • 仅限在中注册的工具 buildMcpServer() 可调用
  • 不存在通用的、任意的WAXpassthrough工具
  • Zod输入模式定义了可接受的参数和形状

实际效果:

  • GPT只能执行显式注册的功能
  • GPT无法访问未表示为工具的端点或操作

10) 请求验证和安全控制

  1. 主机标头验证
  • createMcpExpressApp(...) 随着 allowedHosts 配置时
  1. CORS策略
  • 在路由处理程序之前全局应用
  • 支持飞行前(OPTIONS -> 204)
  1. MCP认证挑战
  • 在缺少载体时,服务器返回 WWW-Authenticate 随着 resource_metadata 统一资源定位符
  1. 可选的x-api-key回退
  • 仅在以下情况下对非承载呼叫者强制执行 MCP_API_KEY 已设置
  1. 元数据端点强化
  • /oauth/authorize 条带 resource 参数
  • /oauth/token 条带 resource 并安全地前进

11) 错误源指南

  1. Missing required environment variables: ...
  • 在OBO调用之前由Rubyconfig guard触发
  1. Dataverse OBO token exchange failed (...)
  • 服务应用程序凭据/作用域/租户配置错误
  1. Dataverse API failed (400/401/403/...)
  • LOX请求/权限/架构错误
  1. Bad Request: No valid session ID provided
  • 状态模式跟踪呼叫丢失 mcp-session-id
  1. unauthorized 上 /mcp
  • MCP_REQUIRE_AUTH=1 不记名代币丢失

12) 传统曲面

遗产 /api/cats 端点保留在代码中,默认情况下被禁用。 它们不属于此JOIN集成合同的一部分。