- 教程
- 文档
- 人工智能
【免费下载链接】mcp-for-beginners
This open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for developers, it focuses on practical techniques for building modular, scalable, and secure AI workflows from session setup to service orchestration.
MCP Apps 是 MCP 协议体系中较新的一种范式:工具调用不再只返回纯数据,而是连同"这段数据应该如何被展示与交互"的 UI 描述一起返回,让工具结果天然携带界面。本篇文章以 mcp-for-beginners 仓库中03-GettingStarted/15-mcp-apps一课的 TypeScript 示例为主线,带你从零安装依赖、启动后端、配置mcp.json接入 Visual Studio Code 聊天窗口,再到用官方 ext-apps 宿主(Host)在浏览器中渲染组件。读完本文,你将掌握 MCP App 的"工具 + UI 资源"双注册架构、前后端事件链路,以及本地机器与 Codespace 两种环境下的完整测试流程。
MCP Apps 是什么:工具结果从"数据"升级为"组件"
传统 MCP 工作流中,宿主(如 Copilot、Claude Desktop)调用工具后拿到的是一段纯文本或结构化数据,UI 需要开发者自己在宿主前端去写、去维护。MCP Apps 的思路是:MCP Server 不仅决定返回什么数据,还可以"主张"这些数据应该如何被呈现与交互——即工具结果中可以包含 UI 信息,一个自带数据与界面的自包含组件。
在本课的示例中,后端会注册两类东西,并通过resourceUri把它们绑在一起:
server.ts -- 负责注册工具,并把组件注册为 UI 资源 src/mcp-app.ts -- 事件处理与调用后端工具的逻辑 mcp-app.html -- 用户界面对应的源码位于 03-GettingStarted/15-mcp-apps/code/typescript/my-app。前端组件最终会被宿主放进一个IFrame中渲染,出于安全考虑,组件与 MCP Server 的通信是通过向父页面发消息完成的,而不是直接持有会话。
一、安装与编译检查
1. 进入示例目录
首先进入 MCP App 示例目录:
cd 03-GettingStarted/15-mcp-apps/code/typescript/my-app2. 安装依赖
执行npm install,它会同时安装 frontend 与 backend 的依赖:
npm install从该目录的 package.json 可以看到关键依赖分组:
- 运行时依赖:
@modelcontextprotocol/ext-apps(MCP App 的 UI/资源支持库)、@modelcontextprotocol/sdk(MCP SDK)、express与cors(HTTP 服务与跨域); - 开发依赖:
concurrently(并行启动前后端)、cross-env(跨平台环境变量)、tsx(直接运行 TypeScript)、vite+vite-plugin-singlefile(把 HTML/JS 打包为单文件)、typescript(编译检查); - 项目声明
"type": "module"且要求"node": ">=20",请确保本机 Node.js 版本满足要求。
3. 验证后端能否编译
运行 TypeScript 编译检查(不产出文件):
npx tsc --noEmit如果一切正常,命令不应有任何输出。
二、启动后端
1. 认识 start 脚本
示例的npm start脚本定义在 package.json 中:
"start": "concurrently \"cross-env NODE_ENV=development INPUT=mcp-app.html vite build --watch\" \"tsx watch main.ts\""它通过concurrently并行执行两件事:
- 前端构建(watch 模式):以
mcp-app.html作为 Vite 入口,用vite-plugin-singlefile把页面与脚本打成单文件 HTML,产出到dist/目录; - 后端启动(watch 模式):用
tsx watch main.ts运行 MCP 服务器进程,改动代码后自动重启。
Windows 用户注意:
concurrently在某些 Windows 环境下需要寻找替代方案,问题就出在上面这行start脚本里。如果你在 Windows 上遇到问题,可以改用npm-run-all或拆成两个终端窗口分别执行npm run build与npx tsx watch main.ts。
INPUT环境变量是必须的——vite.config.ts 中如果检测不到INPUT会直接抛错退出,并且开发模式下sourcemap会以内联形式打开。
2. 执行启动命令
npm start正常情况下后端会监听在:
http://localhost:3001/mcp后端入口 main.ts 使用 MCP SDK 的createMcpExpressApp构建 Express 应用,并在/mcp路径上以Streamable HTTP 传输(无状态模式)提供服务:每个请求都会创建新的McpServer实例并连接StreamableHTTPServerTransport。端口默认取环境变量PORT,未设置时回退到3001。跨域配置为允许任意来源,并放行MCP-Protocol-Version等请求头。代码里也保留了--stdio分支,可用标准输入输出传输方式运行。
Codespace 提示:如果你在 Codespace(GitHub Codespaces)中运行,可能需要把端口可见性设为 Public,然后在浏览器中通过
https://<Codespace 名称>.app.github.dev/mcp验证端点是否可达。
三、测试方案一:在 Visual Studio Code 中测试
Visual Studio Code 对 MCP Apps 有很好的内建支持,是测试 MCP App 最便捷的方式之一。
1. 配置 mcp.json
在 VS Code 的项目级mcp.json中添加一条服务器记录:
{ "servers": { "my-mcp-server-7178eca7": { "url": "http://localhost:3001/mcp", "type": "http" } }, "inputs": [] }要点解析:
url:指向刚才启动的后端端点,即http://localhost:3001/mcp;type:传输类型,这里使用http(Streamable HTTP),对应后端main.ts中/mcp路由的实现;servers下的键名my-mcp-server-7178eca7是服务器标识,可自行命名。
2. 启动并调用工具
点击mcp.json中的 "start" 按钮后,确保聊天窗口已打开,然后输入get-faq触发 FAQ 工具,即可在聊天窗中看到渲染出的组件界面:
需要注意的是,VS Code 方式依赖 GitHub Copilot 的聊天窗口来承载 MCP App 组件渲染(本课程在第 12 课 12-mcp-hosts 中有更系统的宿主介绍)。你也可以用#get-faq这样的提示词形式直接触发工具。
四、测试方案二:用 Host 宿主应用测试
ext-apps仓库提供了多个可用于测试 MVP App 的宿主实现。本仓库在 03-GettingStarted/15-mcp-apps/ext-apps 下内置了examples/basic-host供你直接使用,无需另外克隆。
1. 本地机器方式
先在ext-apps目录安装宿主依赖:
npm install然后在另一个终端窗口中进入宿主示例目录:
cd 03-GettingStarted/15-mcp-apps/ext-apps/examples/basic-host npm startnpm start会先执行构建(分别以index.html与sandbox.html为入口打包),再启动 serve.ts。从源码可以看到它实际启动了两个服务:
- Host 服务器(默认 8080 端口):托管宿主页面,并通过
/api/servers接口向页面暴露后端 MCP Server 的地址列表(由环境变量SERVERS指定,默认指向示例的 Codespace URL); - Sandbox 服务器(默认 8081 端口):以带 CSP 头的独立源(origin)对外提供
sandbox.html,用于安全地承载 MCP App 的 IFrame 内容。
两个服务放在不同端口,是为了保证源隔离(origin isolation)的安全要求。如果 8080/8081 端口被占用,代码会自动回退到随机可用端口,并从控制台日志中打印实际地址。
启动后宿主会连接后端,你应该能看到应用在浏览器中运行:
Codespace 提示:如果你使用 Codespace,需要编辑 serve.ts 第 27 行附近的
SERVERS默认值,把http://localhost:3001/mcp替换为你的 Codespace 后端地址,例如https://psychic-xylophone-657rpjgvxpc5g64-3001.app.github.dev/mcp。也可以通过环境变量SERVERS传入 JSON 数组覆盖默认值。此外,serve.ts 还支持CORS_ORIGINS环境变量(JSON 数组或 CSV)来限制允许跨域访问的宿主来源。
2. Codespace 方式
如果要在 Codespace 中通过宿主使用 MCP App,需要额外几步:
- 进入
ext-apps目录并切换到examples/basic-host; - 运行
npm install安装宿主依赖; - 按上文方法修改
serve.ts中的服务器地址; - 运行
npm start启动宿主。
五、测试组件交互
在宿主页面中尝试以下操作:
- 在输入框中输入 FAQ 关键词(例如
shipping、warranty),点击 "Get FAQ Response"; - 点击 "Call Tool" 按钮触发工具调用。
点击后可以看到工具结果被渲染出来:
一切正常的话,说明前端组件 → 父窗口 → MCP Server → 工具结果 → 组件展示的整条链路已经打通。
六、从源码看懂 MCP App 的工作原理
1. 后端:工具与 UI 资源的"双注册"
核心实现在 server.ts。它导出一个createServer()工厂函数,创建名为Quickstart MCP App Server的McpServer实例,并定义了一组ui://资源 URI:
const resourceUri = "ui://get-time/mcp-app.html"; const faqResourceUri = "ui://get-faq/mcp-faq.html"; const infoUri = "ui://app-info";每个 UI 型工具都通过registerAppTool()注册,并在_meta.ui.resourceUri中指向对应的 UI 资源,例如:
registerAppTool( server, "get-time", { title: "Get Time", description: "Returns the current server time.", inputSchema: zod.object({}), _meta: { ui: { resourceUri } }, // 把工具与其 UI 资源关联起来 }, async () => { const time = new Date().toISOString(); return { content: [{ type: "text", text: time }] }; }, );而 UI 资源本体由registerAppResource()注册,回调中读取 Vite 打包出的单文件 HTML 并返回:
registerAppResource( server, resourceUri, resourceUri, { mimeType: RESOURCE_MIME_TYPE }, async () => { const html = await fs.readFile(path.join(DIST_DIR, "mcp-app.html"), "utf-8"); return { contents: [{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }] }; }, );这正是 MCP Apps 的核心机制:当宿主调用某个工具时,会读取_meta.ui.resourceUri,据此去拉取并渲染对应的交互式 UI 资源。示例中还注册了ping、play-rps(石头剪刀布,带zod.enum输入校验)、get-app-info、get-faq(带zod.string().default("shipping")的可选参数)以及一个内嵌内联 HTML 的simple-click演示资源。
示例里的 FAQ 数据是一份简单的键值映射,工具实现会把用户输入转为小写后查表,未命中则返回兜底提示:
const answer: string = faq[query.toLowerCase()] || "Sorry, I don't have an answer for that.";2. 前端:HTML 界面与事件接线
界面位于 mcp-app.html,包含 Ping、石头剪刀布、FAQ 查询、获取服务器时间等区块,并在末尾通过<script type="module" src="/src/mcp-app.ts"></script>引入逻辑。
事件接线位于 src/mcp-app.ts,关键步骤是:
const app = new App({ name: "Get Time App", version: "1.0.0" }); // 在 app.connect() 之前设置,避免错过首批工具结果 app.ontoolresult = (result) => { ... }; getFaqBtn.addEventListener("click", async () => { const query = faqQueryInput.value; const result = await app.callServerTool({ name: "get-faq", arguments: { query } }); ... }); app.connect();其中app.callServerTool()是核心调用:UI 通过它请求服务器端的新数据,底层实现是向父窗口发送一条消息,由父页面(Host)代为调用 MCP Server,再把结果回传。因此前端组件不需要直接持有 MCP 会话,这也解释了为什么组件必须运行在宿主提供的 IFrame 沙箱中。App与registerAppTool/registerAppResource均来自@modelcontextprotocol/ext-apps包。
七、动手练习:石头剪刀布 MCP App
课程还附带一个练习:实现一个石头剪刀布游戏,要求包含:
UI 部分:
- 一个带选项的下拉列表;
- 一个提交选择的按钮;
- 一个展示双方选择与胜负结果的标签。
服务端部分:
- 一个接收
choice输入的石头剪刀布工具,能生成电脑的选择并判定胜负。
参考答案位于 03-GettingStarted/15-mcp-apps/assignment/typescript/README.md,结构上仍然是server.ts(服务器功能)、src/mcp-app.ts(UI 与事件接线)、mcp-app.html(界面标记)三件套,可参考 code/typescript 的运行方式。
总结
通过本文的完整流程,你已经掌握了 MCP Apps 从安装、编译、启动到双通道测试(VS Code 聊天窗口与 ext-apps 浏览器宿主)的实战路径,并从 server.ts 与 src/mcp-app.ts 的源码层面理解了"工具 + UI 资源通过resourceUri关联、组件运行在 IFrame 中、通过父窗口消息机制与服务器通信"的底层原理。核心要点如下:
- MCP Apps 让工具结果从纯数据升级为"数据 + 呈现方式"的自包含组件;
- 一个 MCP App 由
registerAppTool注册的工具与registerAppResource注册的 UI 资源构成,二者以resourceUri关联; - 组件出于安全原因运行在 IFrame 中,调用服务器工具需经父窗口转发(
app.callServerTool()); - 测试途径有二:VS Code 的
mcp.json(HTTP 类型服务器记录)+ 聊天窗口,或 ext-apps 的basic-host浏览器宿主; - Codespace 环境下需处理端口可见性,并将宿主
serve.ts中的服务器地址替换为 Codespace 的公网 URL。
下一步可以继续学习 04-PracticalImplementation 章节,了解 MCP 在实际项目中的落地实现。
- 教程
- 文档
- 人工智能
【免费下载链接】mcp-for-beginners
This open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for developers, it focuses on practical techniques for building modular, scalable, and secure AI workflows from session setup to service orchestration.
相关推荐
MCP Apps 实战:在 mcp-for-beginners 中用 TypeScript 构建带交互 UI 的石头剪刀布 MCP 应用
MCP Apps 实战:在 mcp for beginners 中用 TypeScript 构建带交互 UI 的石头剪刀布 MCP 应用 导读 本文围绕 mcp
教程文档人工智能MCP Apps 实战指南:用 mcp-for-beginners 构建数据与 UI 一体的 MCP 组件
MCP Apps 实战指南:用 mcp for beginners 构建数据与 UI 一体的 MCP 组件 MCP Apps 是 Model Context P
教程文档人工智能mcp-for-beginners 实战:用 TypeScript 构建、运行并测试你的第一个 MCP 服务器
mcp for beginners 实战:用 TypeScript 构建、运行并测试你的第一个 MCP 服务器 本文聚焦于 mcp for beginners
教程文档人工智能
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考