Skip to main content
插件原生 MCP 工具让插件只实现一次业务方法,再由 Xpert 自动适配为 Agent Middleware Tool、MCP Tool,或同时暴露到两个调用面。插件不需要创建 stdio MCP Server;Xpert 通过受管的 MCP Server 负责能力发现、Streamable HTTP、鉴权、策略、审计和启停。

何时使用

一个 @XpertToolProvider() 类对应一个独立管理的 MCP 服务。一个插件可以注册多个 Provider 类;每个 Provider 都有自己的 Tool 集合、启用状态、Publication、端点和客户端配置。安全边界、生命周期或用途明显不同的能力,应拆成不同 Provider 类。一个 Provider 内声明的多个 Middleware 分组不会自动变成多个 MCP 服务。

工作原理

插件加载器只注册业务类一次。宿主读取类和方法上的元数据,验证名称、Schema、行为与上下文声明,然后展开出:
  • 一个原生 Toolset Provider;
  • 每个已声明分组对应的 Agent Middleware Strategy;
  • 每个启用 MCP 的方法对应的 MCP Tool definition;
  • 每个已声明 App 对应的 Resource 型 MCP App definition;
  • 一个运行时发现的虚拟 TOOLSET 插件组件。
运行时装饰器定义是执行契约的权威来源。无需在 .xpertai-plugin/plugin.json 中重复声明 toolsets 公开端点身份由宿主管理。平台根据插件 artifactNamespace、Provider key 和归属作用域派生稳定的 Publication slug。不要把某个客户端产品名称写入 Provider key、展示名称、文档或端点。旧的 slug 选项只是已弃用的展示提示,不能作为端点契约。

前置条件

插件需要使用兼容且实际提供本文 API 的 @xpert-ai/plugin-sdk@xpert-ai/contracts。尤其应确认已安装 SDK 包含 defineMcpAppXpertToolProviderOptions.appsXpertMcpToolOptions.app,宿主适配器也支持这些声明。支持早期手写原生 definitions 的版本,不一定支持装饰器 App 绑定。本地 SDK 构建或 tarball 验证不代表相同 API 已经发布到 npm。 业务输入和输出必须使用 zod/v3 的严格对象 Schema。MCP Tool 必须同时声明 inputSchemaoutputSchema

定义业务 Tool Provider

下面的 Provider 将同一个读取操作暴露到 Agent Middleware 和 MCP,并为结果绑定一个可选交互式 App。OrderService 是已有的类型化业务服务;增加 App 不改变业务 handler:

Tool 暴露组合

mcp 必须显式配置。宿主不会根据 TypeScript 类型或方法名自动猜测协议 Schema、风险或可见性。

为已有 Tool 绑定 MCP App

示例仍然只有 1 个 Toolorders_searchorders_search_appApp 资源,不是第二个可调用工具。App 为已有 Tool 校验后的 DTO 提供界面,不需要再增加业务方法、Provider 或 stdio Server。 App key 必须在 Provider 内唯一,Tool 引用的 App 必须由同一 Provider 声明。供模型与 iframe 共用的入口 Tool 应显式使用 visibility: ["model", "app"];App 绑定存在而省略可见性时,默认也是这两项,显式排除 app 会校验失败。只有真正的 iframe 专用 Tool 才使用 ["app"]

构建与交付 App

将前端源码与业务 handler 分开:
尽量把 JS、CSS 内联为自包含 HTML。entry 相对已安装插件根目录,必须存在于实际打包产物中。原生读取器提供的是声明的 HTML,不是任意静态文件目录;它会验证插件归属、真实路径(含 symlink)不能逃出插件根目录,并限制 HTML 不超过 2 MiB。不要使用绝对路径、路径穿越或仅存在于源码中的入口。App 构建应接入插件 build,verify:dist 应拒绝缺失或过期产物。 Xpert 自动生成 ui:// URI,通过 resources/listresources/read 发布 App,MIME 为 text/html;profile=mcp-app。不要硬编码 Publication ID,也不需要另写资源 HTTP 路由。 支持 MCP Apps 的客户端读取资源、初始化标准 bridge,再通过 ui/notifications/tool-result 将原有 Tool 的 structuredContent 交给 App。App 可以通过获准的 app-visible Tool 继续交互。遵循共用 bridge、i18n 与主题规范,不要向 iframe 注入 API Key 或让它直连 Xpert 业务 API。不支持 MCP Apps 渲染的客户端仍可消费 Tool 的文本/DTO 降级结果。

Tool 数量与能力数量

App 不会增加可调用 Tool 的数量。例如 5 个 Tool + 2 个 App = 7 项 Publication 能力,此时 tools/list 返回 5 项、resources/list 返回 2 项是正常结果。应用页的 Tool 数量与 MCP 管理页的能力数量口径不同;应检查明确的 capability type,而不是根据 _app 后缀判断。凭证 scope、可见性、策略与 required context 还可能进一步过滤协议列表。不能仅因 Tool 数量没增加就判定更新失败。

注册到插件模块

@XpertToolProvider() 会把类标记为 Injectable,但仍需将类加入插件 Nest 模块的 providers
不要再为同一组方法编写单独的 Middleware 类、Toolset 聚合类或 stdio 入口。

Marketplace 展示

运行时发现不依赖 manifest toolsets。如果需要在插件详情中展示 MCP 能力,建议增加一个描述性的 Marketplace contribution;name 必须与 componentKey 一致,Provider key 也必须一致:
该 contribution 只负责市场展示。工具 Schema、handler、行为标签和实际数量仍以运行时 Provider 为准。一个插件注册多个 Provider 时,应为每个 Provider 各声明一个 contribution,并保持 namecomponentKeyprovider 一一对齐。

上下文、结果与业务边界

每次调用都会创建新的 XpertBusinessToolContext。它包含调用面、租户、组织、principal、工作空间、项目、会话、Agent、执行、请求和终止信号等信息。
  • 不要把 context 保存到单例 Provider;
  • 不要让模型传入 tenant、organization、user 或凭证;
  • 在业务服务中再次按 tenant、organization 和 principal 做范围校验;
  • 返回字段白名单 DTO,不要直接返回 ORM entity 或供应商响应;
  • MCP 将 DTO 放入 structuredContent,同时提供简短文本降级内容;
  • 写操作应使用 operationId、revision/CAS 和紧凑回执实现明确的重试语义。
可选的 getMiddlewareExtensions() 只用于 wrapToolCall 等 Agent 生命周期扩展。直接 MCP 调用不会自动执行 Agent 的 wrapToolCall,因此授权、校验、持久化、幂等和审计不能只写在该 hook 中。

在产品中启用

只有超级管理员可以启用或停用插件 MCP Provider:
  1. 打开 插件 页面。
  2. 在已安装插件卡片上选择 初始化
  3. 在插件详情 dialog 的 MCP 区域找到 Provider。
  4. 选择 启用 MCP Server
  5. 通过受保护的 Token 展示/复制操作取得凭证,并保存到客户端的安全密钥存储。
  6. 复制页面显示的 Streamable HTTP 配置。
插件卡片不提供独立的“管理 MCP”按钮。详情 dialog 分别展示每个 Provider 的 Tool 数量、传输方式、当前组织状态、启停、端点、受保护的 Token 展示/复制和客户端无关配置。出现 高级设置 入口时,它会打开 MCP 管理中的对应 Publication;策略、Key 轮换、就绪检查、测试和审计仍由 Publication 管理。 应用 contribution 与 MCP Provider 保持分离。查看详情 打开应用目录详情页,该页 MCP 区域可以在 Accordion 中复用相同 Provider 控件。两个入口管理同一个 Publication,不会生成重复端点。

组织范围

MCP Provider 的访问始终按当前组织控制,但 Publication 的归属跟随插件级别: 因此,组织 A 启用 Provider 后,组织 B 仍然不能使用,必须由 B 独立启用。对于 tenant/system 插件,A 与 B 都启用后可能连接同一个租户级端点,但两者的 grant、凭证、认证主体和数据作用域仍然隔离。租户级 Publication 的 catalog、binding 和能力策略由这些组织共享;组织绑定 Key 的 scope 可以进一步限制调用方。A 创建的 API Key 不能作为 B 使用。

启用时发生什么

一次启用操作会以幂等方式完成:
  1. 在 Provider 的归属作用域创建或复用 Toolset;
  2. 刷新 MCP capability catalog;
  3. 创建或认领由宿主派生稳定 slug 的 MCP Publication;
  4. 绑定 Provider 中的所有 MCP Tools 与 Apps;
  5. 没有可复用 Key 时创建合适的 API Key:包含 tools:list / tools:call,发布 App 的 Provider 还需要 resources:list / resources:read
  6. 启用 Publication。
插件受管客户端凭证支持当前管理员在当前组织、Provider 启用的前提下显式重复展示和复制,secret 加密存储,不随普通列表或 connection-info 响应返回。普通仅存 hash 的 Publication Key 仍是一次性展示。增加 App 不会静默扩大旧 tools-only Key 的权限:需通过已授权的 Provider 操作取得合适的受管凭证,或在 MCP 管理中创建/轮换 Key,然后更新客户端。

通用客户端配置

平台显示的是客户端无关的 Streamable HTTP 配置,不与任何特定 MCP 客户端品牌绑定:
XPERT_MCP_API_KEY 写入客户端支持的环境变量或安全密钥存储。产品中已授权的配置复制操作可以将当前 Token 填入复制的 JSON,因此剪贴板内容应按密钥保护;示例和预览保留占位符。不要把真实 secret 提交到代码仓库、文档或聊天记录,也不要传入 App iframe。

更新、停用与策略

  • 运行中的插件刷新后,已启用的自动管理 Publication 会同步新增、删除和变化的 Tool 与 App。
  • capability type 与 key 相同的条目会保留 public name、启用状态和管理员策略覆盖;新增条目会绑定并启用。
  • 默认策略为:读取 allow、写入 confirm、危险操作 deny
  • 同步失败时保留最后一套有效绑定,不提交半套配置。
  • 停用会关闭组织级 Publication,或当前组织对租户级 Publication 的 access grant;不会自动删除历史、Key 或审计。
  • 插件被显式禁用或卸载时,关联 Publication 会被关闭;普通版本刷新会保留期望启用状态。

如何更新 Tool 或 App bundle

  1. 构建插件与 App 资源,运行打包检查和 verify:dist,再按插件声明作用域部署/刷新。仅修改源码不会替换已安装的运行时副本。
  2. 部署返回 restartRequired 时重启 API。宿主在 Provider 注册和应用 bootstrap 完成后协调已启用服务;若仍保留旧的有效配置,应检查同步错误。
  3. 手动组合的 Publication:进入 MCP 管理 → 对应服务 → 能力 → 刷新可用能力,选择需要的 Tool App,再点击 保存。刷新只更新可用目录,保存才更新发布绑定。这也是确认运行时定义已更新后的手动恢复路径。
  4. 刷新/重连客户端,验证 Tool 元数据与 Resource 操作。保持原有端点,不需要重建服务,也不要为刷新而停用其他组织。

验证清单

  • Provider、component、Middleware 和 Tool key 稳定且无冲突;同一插件的多个 Provider 可以被独立发现和管理;
  • 每个 MCP Tool 都有严格输入/输出 Schema、行为标签、上下文和可见性;
  • 未知字段、非法 ID、超限数组和错误 revision 会被拒绝;
  • 调用使用当前请求的 principal 和 organization;即使共享租户级端点,跨组织凭证也会被拒绝;
  • DTO 出现在 structuredContent,且不泄露内部路径、scope 或完整实体;
  • 插件构建、verify:dist、package dry-run 和生命周期加载通过;
  • 启用后 initializetools/list 和至少一个只读 tools/call 通过;
  • 对于 App,Tool 的 _meta.ui.resourceUri 必须对应 resources/list 中的资源;使用有 Resource scope 的凭证调用 resources/read,验证 HTML MIME、安全元数据与最新 bundle;
  • 为已有 Tool 增加 App 后,Tool 名称集合不变;测试重复 App key、未知引用、非法入口、scope 拒绝,以及同步时保留既有策略覆盖;
  • 在相应客户端验证渲染、Tool 结果传递、获准交互、尺寸变化、语言/主题与文本降级;协议成功不等于客户端已支持界面渲染;
  • 协议调用出现在 Publication 审计中。

相关文档