Skip to main content
Glama
mustafadeel

@auth0/agent-components

by mustafadeel

@auth0/agent-components — Auth0 通用代理组件

将 Auth0 表单 转变为 MCP 应用 —— 一个由 Model Context Protocol 服务器提供给 MCP 客户端的交互式 UI,在沙箱化 iframe 中渲染。这就是 Auth0 通用代理组件:任何 Auth0 表单都能成为即插即用、可被代理调用的 UI,无需编写 Auth0 Action。

状态:概念验证。已针对官方 MCP Apps 能力(SEP-1865)、MCP Inspector 以及 CopilotKit(参见 examples/copilotkit-poc)完成端到端验证。

为什么

Auth0 表单通常只在 Universal Login 期间的 Auth0 Action 内部渲染。dx-flows-sdk 解耦了这一限制:表单可以通过浏览器 bundle 在登录重定向之外嵌入。MCP Apps 允许服务器向客户端提供交互式 HTML,在沙箱化 iframe 中渲染。将两者结合,代理就可以将真实、功能完整的 Auth0 表单 —— 注册、同意、个人资料、支付 —— 作为其工具之一呈现。

Related MCP server: Homespun

工作原理

MCP host (e.g. MCP Inspector, CopilotKit)
 └─ sandboxed iframe  ← our ui:// HTML resource (text/html;profile=mcp-app)
      ├─ <script src="https://<tenant>/forms/sdk/forms.js">
      ├─ Auth0Forms.embed(formId, "#root", { fields: { session_token } })
      │    └─ form submits to its OWN Auth0 backend (/forms/api/...)  ← we never see the data
      └─ bridge: on af-submitForm-success → app.updateModelContext({ status: "completed" })
                                          → app.requestTeardown()   (close the app view)
                  on af-redirect          → app.openLink(url)       (never navigates the iframe)

表单拥有其数据。 Auth0 表单原生提交到其 Auth0 后端。MCP 层从不读取或传输字段值 —— 它只报告完成状态(completed / cancelled / errored,以及可选的跳转目标),以便代理知道用户已完成操作。

包

包

说明

packages/agent-components

@auth0/agent-components —— 在任何 McpServer 上将 Auth0 表单注册为 MCP Apps。

packages/mcp-apps-middleware-auth

@auth0/mcp-apps-middleware-auth —— 为 CopilotKit 的 @ag-ui/mcp-apps-middleware 添加认证支持,后者无法为其 MCP 连接附加凭据。

examples/poc-server

可运行的 MCP 服务器 POC;可通过 MCP Inspector 驱动。包含 scripts/discover-forms.mjs(通过 Auth0 CLI 发现租户表单)。

examples/copilotkit-poc

以 CopilotKit 作为 MCP 客户端 —— 真实 Auth0 登录(@auth0/auth0-server-js)→ 表单渲染并内联提交。端到端。

用法

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { registerAuth0Forms } from "@auth0/agent-components";

const server = new McpServer({ name: "my-server", version: "1.0.0" });

await registerAuth0Forms(
  server,
  [
    {
      formId: "your-form-id",
      tenantOrigin: "https://your-tenant.us.auth0.com",
      // inputMode: "prefill",         // expose form fields as optional agent inputs
      // ui: { csp: { frameDomains: ["https://js.stripe.com"] } }, // for payment/social steps
      onComplete: (r) => console.log(r.formId, r.status),         // status only — no field data
    },
  ],
  { assumeUiSupport: true }, // register before connect; see "Registration timing"
);

// ...connect your transport (StreamableHTTP / stdio / SSE)

每个表单注册:

  • 一个工具 open_form_<slug>,其 _meta.ui.resourceUri 指向……

  • 一个 ui://agent-components/<formId> 资源,返回表单应用 HTML 及 CSP 块。

CSP

宿主在严格的默认策略(default-src 'none')下渲染资源。@auth0/agent-components 会自动将你的 tenantOrigin 加入白名单,包括:

  • csp.resourceDomains —— 使 forms.js、样式、字体、图片能够加载,以及

  • csp.connectDomains —— 使 bundle 对 /forms/api/... 的 fetch 请求能够工作。

如果表单步骤嵌套了其他来源的 iframe(Stripe、社交登录提供商、验证码),请声明它:

ui: { csp: { frameDomains: ["https://js.stripe.com", "https://hooks.stripe.com"] } }

首次渲染新表单时请留意浏览器控制台:任何 CSP 违规都会准确告诉你需要添加哪个来源。

会话支持的表单(flow/router 表单)

包含 FLOW/ROUTER 节点的表单需要已认证的会话 —— 否则 router 之后的步骤会失败并报 ERR_INVALID_FORM_SESSION。该机制(已与 Forms 团队确认,并完成端到端验证):

  1. 在表单上声明一个隐藏字段(例如 session_token)。

  2. 表单的 flow 读取该字段 —— 例如一个 Update User 操作,使用 user_id: {{fields.session_token}}。

  3. MCP 服务器作为 OAuth 资源服务器,验证调用方的 Auth0 token,解析用户的 sub,为其铸造一个短期可信 JWT(使用 Forms 后端信任的共享密钥签名),并在每次请求时将其注入隐藏字段。

将表单标记为会话感知:

{
  formId: "ap_...",
  session: { field: "session_token" },   // must match the form's hidden field
}

……并使用服务器作用域的信任配置以及一个读取已验证身份的解析器来初始化客户端(verifier 和 subFromExtra 来自 /auth 子路径,由 @auth0/auth0-api-js 提供支持):

import { createAgentComponents } from "@auth0/agent-components";
import { subFromExtra } from "@auth0/agent-components/auth";

const agentComponents = createAgentComponents({
  tenantOrigin: "https://your-tenant.auth0.com",
  assumeUiSupport: true,
  sessionTrust: { secret: process.env.FORMS_TRUST_SECRET! }, // shared with the Forms backend
  resolveUserSub: subFromExtra,                    // returns the caller's `sub`, or undefined
});
await agentComponents.register(server, forms);

POC 服务器(examples/poc-server)串联了完整流程:createAuth0Verifier(→ @auth0/auth0-api-js)、一个 ProtectedResourceMetadataBuilder 元数据端点,以及 requireBearerAuth —— 因此 401 + WWW-Authenticate 质询可让客户端运行 Auth0 OAuth 流程。token/sub/铸造的 JWT 永远不会进入 MCP 模型上下文 —— 铸造的 token 仅通过 embed().fields 传递到 Auth0 Forms 后端。

注意:目前一次完整的 Auth0 Forms 旅程是单次使用的(重新提交已使用的旅程会返回 ERR_INVALID_FORM_SESSION)。Universal Portals EPIC 7 将添加可重新完成的旅程。MCP 应用完成一次并报告状态,因此新的工具调用会获得新的旅程 —— 重新提交不属于该流程的一部分。

注册时机

MCP SDK 禁止在 server.connect(transport) 之后添加能力。两种受支持的模式:

  • 在连接之前注册(最简单),使用 assumeUiSupport: true。适用于支持 UI 的客户端(MCP Inspector、Claude)。POC 采用的就是这种方式。

  • 按客户端动态门控(assumeUiSupport: "auto",默认值):从 server.server.oninitialized 调用 registerAuth0Forms,以便了解客户端的能力 —— 并使用 { capabilities: { tools: {}, resources: {} } } 构造服务器,或在连接前注册一个工具和一个资源,这样连接后的注册就不会尝试添加新的能力。

开发

npm install
npm run build      # builds all packages (agent-components builds its bridge first)
npm test           # unit tests (form→tool, ui-template CSP, bridge status-only contract)

许可证

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables authenticated MCP apps to expose and interact with Auth0 Forms, submitting form data directly to Auth0 while only completion status is returned to the agent.
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables agents to ask users questions through rich, browser-rendered HTML forms and receive structured answers, supporting approvals, choices, free-text, and form inputs.
    11 npm
    MIT