Skip to main content

Function: registerAppResource()

registerAppResource(__namedParameters): RegisteredAppResource

Defined in: registerAppResource.ts:201

Registers an MCP Apps view: a ui:// resource a tool result is rendered with, per the io.modelcontextprotocol/ui extension.

The extension asks nothing of the transport — a view is an ordinary MCP resource, and the tool linkage is ordinary tool _meta — so this is registration sugar over registerResource, not new protocol surface. What it owns is the part that is easy to get wrong: the ui:// scheme, the exact MIME type, _meta.ui on both the declaration and the read result, and writing the deprecated flat linkage key alongside the current one.

Register the linkage unconditionally. The extension's negotiation is per-request and only reliably readable on the 2026-07-28 revision; in this package's default stateless 2025-era mode there is no remembered initialize to read a client capability from. Gating registration on that capability would therefore silently drop the view for every 2025-era client. A host without Apps support simply ignores _meta, so keep each tool's content meaningful on its own and let the text result be the fallback.

Parameters

ParameterType
__namedParametersRegisterAppResourceParams

Returns

RegisteredAppResource

Example

import {
McpServer,
registerAppResource,
UI_EXTENSION_ID,
UI_RESOURCE_MIME_TYPE,
z,
} from '@ttoss/http-server-mcp';

const server = new McpServer(
{ name: 'weather', version: '1.0.0' },
{
capabilities: {
extensions: { [UI_EXTENSION_ID]: { mimeTypes: [UI_RESOURCE_MIME_TYPE] } },
},
}
);

const dashboard = registerAppResource({
server,
name: 'weather_dashboard',
uri: 'ui://weather/dashboard',
description: 'Interactive weather dashboard',
html: dashboardHtml,
ui: {
csp: { connectDomains: ['https://api.openweathermap.org'] },
prefersBorder: true,
},
});

server.registerTool(
'get-weather',
{
description: 'Get the weather for a location',
inputSchema: { location: z.string() },
_meta: dashboard.toolMeta(),
},
async ({ location }) => {
const forecast = await fetchForecast(location);
return {
// Text stays meaningful: it is what a host without Apps renders.
content: [{ type: 'text', text: summarise(forecast) }],
structuredContent: forecast,
};
}
);