Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions examples/basic-server-react/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
26 changes: 12 additions & 14 deletions examples/basic-server-vanillajs/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,47 @@ 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({
name: "Basic MCP App Server (Vanilla JS)",
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",
{
title: "Get Time",
description: "Returns the current server time as an ISO 8601 string.",
inputSchema: {},
_meta: { [RESOURCE_URI_META_KEY]: RESOURCE_URI },
_meta: { [RESOURCE_URI_META_KEY]: resourceUri },
},
async (): Promise<CallToolResult> => {
const time = new Date().toISOString();
return {
content: [{ type: "text", text: JSON.stringify({ time }) }],
};
return { content: [{ type: "text", text: time }] };
},
);

// 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 },
],
};
},
Expand Down
Loading