Merge pull request #228 from jonathanhefner/restore-182

Restore educational comments in `basic-server-*` examples
This commit is contained in:
Jonathan Hefner 2026-01-12 12:57:47 -06:00 • committed by GitHub
commit 6e4eb32d1e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 19 additions and 13 deletions

View file

@ -17,21 +17,27 @@ export function createServer(): McpServer {
version: "1.0.0",
});
// Two-part registration: tool + resource, tied together by the resource URI.
const resourceUri = "ui://get-time/mcp-app.html";
// Register a tool with UI metadata. When the host calls this tool, it reads
// `_meta[RESOURCE_URI_META_KEY]` to know which resource to fetch and render
// as an interactive UI.
registerAppTool(server,
"get-time",
{
title: "Get Time",
description: "Returns the current server time.",
description: "Returns the current server time as an ISO 8601 string.",
inputSchema: {},
_meta: { [RESOURCE_URI_META_KEY]: resourceUri },
},
async (): Promise<CallToolResult> => {
return { content: [{ type: "text", text: new Date().toISOString() }] };
const time = new Date().toISOString();
return { content: [{ type: "text", text: time }] };
},
);
// Register the resource, which returns the bundled HTML/JavaScript for the UI.
registerAppResource(server,
resourceUri,
resourceUri,

View file

@ -8,11 +8,9 @@ import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_
import { startServer } from "./server-utils.js";
const DIST_DIR = path.join(import.meta.dirname, "dist");
const RESOURCE_URI = "ui://get-time/mcp-app.html";
/**
* Creates a new MCP server instance with tools and resources registered.
* Each HTTP session needs its own server instance because McpServer only supports one transport.
*/
export function createServer(): McpServer {
const server = new McpServer({
@ -20,9 +18,12 @@ export function createServer(): McpServer {
version: "1.0.0",
});
// MCP Apps require two-part registration: a tool (what the LLM calls) and a
// resource (the UI it renders). The `_meta` field on the tool links to the
// resource URI, telling hosts which UI to display when the tool executes.
// Two-part registration: tool + resource, tied together by the resource URI.
const resourceUri = "ui://get-time/mcp-app.html";
// Register a tool with UI metadata. When the host calls this tool, it reads
// `_meta[RESOURCE_URI_META_KEY]` to know which resource to fetch and render
// as an interactive UI.
registerAppTool(server,
"get-time",
{
@ -32,7 +33,7 @@ export function createServer(): McpServer {
outputSchema: z.object({
time: z.string(),
}),
_meta: { [RESOURCE_URI_META_KEY]: RESOURCE_URI },
_meta: { [RESOURCE_URI_META_KEY]: resourceUri },
},
async (): Promise<CallToolResult> => {
const time = new Date().toISOString();
@ -43,18 +44,17 @@ export function createServer(): McpServer {
},
);
// Register the resource, which returns the bundled HTML/JavaScript for the UI.
registerAppResource(server,
RESOURCE_URI,
RESOURCE_URI,
resourceUri,
resourceUri,
{ mimeType: RESOURCE_MIME_TYPE },
async (): Promise<ReadResourceResult> => {
const html = await fs.readFile(path.join(DIST_DIR, "mcp-app.html"), "utf-8");
return {
contents: [
// Per the MCP App specification, "text/html;profile=mcp-app" signals
// to the Host that this resource is indeed for an MCP App UI.
{ uri: RESOURCE_URI, mimeType: RESOURCE_MIME_TYPE, text: html },
{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html },
],
};
},