Resources
Disponibilize interfaces de MCP Apps e dados como resources MCP
O que são resources MCP?
Resources MCP são dados somente de leitura expostos pelo seu servidor MCP e identificados por URI. No contexto de MCP Apps, os resources servem principalmente bundles HTML de arquivo único, renderizados como interfaces interativas dentro de clientes MCP.
Resources de MCP Apps
Um resource de MCP App serve o bundle HTML compilado como uma interface interativa para uma ferramenta:
- Tipo MIME:
text/html;profile=mcp-app - Conteúdo: HTML de arquivo único (CSS e JS embutidos), compilado com Vite +
vite-plugin-singlefile - Vinculado a ferramentas por meio de
_meta.ui.resourceUri
Criando um resource
Exemplo básico
Este é o resource hello do template (api/resources/hello.ts):
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { createPublicResource } from "@decocms/runtime/tools";
import { HELLO_RESOURCE_URI } from "../tools/hello.ts";
import type { Env } from "../types/env.ts";
const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
function getDistPath(): string {
const projectRoot = join(import.meta.dir, "../..");
return join(projectRoot, "dist", "client", "index.html");
}
export const helloAppResource = (_env: Env) =>
createPublicResource({
uri: HELLO_RESOURCE_URI,
name: "Hello UI",
description: "Interactive greeting display powered by MCP Apps",
mimeType: RESOURCE_MIME_TYPE,
read: async () => {
const html = await readFile(getDistPath(), "utf-8");
return {
uri: HELLO_RESOURCE_URI,
mimeType: RESOURCE_MIME_TYPE,
text: html,
};
},
});Partes principais:
createPublicResourcede@decocms/runtime/tools— cria um resource acessível publicamenteuri— deve corresponder ao_meta.ui.resourceUrina definição da ferramentamimeType—text/html;profile=mcp-appinforma ao cliente MCP que este é um MCP Appread()— função assíncrona que retorna o conteúdo HTML
Registrando resources
Adicione a função que cria seu resource ao array resources de withRuntime() em api/app.ts. Esse é o núcleo da aplicação no template revisado:
const runtime = withRuntime<Env, typeof StateSchema>({
configuration: { state: StateSchema },
tools,
resources: [helloAppResource, myToolResource],
});URIs dos resources
- Convenção:
ui://<app-name>/<tool-name>(por exemplo,ui://mcp-app/hello) - A URI deve corresponder ao
_meta.ui.resourceUrina definição da ferramenta correspondente - O cliente MCP usa essa URI para encontrar e carregar a interface de um resultado da ferramenta
Exporte a URI do resource como uma constante no arquivo da ferramenta para que ambos referenciem o mesmo valor.
Resultado do build
O Vite compila web/ em dist/client/index.html:
- Todo o CSS e JS ficam embutidos em um único arquivo HTML (via
vite-plugin-singlefile) - O resource lê esse arquivo em tempo de execução e o serve aos clientes MCP
- Durante o desenvolvimento,
bun run devexecutavite build --watchpara manter o bundle atualizado
Múltiplos resources
Se seu app tiver várias ferramentas com interfaces, cada ferramenta terá sua própria definição de resource, mas todas servirão o mesmo bundle HTML. O roteador dentro do bundle (web/router.tsx) seleciona a interface correta com base em toolName, recebido do contexto do host.
// api/resources/analytics.ts
export const analyticsAppResource = (_env: Env) =>
createPublicResource({
uri: ANALYTICS_RESOURCE_URI,
name: "Analytics UI",
description: "Interactive analytics dashboard",
mimeType: "text/html;profile=mcp-app",
read: async () => {
const html = await readFile(getDistPath(), "utf-8");
return {
uri: ANALYTICS_RESOURCE_URI,
mimeType: "text/html;profile=mcp-app",
text: html,
};
},
});