服务器需要做两件事:注册一个包含 _meta.ui.resourceUri 字段的工具,以及注册一个提供打包后 HTML 的资源处理器。以下是完整的服务器文件:
// server.tsconsole.log("Starting MCP App server...");import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE,} from "@modelcontextprotocol/ext-apps/server";import cors from "cors";import express from "express";import fs from "node:fs/promises";import path from "node:path";const server = new McpServer({ name: "My MCP App Server", version: "1.0.0",});// The ui:// scheme tells hosts this is an MCP App resource.// The path structure is arbitrary; organize it however makes sense for your app.const resourceUri = "ui://get-time/mcp-app.html";// Register the tool that returns the current timeregisterAppTool( server, "get-time", { title: "Get Time", description: "Returns the current server time.", inputSchema: {}, _meta: { ui: { resourceUri } }, }, async () => { const time = new Date().toISOString(); return { content: [{ type: "text", text: time }], }; },);// Register the resource that serves the bundled HTMLregisterAppResource( server, resourceUri, resourceUri, { mimeType: RESOURCE_MIME_TYPE }, async () => { const html = await fs.readFile( path.join(import.meta.dirname, "dist", "mcp-app.html"), "utf-8", ); return { contents: [ { uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }, ], }; },);// Expose the MCP server over HTTPconst expressApp = express();expressApp.use(cors());expressApp.use(express.json());expressApp.post("/mcp", async (req, res) => { const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true, }); res.on("close", () => transport.close()); await server.connect(transport); await transport.handleRequest(req, res, req.body);});expressApp.listen(3001, (err) => { if (err) { console.error("Error starting server:", err); process.exit(1); } console.log("Server listening on http://localhost:3001/mcp");});