ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 TypeScript 实现石头剪刀布 MCP App:从工具注册到前端组件实战(mcp-for-beginners 第 15 章作业解析)

用 TypeScript 实现石头剪刀布 MCP App:从工具注册到前端组件实战(mcp-for-beginners 第 15 章作业解析) 教程文档人工智能【免费下载链接】mcp-for-beginnersThis 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-for-beginners 开源课程第 15 章MCP Apps的 TypeScript 作业展开完整讲解「石头剪刀布Rock Paper Scissors」解决方案的三层代码结构server.ts中的工具与组件资源注册、mcp-app.ts中的事件绑定与工具调用、mcp-app.html中的交互式 UI。读完本文你将掌握如何用modelcontextprotocol/ext-apps与modelcontextprotocol/sdk搭建一个同时返回数据与可渲染 UI 的 MCP App并能在 Visual Studio Code 或独立 Host 中启动、联调与验证它。MCP Apps让工具返回「可交互的组件」而不是裸数据在进入作业代码之前需要先理解作业背后的范式。正如 15-mcp-apps 课程主文档 所阐述的MCP Apps 是 MCP 标准中的新范式它不再要求工具调用只返回数据而是允许服务器同时声明「这份数据应该如何被用户交互」。也就是说工具结果可以携带 UI 信息——一个自包含的组件从数据到用户界面一应俱全避免了开发者自行编写和长期维护前置前端页面的开销。实现一个 MCP App 需要两部分彼此关联的注册工具Tool负责接收参数、执行逻辑并返回数据组件资源App Resource负责提供打包后的 HTML/JavaScript即可渲染的 UI。两者通过同一个resourceUri连接起来。整个 MCP Apps 的运行模型可以概括为Host 应用把 MCP App 的 UI 注入到 IFrame 容器中IFrame 内的事件处理器通过向父页面发送消息来调用服务器工具再把工具结果数据渲染回界面详见主文档中的 Mermaid 流程图。本作业正是对上述范式的直接练习作业要求实现一个石头剪刀布游戏UI 部分需要一个下拉列表、一个提交按钮和一个显示「谁出了什么、谁赢了」的标签服务端部分需要一个以choice为输入、随机生成电脑选择并判定胜负的工具。对应的解决方案文档即 assignment/typescript/README.md。解决方案的整体结构作业的官方解答刻意只保留了「真正关键」的代码UI 标记markup、事件绑定event wire up和服务端功能server features完整的构建配置、依赖声明与启动入口则在课程code目录中提供。my-app server.ts -- 服务端功能工具 组件资源注册 src mcp-app.ts -- UI 与事件绑定逻辑 mcp-app.html -- UI 标记对照仓库中的实际文件作业解答存放于 assignment/typescript/my-app文件职责仓库路径server.ts注册play-rps工具与ui://get-time/mcp-app.html资源并读取打包后的 HTMLserver.tssrc/mcp-app.ts创建App实例、绑定下拉框与按钮事件、通过callServerTool调用后端工具mcp-app.tsmcp-app.html定义石头剪刀布的下拉列表、提交按钮与结果展示区mcp-app.html服务端registerAppTool注册游戏工具服务端核心是 assignment 版 server.ts。它先创建一个McpServer实例然后用modelcontextprotocol/ext-apps/server提供的registerAppTool注册名为play-rps的工具import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE, } from modelcontextprotocol/ext-apps/server; import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import zod from zod; const resourceUri ui://get-time/mcp-app.html; registerAppTool( server, play-rps, { title: Play Rock-Paper-Scissors, description: Play a game of rock-paper-scissors with the server., inputSchema: zod.object({ choice: zod.enum([rock, paper, scissors]), }), _meta: { ui: { resourceUri } }, // 将工具与其 UI 资源关联 }, async ({ choice }) { const options [rock, paper, scissors] as const; const serverChoice options[Math.floor(Math.random() * options.length)]; let result: string; if (choice serverChoice) { result Its a tie! We both chose ${choice}.; } else if ( (choice rock serverChoice scissors) || (choice paper serverChoice rock) || (choice scissors serverChoice paper) ) { result You win! You chose ${choice} and I chose ${serverChoice}.; } else { result I win! You chose ${choice} and I chose ${serverChoice}.; } return { content: [{ type: text, text: result }], }; }, );值得注意的三个设计点输入校验inputSchema使用 zod 的zod.enum([rock, paper, scissors])限定choice只能取三种合法值从协议层杜绝非法输入。这与课程主文档中 FAQ 示例的zod.string().default(shipping)一脉相承——需要接受用户输入的工具都应声明inputSchema。UI 关联元数据_meta: { ui: { resourceUri } }是 MCP Apps 的关键连线——Host 调用该工具时会读取_meta.ui.resourceUri得知应该获取并渲染哪个资源作为交互式 UI。游戏判定逻辑服务端随机生成电脑选择按「平局—玩家赢—服务器赢」的顺序判定并把结果以标准 MCPcontent: [{ type: text, text: result }]结构返回。服务端registerAppResource注册组件资源工具只负责「算」UI 则来自组件资源。同一文件的第 64-86 行 用registerAppResource把打包产物注册为资源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, _meta: { ui: {} }, }, ], }; }, );关键点DIST_DIR path.join(import.meta.dirname, dist)即读取 Vite 构建产物目录中的mcp-app.html资源回调返回contents数组其中text字段携带完整的 HTML 字符串mimeType使用RESOURCE_MIME_TYPE注意工具与资源共用同一个resourceUri常量——这正是文档强调的「组件与工具通过resourceUri连接」的实现证据。如果继续阅读课程code目录下的完整版 server.ts可以看到 FAQ 工具的完整形态faq键值对数据、带zod.object({ query: zod.string().default(shipping) })的inputSchema以及registerAppToolregisterAppResource成对注册的模式——作业解答是这套模式的精炼版。前端 UImcp-app.html标记作业的 UI 标记位于 mcp-app.html满足作业全部三条 UI 要求!DOCTYPE html html langen head meta charsetUTF-8 / titleRock paper scissor/title /head body div classrock-paper-scissors h1Rock Paper Scissors/h1 select idrps-options valuerock option valuerockRock/option option valuepaperPaper/option option valuescissorsScissors/option /select button classselect idrps-buttonSelect/button pResult: code idrps-result.../code/p /div script typemodule src/src/mcp-app.ts/script /body /html对应作业验收点select idrps-options提供三个选项的下拉列表、button idrps-button是提交选择的按钮、code idrps-result是展示结果的标签。页面最后以模块方式引入/src/mcp-app.ts即事件绑定脚本。前端逻辑src/mcp-app.ts的事件绑定与工具调用assignment 版 mcp-app.ts 是整个交互的枢纽它完整演示了「获取元素引用 → 创建 App → 处理工具结果 → 绑定事件 → 连接 Host」的标准流程import { App } from modelcontextprotocol/ext-apps; // 获取元素引用 const serverTimeEl document.getElementById(server-time)!; // rps const getRpsBtn document.getElementById(rps-button)!; const rpsResponseEl document.getElementById(rps-result)!; const rpsOptions document.getElementById(rps-options) as HTMLSelectElement; // 创建 App 实例 const app new App({ name: Get Time App, version: 1.0.0 }); // 处理来自服务器的工具结果。必须在 app.connect() 之前设置 // 以免错过最初的工具结果。 app.ontoolresult (result) { const time result.content?.find((c) c.type text)?.text; serverTimeEl.textContent time ?? [ERROR]; }; getRpsBtn.addEventListener(click, async () { const userChoice rpsOptions.value; const result await app.callServerTool({ name: play-rps, arguments: { choice: userChoice } }); const rpsResult result.content?.find((c) c.type text)?.text; rpsResponseEl.textContent rpsResult ?? [ERROR]; }); // 连接到 Host app.connect();这段代码的核心机制new App({ name, version })来自modelcontextprotocol/ext-apps包封装了与父页面通信的协议细节app.callServerTool({ name: play-rps, arguments: { choice: userChoice } })是请求后端的关键调用——正如课程主文档所述它实际上向父窗口发送消息由父窗口Host转发并调用 MCP Server从返回结果中取出content里type text的文本渲染到rps-result没有结果时兜底显示[ERROR]app.ontoolresult在connect()之前赋值避免遗漏初始工具结果app.connect()放在最后完成与 Host 的连接握手。如何运行与验证作业文档给出的运行方式为参考 code/typescript/README.md 的完整工程再把作业三个文件的内容分别填入对应文件中。完整工程的运行步骤如下安装依赖并校验编译# 进入 my-app 目录 npm install # 同时安装前端与后端依赖 npx tsc --noEmit # 校验后端编译无输出即代表通过依赖清单可在 code 版 package.json 中看到运行时依赖modelcontextprotocol/ext-apps、modelcontextprotocol/sdk、express、cors开发依赖包括typescript、tsx、vite、vite-plugin-singlefile、concurrently、cross-env等要求 Node.js 20。启动后端npm start该命令由concurrently并行执行两件事cross-env NODE_ENVdevelopment INPUTmcp-app.html vite build --watch开发模式增量打包 UI和tsx watch main.ts热重启 MCP 服务端。启动后 MCP 端点位于http://localhost:3001/mcp。注意若在 Windows 上运行concurrently可能需要替换为等效工具若在 Codespace 中需要把端口可见性设为 public并通过https://Codespace 名称.app.github.dev/mcp验证端点可达。后端入口 main.ts 揭示了端点的实现方式使用createMcpExpressApp创建 Express 应用启用 CORS允许GET/POST/OPTIONS请求头含Content-Type、Authorization、MCP-Protocol-Version并在/mcp路由上为每个请求创建一次McpServer实例与StreamableHTTPServerTransport无会话 ID 的无状态模式。配套的 vite.config.ts 使用vite-plugin-singlefile把 UI 打包为单个 HTML 文件开发模式内联 sourcemap这正是registerAppResource能直接读取dist/mcp-app.html的原因。方案一在 Visual Studio Code 中测试在.vscode/mcp.json中注册服务器{ servers: { my-mcp-server-7178eca7: { url: http://localhost:3001/mcp, type: http } }, inputs: [] }点击mcp.json中的启动按钮在聊天窗口输入工具名课程示例为get-faq作业对应play-rps即可看到 MCP App 的 UI 渲染出来——这是目前测试 MCP Apps 最便捷的方式之一。方案二使用独立 Host 测试克隆ext-apps仓库后进入ext-apps目录执行npm install在另一个终端进入ext-apps/examples/basic-host执行npm startHost 会连接到后端并渲染 MCP App 界面。在 Codespace 环境中需要修改serve.ts中第 27 行的http://localhost:3001/mcp为你的 Codespace 后端地址形如https://name-3001.app.github.dev/mcp。验证游戏功能在渲染出的界面上从下拉框选择 Rock / Paper / Scissors点击 Select 按钮rps-result区域会显示类似「You win! You chose rock and I chose scissors.」的判定结果同时可通过点击「Call Tool」按钮查看工具返回的原始数据。从源码看 MCP Apps 的工作原理结合本作业与课程完整版代码可以提炼出 MCP Apps 的几条核心原理工具 资源成对注册resourceUri是唯一纽带registerAppTool的_meta.ui.resourceUri与registerAppResource的第一个参数指向同一个 URI如ui://get-time/mcp-app.htmlHost 据此把工具调用和 UI 渲染绑定。UI 在 IFrame 中运行出于安全考虑MCP App 的 HTML 被注入 IFrame 容器与父页面隔离。通信走消息转发IFrame 内的app.callServerTool()不直接发起网络请求而是向父窗口postMessage由 Host 代为调用 MCP Server 并回传结果——这是modelcontextprotocol/ext-apps等库封装的核心能力。数据与 UI 一同交付工具仍以标准 MCP 的content结构返回文本数据同时服务器附带可渲染的组件资源这正是「让 MCP Server 对数据如何呈现也有发言权」的范式落点。小结与关键收获本作业是对 MCP Apps 范式的完整练习服务端用registerAppToolregisterAppResource成对注册play-rps工具与其 UI 资源前端用mcp-app.html定义交互界面、src/mcp-app.ts负责事件绑定与callServerTool调用最终通过 VSCode 或独立 Host 验证游戏可玩。完成本作业后你已具备在 TypeScript 中构建和集成自有 MCP App 的能力可以继续深入 04-PracticalImplementation 章节把这些组件化能力应用到更完整的实际实现中。赞分享教程文档人工智能【免费下载链接】mcp-for-beginnersThis 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 实战作业用 TypeScript 构建带 UI 的石头剪刀布Rock-Paper-ScissorsMCP AppMCP Apps 实战作业用 TypeScript 构建带 UI 的石头剪刀布Rock Paper ScissorsMCP App 本篇文章基于 mcp教程文档人工智能MCP Apps 实战在 mcp-for-beginners 中用 TypeScript 构建带交互 UI 的石头剪刀布 MCP 应用MCP Apps 实战在 mcp for beginners 中用 TypeScript 构建带交互 UI 的石头剪刀布 MCP 应用 导读 本文围绕 mcp教程文档人工智能在 TypeScript 中构建剪刀石头布 MCP AppregisterAppTool 与 registerAppResource 实战在 TypeScript 中构建剪刀石头布 MCP AppregisterAppTool 与 registerAppResource 实战 MCP Apps教程文档人工智能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表