应用

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()、XHR、WebSocket、EventSource

来源应使用 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. 主机通过 resources/read 读取 ui:// 资源,并在 iframe 中挂载打包后的 HTML。
  3. 主机会将工具结果推送到 iframe,useMcpApp() 会将其中的 structuredContent 作为 data 暴露。
  4. 此后,iframe 和主机会通过 JSON-RPC 桥交换 callTool、sendPrompt、openLink 以及主题和尺寸更新等消息。
整个视图都随一个 HTML 响应交付,iframe 无需为脚本、样式或资源发起额外 HTTP 请求。

::