Replace deprecated RESOURCE_URI_META_KEY with _meta.ui.resourceUri

Update all example servers to use the new recommended metadata format
for associating UI resources with tools. The old `RESOURCE_URI_META_KEY`
constant is deprecated in favor of the nested `_meta.ui.resourceUri`
structure.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jonathan Hefner 2026-01-08 07:07:37 -06:00
commit 94bc708963
12 changed files with 50 additions and 60 deletions

View file

@ -1,9 +1,9 @@
import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js"; import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY } from "@modelcontextprotocol/ext-apps/server";
import { startServer } from "./server-utils.js"; import { startServer } from "./server-utils.js";
const DIST_DIR = path.join(import.meta.dirname, "dist"); const DIST_DIR = path.join(import.meta.dirname, "dist");
@ -21,15 +21,15 @@ export function createServer(): McpServer {
const resourceUri = "ui://get-time/mcp-app.html"; const resourceUri = "ui://get-time/mcp-app.html";
// Register a tool with UI metadata. When the host calls this tool, it reads // 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 // `_meta.ui.resourceUri` to know which resource to fetch and render as an
// as an interactive UI. // interactive UI.
registerAppTool(server, registerAppTool(server,
"get-time", "get-time",
{ {
title: "Get Time", title: "Get Time",
description: "Returns the current server time as an ISO 8601 string.", description: "Returns the current server time as an ISO 8601 string.",
inputSchema: {}, inputSchema: {},
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async (): Promise<CallToolResult> => { async (): Promise<CallToolResult> => {
const time = new Date().toISOString(); const time = new Date().toISOString();

View file

@ -1,10 +1,10 @@
import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js"; import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { z } from "zod"; import { z } from "zod";
import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY } from "@modelcontextprotocol/ext-apps/server";
import { startServer } from "./server-utils.js"; import { startServer } from "./server-utils.js";
const DIST_DIR = path.join(import.meta.dirname, "dist"); const DIST_DIR = path.join(import.meta.dirname, "dist");
@ -22,8 +22,8 @@ export function createServer(): McpServer {
const resourceUri = "ui://get-time/mcp-app.html"; const resourceUri = "ui://get-time/mcp-app.html";
// Register a tool with UI metadata. When the host calls this tool, it reads // 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 // `_meta.ui.resourceUri` to know which resource to fetch and render as an
// as an interactive UI. // interactive UI.
registerAppTool(server, registerAppTool(server,
"get-time", "get-time",
{ {
@ -33,7 +33,7 @@ export function createServer(): McpServer {
outputSchema: z.object({ outputSchema: z.object({
time: z.string(), time: z.string(),
}), }),
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async (): Promise<CallToolResult> => { async (): Promise<CallToolResult> => {
const time = new Date().toISOString(); const time = new Date().toISOString();

View file

@ -15,7 +15,6 @@ import path from "node:path";
import { z } from "zod"; import { z } from "zod";
import { import {
RESOURCE_MIME_TYPE, RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
registerAppResource, registerAppResource,
registerAppTool, registerAppTool,
} from "@modelcontextprotocol/ext-apps/server"; } from "@modelcontextprotocol/ext-apps/server";
@ -273,7 +272,7 @@ export function createServer(): McpServer {
"Returns budget configuration with 24 months of historical allocations and industry benchmarks by company stage", "Returns budget configuration with 24 months of historical allocations and industry benchmarks by company stage",
inputSchema: {}, inputSchema: {},
outputSchema: BudgetDataResponseSchema, outputSchema: BudgetDataResponseSchema,
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async (): Promise<CallToolResult> => { async (): Promise<CallToolResult> => {
const response: BudgetDataResponse = { const response: BudgetDataResponse = {

View file

@ -6,7 +6,6 @@ import path from "node:path";
import { z } from "zod"; import { z } from "zod";
import { import {
RESOURCE_MIME_TYPE, RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
registerAppResource, registerAppResource,
registerAppTool, registerAppTool,
} from "@modelcontextprotocol/ext-apps/server"; } from "@modelcontextprotocol/ext-apps/server";
@ -181,7 +180,7 @@ export function createServer(): McpServer {
"Returns cohort retention heatmap data showing customer retention over time by signup month", "Returns cohort retention heatmap data showing customer retention over time by signup month",
inputSchema: GetCohortDataInputSchema.shape, inputSchema: GetCohortDataInputSchema.shape,
outputSchema: CohortDataSchema.shape, outputSchema: CohortDataSchema.shape,
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async ({ metric, periodType, cohortCount, maxPeriods }) => { async ({ metric, periodType, cohortCount, maxPeriods }) => {
const data = generateCohortData( const data = generateCohortData(

View file

@ -9,7 +9,6 @@ import path from "node:path";
import { z } from "zod"; import { z } from "zod";
import { import {
RESOURCE_MIME_TYPE, RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
registerAppResource, registerAppResource,
registerAppTool, registerAppTool,
} from "@modelcontextprotocol/ext-apps/server"; } from "@modelcontextprotocol/ext-apps/server";
@ -102,7 +101,7 @@ export function createServer(): McpServer {
"Returns customer data with segment information for visualization. Optionally filter by segment.", "Returns customer data with segment information for visualization. Optionally filter by segment.",
inputSchema: GetCustomerDataInputSchema.shape, inputSchema: GetCustomerDataInputSchema.shape,
outputSchema: GetCustomerDataOutputSchema.shape, outputSchema: GetCustomerDataOutputSchema.shape,
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async ({ segment }): Promise<CallToolResult> => { async ({ segment }): Promise<CallToolResult> => {
const data = getCustomerData(segment); const data = getCustomerData(segment);

View file

@ -1,3 +1,8 @@
import {
registerAppResource,
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { import type {
@ -7,12 +12,6 @@ import type {
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { z } from "zod"; import { z } from "zod";
import {
registerAppTool,
registerAppResource,
RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
} from "@modelcontextprotocol/ext-apps/server";
import { startServer } from "./server-utils.js"; import { startServer } from "./server-utils.js";
const DIST_DIR = path.join(import.meta.dirname, "dist"); const DIST_DIR = path.join(import.meta.dirname, "dist");
@ -37,7 +36,7 @@ export function createServer(): McpServer {
outputSchema: z.object({ outputSchema: z.object({
time: z.string(), time: z.string(),
}), }),
_meta: { [RESOURCE_URI_META_KEY]: RESOURCE_URI }, _meta: { ui: { resourceUri: RESOURCE_URI } },
}, },
async (): Promise<CallToolResult> => { async (): Promise<CallToolResult> => {
const time = new Date().toISOString(); const time = new Date().toISOString();

View file

@ -1,3 +1,8 @@
import {
RESOURCE_MIME_TYPE,
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { import type {
@ -7,12 +12,6 @@ import type {
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { z } from "zod"; import { z } from "zod";
import {
RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
import { startServer } from "./server-utils.js"; import { startServer } from "./server-utils.js";
const DIST_DIR = path.join(import.meta.dirname, "dist"); const DIST_DIR = path.join(import.meta.dirname, "dist");
@ -308,7 +307,7 @@ export function createServer(): McpServer {
"Returns SaaS scenario templates and optionally computes custom projections for given inputs", "Returns SaaS scenario templates and optionally computes custom projections for given inputs",
inputSchema: GetScenarioDataInputSchema.shape, inputSchema: GetScenarioDataInputSchema.shape,
outputSchema: GetScenarioDataOutputSchema.shape, outputSchema: GetScenarioDataOutputSchema.shape,
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async (args: { async (args: {
customInputs?: ScenarioInputs; customInputs?: ScenarioInputs;

View file

@ -9,7 +9,6 @@ import { z } from "zod";
import ABCJS from "abcjs"; import ABCJS from "abcjs";
import { import {
RESOURCE_MIME_TYPE, RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
registerAppResource, registerAppResource,
registerAppTool, registerAppTool,
} from "@modelcontextprotocol/ext-apps/server"; } from "@modelcontextprotocol/ext-apps/server";
@ -59,7 +58,7 @@ function createServer(): McpServer {
"ABC notation string to render as sheet music with audio playback", "ABC notation string to render as sheet music with audio playback",
), ),
}), }),
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async ({ abcNotation }): Promise<CallToolResult> => { async ({ abcNotation }): Promise<CallToolResult> => {
// Validate ABC notation using abcjs parser // Validate ABC notation using abcjs parser

View file

@ -1,3 +1,8 @@
import {
RESOURCE_MIME_TYPE,
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { import type {
@ -9,12 +14,6 @@ import os from "node:os";
import path from "node:path"; import path from "node:path";
import si from "systeminformation"; import si from "systeminformation";
import { z } from "zod"; import { z } from "zod";
import {
RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
import { startServer } from "./server-utils.js"; import { startServer } from "./server-utils.js";
// Schemas - types are derived from these using z.infer // Schemas - types are derived from these using z.infer
@ -149,7 +148,7 @@ export function createServer(): McpServer {
"Returns current system statistics including per-core CPU usage, memory, and system info.", "Returns current system statistics including per-core CPU usage, memory, and system info.",
inputSchema: {}, inputSchema: {},
outputSchema: SystemStatsSchema.shape, outputSchema: SystemStatsSchema.shape,
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async (): Promise<CallToolResult> => { async (): Promise<CallToolResult> => {
const stats = await getStats(); const stats = await getStats();

View file

@ -3,18 +3,17 @@
* *
* Provides tools for rendering interactive 3D scenes using Three.js. * Provides tools for rendering interactive 3D scenes using Three.js.
*/ */
import {
RESOURCE_MIME_TYPE,
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { ReadResourceResult } from "@modelcontextprotocol/sdk/types.js"; import type { ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { z } from "zod"; import { z } from "zod";
import {
RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
import { startServer } from "./server-utils.js"; import { startServer } from "./server-utils.js";
const DIST_DIR = path.join(import.meta.dirname, "dist"); const DIST_DIR = path.join(import.meta.dirname, "dist");
@ -170,7 +169,7 @@ export function createServer(): McpServer {
code: z.string(), code: z.string(),
height: z.number(), height: z.number(),
}), }),
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async ({ code, height }) => { async ({ code, height }) => {
const data = { code, height }; const data = { code, height };

View file

@ -4,24 +4,23 @@
* Demonstrates serving binary content (video) via MCP resources. * Demonstrates serving binary content (video) via MCP resources.
* The server fetches videos from CDN and serves them as base64 blobs. * The server fetches videos from CDN and serves them as base64 blobs.
*/ */
import {
registerAppResource,
registerAppTool,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
import { import {
McpServer, McpServer,
ResourceTemplate, ResourceTemplate,
} from "@modelcontextprotocol/sdk/server/mcp.js"; } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { import type {
CallToolResult, CallToolResult,
ReadResourceResult, ReadResourceResult,
} from "@modelcontextprotocol/sdk/types.js"; } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { import { z } from "zod";
registerAppTool,
registerAppResource,
RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
} from "@modelcontextprotocol/ext-apps/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { startServer } from "./server-utils.js"; import { startServer } from "./server-utils.js";
const DIST_DIR = path.join(import.meta.dirname, "dist"); const DIST_DIR = path.join(import.meta.dirname, "dist");
@ -133,7 +132,7 @@ ${Object.entries(VIDEO_LIBRARY)
videoUri: z.string(), videoUri: z.string(),
description: z.string(), description: z.string(),
}), }),
_meta: { [RESOURCE_URI_META_KEY]: RESOURCE_URI }, _meta: { ui: { resourceUri: RESOURCE_URI } },
}, },
async ({ videoId }): Promise<CallToolResult> => { async ({ videoId }): Promise<CallToolResult> => {
const video = VIDEO_LIBRARY[videoId]; const video = VIDEO_LIBRARY[videoId];

View file

@ -1,3 +1,8 @@
import {
RESOURCE_MIME_TYPE,
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { import type {
@ -8,12 +13,6 @@ import * as cheerio from "cheerio";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { z } from "zod"; import { z } from "zod";
import {
RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
registerAppResource,
registerAppTool,
} from "@modelcontextprotocol/ext-apps/server";
import { startServer } from "./server-utils.js"; import { startServer } from "./server-utils.js";
const DIST_DIR = path.join(import.meta.dirname, "dist"); const DIST_DIR = path.join(import.meta.dirname, "dist");
@ -108,7 +107,7 @@ export function createServer(): McpServer {
), ),
error: z.string().nullable(), error: z.string().nullable(),
}), }),
_meta: { [RESOURCE_URI_META_KEY]: resourceUri }, _meta: { ui: { resourceUri } },
}, },
async ({ url }): Promise<CallToolResult> => { async ({ url }): Promise<CallToolResult> => {
let title = url; let title = url;