应用

CSP 与构建流水线

内容安全策略、允许列表域名,以及 HTML bundle 的生成方式。

CSP 与资源允许列表

该工具包会向每个应用的 HTML 注入一个 保守的内容安全策略。默认情况下,iframe 可以:

  • 只运行其自身的内联脚本。
  • 仅从同一响应中渲染图片和样式。
  • 通过 postMessage 与其父宿主通信。

如果你的 UI 需要外部资源或 API,请显式允许它们:

app/mcp/color-picker.vue
<script setup lang="ts">
defineMcpApp({
  description: '选择一种颜色并预览调色板。',
  csp: {
    resourceDomains: ['https://images.unsplash.com'],
    connectDomains: ['https://api.example.com'],
  },
  handler: async ({ base }) => ({ structuredContent: await $fetch('/api/palette', { query: { base } }) }),
})
</script>

CSP 会镜像到 _meta.ui.csp(以及 ChatGPT 的 openai/widgetCSP),因此在 iframe 级别强制执行 CSP 的宿主也会采用相同规则。

仅在万不得已时才传入 csp: false —— 并且仅当你完全控制 iframe 加载的资源时才这样做。默认策略正是让应用能够在不同宿主之间安全渲染的关键。
字段它允许什么
resourceDomains来自这些源的 <img><style><link>、字体
connectDomains到这些源的 fetch()XHRWebSocketEventSource

来源应使用 http(s)://ws(s)://。在应用响应被提供之前,该工具包会拒绝空值、不受支持的 URL 协议、空白、引号和分号。

它是如何连接的

在幕后,配置好的 apps 目录下的每个 .vue 文件在构建时都会变成 三种产物

  1. 在你的 MCP 处理器上注册的一个 工具定义(输入 schema、描述、服务器处理函数)。
  2. 一个位于 ui://mcp-app/<name>UI 资源,返回 text/html;profile=mcp-app
  3. 一个将 Vue SFC(Vue runtime、你的代码、作用域 CSS、资源)内联进资源响应中的 单文件 HTML bundle

当 LLM 调用该工具时:

  1. 你的 handler 在服务器上运行并生成 structuredContent
  2. 工具包将这些数据注入到打包后的 HTML 中,形式为 <script type="application/json" id="__mcp_app_data__">…</script>
  3. 宿主将该资源返回给用户;其 iframe 启动,并且 useMcpApp() 会同步将内联数据读取到 data 中。
  4. 从那里开始,iframe 和宿主通过 JSON-RPC 桥交换 callToolsendPromptopenLink 以及主题/尺寸更新等消息。
一切都在 一个 HTML 响应 中交付。iframe 不需要额外的 HTTP 请求,没有瀑布流,没有闪烁。