news 2026/10/7 2:24:43

mcp-for-beginners 实战:用 TypeScript 构建并测试可交互的 MCP Apps(UI 组件型 MCP 服务)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
mcp-for-beginners 实战:用 TypeScript 构建并测试可交互的 MCP Apps(UI 组件型 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.

项目地址:https://gitcode.com/GitHub_Trending/mc/mcp-for-beginners
点击查看免费下载

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-app

2. 安装依赖

执行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并行执行两件事:

  1. 前端构建(watch 模式):以mcp-app.html作为 Vite 入口,用vite-plugin-singlefile把页面与脚本打成单文件 HTML,产出到dist/目录;
  2. 后端启动(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 start

npm 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.

项目地址:https://gitcode.com/GitHub_Trending/mc/mcp-for-beginners
点击查看免费下载
上一篇:终极指南:如何用免费在线JSON对比工具快速找出数据差异
下一篇:TQVaultAE:从仓库焦虑到装备自由,泰坦之旅玩家的终极资产管理方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 2:24:22

九. SCL 先入先出

一. 先入先出是什么&#xff1f;以下面的数组为例。写入值&#xff1a;写入一个新的值11&#xff0c;数据放在【0】位。在写入12&#xff0c;放在【1】位。读取值&#xff1a;先读取第一个存入的值&#xff0c;也就是11. 随后将12移动到【0】位&#xff0c;依次前移。二. 程序1…

作者头像 李华
网站建设 2026/10/7 2:15:15

DeepSeek本地部署全指南:显存计算、量化选型与推理框架调优

简介&#xff1a;一份DeepSeek大语言模型本地部署教程&#xff0c;面向具有一定计算机基础、希望实现数据本地化处理或模型二次开发的技术人员。教程完整覆盖安装前准备、部署方案选择、可视化界面配置、验证与测试、常见问题与解决方案、安全与性能优化建议等环节&#xff1a;…

作者头像 李华
网站建设 2026/10/7 2:13:25

排序全解析:算法、工程与应用的三个核心层面

如果只看标题“排序------3”&#xff0c;你可能会觉得这是一个随手记的草稿&#xff1a;不知道“3”是第几版&#xff0c;也不知道为什么要用三个横杠隔开。但恰恰是这种模糊的标题&#xff0c;反而把一个被大多数人当成“理所当然”的技术话题重新推到了台前。排序这件事&…

作者头像 李华