MCP Fusion/Protocol and runtime/Motor de prompts

Motor de prompts

Pergunte à IA sobre a Vinkius

Prompts são cidadãos de primeira classe ao lado das tools: schemas de argumentos tipados, execução de tools em loopback a partir de handlers de prompt, paginação com cursores assinados, interceptadores e prazos de hidratação.

Tools executam; prompts semeiam. Um prompt é um template reutilizável, do lado do servidor, para uma conversa: o cliente lista os prompts, o usuário escolhe um e o servidor devolve o conjunto de mensagens. O MCP Fusion trata os prompts com a mesma engenharia das tools: entradas tipadas, middleware, paginação e um loopback para o seu próprio tool pipeline.

Definindo um prompt

typescript
import { z } from 'zod';

export default f.prompt('issue.review')
  .describe('Review a pull request with the team checklist')
  .input(z.object({
    repo: z.string().describe('Repository slug'),
    pr: z.number().describe('Pull request number'),
  }))
  .handler(async (ctx, args) => ({
    description: 'Review acme/product#42 against the checklist',
    messages: [
      { role: 'user', content: `Review PR ${args.pr} in ${args.repo}. Use the checklist.` },
      { role: 'assistant', content: 'Sharing the checklist first, then the diff.' },
    ],
  }));

A forma fluent espelha a das tools: .describe(), .input() (um objeto Zod, ou um map plano de descritores de argumentos primitivos), .use(middleware), .title(), .icons(), .tags() e o terminal .handler((ctx, args) => PromptResult). O resultado é { description?, messages } com os papéis user e assistant, múltiplos turnos são permitidos, e há blocos de conteúdo além de texto: image, audio, resource_link, resource e os helpers de fábrica do PromptMessage (.system() é codificado como user: o MCP não tem papel system).

A forma declarativa, definePrompt, e a forma f.prompt(name, config) no estilo f.presenter() existem para layouts de config-as-code. Os argumentos compilam para Zod com validação plana e estrita: só primitivos, sem arrays nem objetos aninhados. Essa é uma restrição do MCP, imposta no momento da definição com um erro claro, e não no momento do wire.

Loopback: prompts que chamam tools

O contexto do handler de prompt inclui invokeTool(name, args), um dispatcher para o mesmo tool pipeline, com middleware, validação e Presenters. Um prompt, portanto, não é uma string estática: ele pode buscar o diff ao vivo do PR com as próprias tools do usuário, hidratar o checklist e só então devolver as mensagens semeadas. O RBAC é aplicado dentro do loopback (o contexto de quem chama é o contexto de quem chama), e o AbortSignal da requisição se propaga, de modo que um prompt cancelado cancela o trabalho de tools que ele disparou.

A hidratação tem limite: um prazo por registry (.timeout(ms) no builder ou setDefaultHydrationTimeout) define quanto tempo um prompt pode gastar chamando tools antes de devolver. Passado o prazo, a resposta sai com um bloco de alerta de hidratação, em vez de travar o cliente.

Paginação e ciclo de vida

prompts/list é paginado no servidor: CursorCodec transforma o nome "after" em um cursor que é assinado com HMAC-SHA256 ou criptografado com AES-GCM (configurado com um segredo de 32 bytes; sem um, vale uma chave efêmera por processo). O tamanho de página padrão é 50, com suporte a filtragem por tags. Por design, um cursor é opaco para os clientes.

notifyPromptListChanged() (ou o caminho do evento list_changed em mutações de f.prompt em tempo de execução) envia notifications/prompts/list_changed com debounce de 100ms, para que um registry que cresce durante uma sessão não inunde o cliente.

Interceptadores

registry.useInterceptor(fn) roda depois que um handler retorna e antes que o cliente veja o resultado: acrescentar um <compliance_notice>, prefixar um turno de usuário ou injetar blocos de contexto envolvidos em uma tag. Interceptar é o jeito seguro de adicionar diretrizes para toda a organização sem editar cada prompt.

Por que isso importa

O imposto de integração de quem constrói sobre o MCP costuma ser "o cliente só tem tools". Os prompts fecham a outra metade: você entrega o workflow, não apenas a capacidade. Combinados com Tools, Resources e o Wire format, um único conector pode entregar a um agente a forma completa de como trabalhar com os seus dados, no protocolo nativo do agente.

Próximos passos