mcpField
C
create-mcp-app

create-mcp-app

github.com/modelcontextprotocol开发3.0k2.7k 次安装1 天前更新
代码仓库

关于 create-mcp-app

create-mcp-app 是用于构建交互界面的技能,界面可在支持 MCP 的宿主中运行。它指导开发者将 MCP 工具与 HTML 资源配对,并提供框架示例、实现说明和本地测试步骤。

主要功能

  1. 01将 MCP 工具与 HTML 资源配对
  2. 02提供 React 等界面框架指南
  3. 03包含向现有服务添加应用的示例
  4. 04介绍宿主上下文、流式输入和视图状态
  5. 05使用参考宿主进行本地测试

适用场景

  1. 01为 MCP 服务添加交互界面
  2. 02使用 React 或原生 JavaScript 创建 MCP App
  3. 03实现界面生命周期和宿主上下文处理
  4. 04通过 basic-host 本地测试应用

MCP 相关

它指导开发者构建 MCP App:MCP 工具返回数据,HTML 资源则为支持 MCP 的宿主提供界面。内容还涵盖在 MCP 服务中注册工具和资源。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/modelcontextprotocol/ext-apps --skill create-mcp-app

安装后在 Claude Code 中输入/create-mcp-app确认已加载。

详细介绍

创建 MCP App

构建可在 Claude Desktop 等支持 MCP 的宿主中运行的交互式 UI。MCP App 将 MCP 工具与 HTML 资源结合,用于显示丰富的交互式内容。

核心概念:工具 + 资源

每个 MCP App 都需要两个相互关联的部分:

  1. 工具 — 由大模型/宿主调用,并返回数据
  2. 资源 — 提供打包后的 HTML UI,用于显示数据

工具的 _meta.ui.resourceUri 引用资源的 URI。

宿主调用工具 → 宿主渲染资源 UI → 服务端返回结果 → UI 接收结果。

快速入门决策树

框架选择
框架SDK 支持最适合
React提供 useApp hook熟悉 React 的团队
Vanilla JS手动管理生命周期简单应用,无构建复杂度
Vue/Svelte/Preact/Solid手动管理生命周期偏好使用特定框架
项目背景

添加到现有 MCP 服务:

  • 从 SDK 导入 registerAppTool、registerAppResource
  • 添加带有 _meta.ui.resourceUri 的工具注册
  • 添加用于提供打包后 HTML 的资源注册

创建新的 MCP 服务:

  • 配置带有传输方式(stdio 或 HTTP)的服务
  • 注册工具和资源
  • 使用 vite-plugin-singlefile 配置构建系统

获取参考代码

克隆 SDK 仓库,获取可运行示例和 API 文档:

git clone --branch "v$(npm view @modelcontextprotocol/ext-apps version)" --depth 1 https://github.com/modelcontextprotocol/ext-apps.git /tmp/mcp-ext-apps
框架模板

从 /tmp/mcp-ext-apps/examples/basic-server-{framework}/ 中学习并改造:

模板关键文件
basic-server-vanillajs/server.ts、src/mcp-app.ts、mcp-app.html
basic-server-react/server.ts、src/mcp-app.tsx(使用 useApp hook)
basic-server-vue/server.ts、src/App.vue
basic-server-svelte/server.ts、src/App.svelte
basic-server-preact/server.ts、src/mcp-app.tsx
basic-server-solid/server.ts、src/mcp-app.tsx

每个模板都包含:

  • 带有 registerAppTool 和 registerAppResource 的 server.ts
  • 带有 HTTP 和 stdio 传输设置的 main.ts 入口文件
  • 带有生命周期处理程序的客户端应用(例如 src/mcp-app.ts、src/mcp-app.tsx)
  • 带有全局样式和宿主样式变量回退值的 src/global.css
  • 使用 vite-plugin-singlefile 的 vite.config.ts
  • 带有 npm run 脚本和所需依赖项的 package.json
  • 排除 node_modules/ 和 dist/ 的 .gitignore
API 参考(源文件)

直接阅读 /tmp/mcp-ext-apps/src/ 中的 JSDoc 文档:

文件内容
src/app.tsApp 类、处理程序(ontoolinput、ontoolresult、onhostcontextchanged、onteardown 等)、生命周期
src/server/index.tsregisterAppTool、registerAppResource、辅助函数
src/spec.types.ts所有类型定义:McpUiHostContext、McpUiStyleVariableKey(CSS 变量名称)、McpUiResourceCsp(CSP 配置)等
src/styles.tsapplyDocumentTheme、applyHostStyleVariables、applyHostFonts
src/react/useApp.tsx适用于 React 应用的 useApp hook
高级模式

参阅 /tmp/mcp-ext-apps/docs/patterns.md,了解详细用法:

  • 仅 App 可见的工具 — visibility: ["app"],对模型隐藏工具
  • 轮询 — 实时仪表板、间隔管理
  • 分块响应 — 大文件、分页、Base64 编码
  • 错误处理 — isError,告知模型发生的故障
  • 二进制资源 — 通过 resources/read、blob 字段处理音频/视频等
  • 网络请求 — 资源、fetch、CSP、_meta.ui.csp、CORS、_meta.ui.domain
  • 宿主上下文 — 主题、样式、字体、安全区域内边距
  • 全屏模式 — requestDisplayMode、显示模式更改
  • 模型上下文 — updateModelContext、sendMessage,让模型了解最新信息
  • 视图状态 — viewUUID、localStorage、状态恢复
  • 基于可见性的暂停 — IntersectionObserver、暂停动画/WebGL
  • 流式输入 — ontoolinputpartial、渐进式渲染
参考宿主实现

/tmp/mcp-ext-apps/examples/basic-host/ 展示了一种实现支持 MCP Apps 的宿主的方式。Claude Desktop 等真实宿主更加复杂——请将 basic-host 用于本地测试和了解协议,而不要将其视为宿主行为的保证。

关键实现说明

添加依赖项

添加依赖项时,始终使用 npm install,不要手动编写版本号:

npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@^2.0.0 @modelcontextprotocol/server@^2.0.0 @modelcontextprotocol/node@^2.0.0 @modelcontextprotocol/express@^2.0.0 zod@^4.2.0 express cors
npm install -D typescript vite vite-plugin-singlefile concurrently cross-env @types/node @types/express @types/cors

ext-apps 2.x 要求使用拆分后的基础 MCP SDK 软件包(@modelcontextprotocol/client、 server、node、express),版本为 ^2.0.0;@modelcontextprotocol/core 会作为 传递依赖引入。不要添加旧版 @modelcontextprotocol/sdk v1 软件包,也不要 替换为尚未发布的本地软件包。

TypeScript 服务执行

除非用户另有指定,否则使用 tsx 运行 TypeScript 服务文件。例如:

npm install -D tsx

npm pkg set scripts.dev="cross-env NODE_ENV=development concurrently 'cross-env INPUT=mcp-app.html vite build --watch' 'tsx --watch main.ts'"

说明

SDK 示例使用 bun,但生成的项目应默认使用 tsx,以获得更广泛的兼容性。

处理程序注册顺序

在调用 app.connect() 之前注册所有处理程序:

const app = new App({ name: "My App", version: "1.0.0" });

// Register handlers first
app.ontoolinput = (params) => { /* handle input */ };
app.ontoolresult = (result) => { /* handle result */ };
app.onhostcontextchanged = (ctx) => { /* handle context */ };
app.onteardown = async () => { return {}; };
// etc.

// Then connect
await app.connect();

应避免的常见错误

  1. 没有文本回退 - 始终提供 content 数组,以支持非 UI 宿主
  2. 缺少 CSP 配置 - MCP Apps HTML 作为 MCP 资源提供,不存在同源服务;所有网络请求(即使发往 localhost)都需要 CSP 配置
  3. CSP 或 CORS 配置位于错误的 _meta 对象中 - _meta.ui.csp 和 _meta.ui.domain 应放在 registerAppResource() 的读取回调所返回的 contents[] 对象中,而不是放在 registerAppResource() 的配置对象中
  4. 在 app.connect() 之后注册处理程序 - 在调用 app.connect() 之前注册所有处理程序
  5. 大输入未使用流式传输 - 使用 ontoolinputpartial,在生成输入期间显示进度

测试

使用 basic-host

使用 basic-host 示例在本地测试 MCP Apps:

# Terminal 1: Build and run your server
npm run build && npm run serve

# Terminal 2: Run basic-host (from cloned repo)
cd /tmp/mcp-ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm run start
# Open http://localhost:8080

使用服务器 URL 的 JSON 数组配置 SERVERS(默认值:http://localhost:3001/mcp)。

使用 sendLog 进行调试

将调试日志发送到宿主应用程序(而不只是 iframe 的开发控制台):

await app.sendLog({ level: "info", data: "Debug message" });
await app.sendLog({ level: "error", data: { error: err.message } });

评论

支持 Markdown