Ir para o conteúdo
decodecodeveloper docs
Studio → MCP Apps e extensões → Criar MCP Apps

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:

  • createPublicResource de @decocms/runtime/tools — cria um resource acessível publicamente
  • uri — deve corresponder ao _meta.ui.resourceUri na definição da ferramenta
  • mimeType — text/html;profile=mcp-app informa ao cliente MCP que este é um MCP App
  • read() — 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.resourceUri na 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 dev executa vite build --watch para 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,
      };
    },
  });