Replace deprecated RESOURCE_URI_META_KEY usage with modern format (#457)

This commit is contained in:
Hryhorii (Greg) Avcharov 2026-03-06 15:32:04 +01:00 • committed by GitHub
commit 19fe73a08a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 80 additions and 28 deletions

View file

@ -17,7 +17,6 @@ import {
registerAppTool,
registerAppResource,
RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
} from "@modelcontextprotocol/ext-apps/server";
import { randomUUID } from "crypto";
@ -25,7 +24,7 @@ import { randomUUID } from "crypto";
const DIST_DIR = import.meta.filename.endsWith(".ts")
? path.join(import.meta.dirname, "dist")
: import.meta.dirname;
const RESOURCE_URI = "ui://cesium-map/mcp-app.html";
const resourceUri = "ui://cesium-map/mcp-app.html";
// Nominatim API response type
interface NominatimResult {
@ -118,8 +117,8 @@ export function createServer(): McpServer {
// Register the CesiumJS map resource with CSP for external tile sources
registerAppResource(
server,
RESOURCE_URI,
RESOURCE_URI,
resourceUri,
resourceUri,
{ mimeType: RESOURCE_MIME_TYPE },
async (): Promise<ReadResourceResult> => {
const html = await fs.readFile(
@ -130,7 +129,7 @@ export function createServer(): McpServer {
contents: [
// CSP metadata on the content item takes precedence over listing-level _meta
{
uri: RESOURCE_URI,
uri: resourceUri,
mimeType: RESOURCE_MIME_TYPE,
text: html,
_meta: cspMeta,
@ -175,7 +174,7 @@ export function createServer(): McpServer {
.optional()
.describe("Optional label to display on the map"),
},
_meta: { [RESOURCE_URI_META_KEY]: RESOURCE_URI },
_meta: { ui: { resourceUri } },
},
async ({ west, south, east, north, label }): Promise<CallToolResult> => ({
content: [

View file

@ -9,13 +9,12 @@ import {
registerAppTool,
registerAppResource,
RESOURCE_MIME_TYPE,
RESOURCE_URI_META_KEY,
} from "@modelcontextprotocol/ext-apps/server";
// Works both from source (server.ts) and compiled (dist/server.js)
const DIST_DIR = import.meta.filename.endsWith(".ts")
? path.join(import.meta.dirname, "dist")
: import.meta.dirname;
const RESOURCE_URI = "ui://transcript/mcp-app.html";
const resourceUri = "ui://transcript/mcp-app.html";
/**
* Creates a new MCP server instance with tools and resources registered.
@ -35,7 +34,7 @@ export function createServer(): McpServer {
description:
"Opens a live speech transcription interface using the Web Speech API.",
inputSchema: {},
_meta: { [RESOURCE_URI_META_KEY]: RESOURCE_URI },
_meta: { ui: { resourceUri } },
},
async (): Promise<CallToolResult> => {
return {
@ -55,8 +54,8 @@ export function createServer(): McpServer {
// Register the UI resource
registerAppResource(
server,
RESOURCE_URI,
RESOURCE_URI,
resourceUri,
resourceUri,
{ mimeType: RESOURCE_MIME_TYPE, description: "Transcript UI" },
async (): Promise<ReadResourceResult> => {
const html = await fs.readFile(
@ -67,7 +66,7 @@ export function createServer(): McpServer {
return {
contents: [
{
uri: RESOURCE_URI,
uri: resourceUri,
mimeType: RESOURCE_MIME_TYPE,
text: html,
_meta: {

View file

@ -12,16 +12,46 @@ import type {
McpServer,
ToolCallback,
} from "@modelcontextprotocol/sdk/server/mcp.js";
import { App, PostMessageTransport, RESOURCE_URI_META_KEY } from "./app.js";
import {
App,
PostMessageTransport,
RESOURCE_URI_META_KEY,
McpUiToolMeta,
} from "./app.js";
import { registerAppTool } from "./server/index.js";
/**
* Example: How MCP servers use RESOURCE_URI_META_KEY (server-side, not in Apps).
* Example: Modern format for registering tools with UI (recommended).
*/
function RESOURCE_URI_META_KEY_serverSide(
function RESOURCE_URI_META_KEY_modernFormat(
server: McpServer,
handler: ToolCallback,
) {
//#region RESOURCE_URI_META_KEY_serverSide
//#region RESOURCE_URI_META_KEY_modernFormat
// Preferred: Use registerAppTool with nested ui.resourceUri
registerAppTool(
server,
"weather",
{
description: "Get weather forecast",
_meta: {
ui: { resourceUri: "ui://weather/forecast" },
},
},
handler,
);
//#endregion RESOURCE_URI_META_KEY_modernFormat
}
/**
* Example: Legacy format using RESOURCE_URI_META_KEY (deprecated).
*/
function RESOURCE_URI_META_KEY_legacyFormat(
server: McpServer,
handler: ToolCallback,
) {
//#region RESOURCE_URI_META_KEY_legacyFormat
// Deprecated: Direct use of RESOURCE_URI_META_KEY
server.registerTool(
"weather",
{
@ -32,16 +62,19 @@ function RESOURCE_URI_META_KEY_serverSide(
},
handler,
);
//#endregion RESOURCE_URI_META_KEY_serverSide
//#endregion RESOURCE_URI_META_KEY_legacyFormat
}
/**
* Example: How hosts check for RESOURCE_URI_META_KEY metadata (host-side).
* Example: How hosts check for RESOURCE_URI_META_KEY metadata (must support both formats).
*/
function RESOURCE_URI_META_KEY_hostSide(tool: Tool) {
//#region RESOURCE_URI_META_KEY_hostSide
// Check tool definition metadata (from tools/list response):
const uiUri = tool._meta?.[RESOURCE_URI_META_KEY];
// Hosts should check both modern and legacy formats
const meta = tool._meta;
const uiMeta = meta?.ui as McpUiToolMeta | undefined;
const legacyUri = meta?.[RESOURCE_URI_META_KEY] as string | undefined;
const uiUri = uiMeta?.resourceUri ?? legacyUri;
if (typeof uiUri === "string" && uiUri.startsWith("ui://")) {
// Fetch the resource and display the UI
}

View file

@ -75,12 +75,30 @@ export {
* When hosts see a tool with this metadata, they fetch and render the
* corresponding {@link App `App`}.
*
* **Note**: This constant is provided for reference. App developers typically
* don't need to use it directly. Prefer using {@link server-helpers!registerAppTool `registerAppTool`}
* with the `_meta.ui.resourceUri` format instead.
* **Note**: This constant is provided for reference and backwards compatibility.
* Server developers should use {@link server-helpers!registerAppTool `registerAppTool`}
* with the `_meta.ui.resourceUri` format instead. Host developers must check both
* formats for compatibility.
*
* @example How MCP servers use this key (server-side, not in Apps)
* ```ts source="./app.examples.ts#RESOURCE_URI_META_KEY_serverSide"
* @example Modern format (server-side, not in Apps)
* ```ts source="./app.examples.ts#RESOURCE_URI_META_KEY_modernFormat"
* // Preferred: Use registerAppTool with nested ui.resourceUri
* registerAppTool(
* server,
* "weather",
* {
* description: "Get weather forecast",
* _meta: {
* ui: { resourceUri: "ui://weather/forecast" },
* },
* },
* handler,
* );
* ```
*
* @example Legacy format (deprecated, for backwards compatibility)
* ```ts source="./app.examples.ts#RESOURCE_URI_META_KEY_legacyFormat"
* // Deprecated: Direct use of RESOURCE_URI_META_KEY
* server.registerTool(
* "weather",
* {
@ -93,10 +111,13 @@ export {
* );
* ```
*
* @example How hosts check for this metadata (host-side)
* @example How hosts check for this metadata (must support both formats)
* ```ts source="./app.examples.ts#RESOURCE_URI_META_KEY_hostSide"
* // Check tool definition metadata (from tools/list response):
* const uiUri = tool._meta?.[RESOURCE_URI_META_KEY];
* // Hosts should check both modern and legacy formats
* const meta = tool._meta;
* const uiMeta = meta?.ui as McpUiToolMeta | undefined;
* const legacyUri = meta?.[RESOURCE_URI_META_KEY] as string | undefined;
* const uiUri = uiMeta?.resourceUri ?? legacyUri;
* if (typeof uiUri === "string" && uiUri.startsWith("ui://")) {
* // Fetch the resource and display the UI
* }