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
| Parameter | Type |
|---|---|
__namedParameters | RegisterAppResourceParams |
Returns
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,
};
}
);