mcpapinpmagentesiatamperlens

Um MCP server para a sua API: as decisões de empacotamento que importam

Douglas Haruo 11 min 26/08/2026

MCP (Model Context Protocol) virou a resposta padrão para “como um agente de IA usa o seu produto”. Empacotar uma API REST existente como MCP server, o pacote que entrega essa API a um agente, é um projeto pequeno com decisões desproporcionalmente importantes. Esta é a nota de campo do tamperlens-mcp. Ele expõe a API do Tamperlens como quatro ferramentas instaláveis por npx, e está publicado no npm e no MCP Registry oficial.

O formato de sempre: as decisões com os porquês e os dois incidentes que viraram guarda. No final, a leitura honesta sobre registries como canal de distribuição, menos animadora e mais útil do que o hype.


Decisão 1: superfície mínima — ferramentas, não endpoints

A API tem mais rotas do que o MCP server expõe. O server tem quatro ferramentas: inspecionar um documento a fundo, fazer a triagem barata antes de ingerir, checar redação, comparar dois documentos. Ferramenta de agente não é espelho de API: é verbo que um modelo consegue escolher com segurança.

Cada endpoint a mais na superfície MCP é uma decisão a mais que o modelo pode tomar errado. É também uma descrição a mais competindo por atenção no contexto, e um caminho a mais para manter. A pergunta de design não é “o que a API faz?”, é “quais são as poucas coisas que um agente faria com isto num fluxo real?”. O resto continua disponível na API REST para quem programa. MCP é para quem conversa.

Correção de 26 de agosto de 2026. Esta seção foi publicada dizendo três ferramentas, e listando três. São quatro: a triage_document — a pré-checagem barata que lê estrutura, metadados e assinaturas sem a varredura página a página, e devolve a faixa de risco junto do custo medido — entrou no engine 1.34 em 24 de agosto, dois dias antes deste post ir ao ar. O texto não acompanhou. É exatamente o modo de falha da Decisão 4, aqui embaixo, com uma diferença que dói: lá existe um teste amarrando o artefato publicado à versão do sistema que ele descreve, e num post não existe. A contagem e a lista foram corrigidas em todos os pontos do texto.

Decisão 2: caminho de arquivo, nunca base64 inline

A decisão mais estrutural do pacote: as ferramentas aceitam caminho absoluto de arquivo, e recusam conteúdo binário inline.

O motivo é o custo no lugar errado. Documento entra em megabytes. O base64 inflaria o binário em ~33% e o faria atravessar o contexto do modelo. Isso é pagar tokens para transportar bytes que o modelo não deveria ler, estourar limites de mensagem e degradar exatamente o fluxo que o MCP deveria facilitar. Com caminho de arquivo, o binário vai do disco para a API pelo server, e o modelo só trafega o que lhe diz respeito: o caminho, e depois o relatório.

Só que “o server lê arquivo local que o modelo nomeia” é uma frase que deveria arrepiar. É aqui que a decisão exige a contrapartida de segurança:

  • TAMPERLENS_ALLOWED_DIRS confina as leituras. O server só lê dentro dos diretórios que o usuário listou na configuração. Sem allowlist explícita, um agente confuso (ou um prompt injetado num documento, ironia que este produto conhece bem) poderia pedir a inspeção de ~/.ssh/id_rsa.
  • Symlink é resolvido antes de decidir. Um link simbólico dentro do diretório permitido apontando para fora dele é resolvido e recusado. Allowlist de caminho sem resolução de symlink é uma porta com a chave pendurada na fechadura.
  • E o mesmo rigor para URLs: o módulo de guarda anti-SSRF valida qualquer origem remota. Um server MCP que baixa o que mandarem é um proxy de rede interna esperando acontecer.

A regra geral: quando a conveniência do agente exige que o server toque o mundo (disco, rede), o confinamento vira a feature principal do pacote, não uma nota de rodapé.

Decisão 3: funciona sem chave — com a quota anônima do free tier

O server funciona sem API key, caindo na mesma quota anônima do checker gratuito do produto (10 documentos/hora). Com chave, usa a conta.

Isso importa porque o primeiro contato de um agente com a ferramenta é exploratório: alguém instala, aponta para um PDF, olha o relatório. Exigir cadastro antes desse momento mata a exploração; deixar ilimitado convida abuso. A quota anônima que o produto já tinha resolve os dois. É também um argumento para desenhar o free tier na API, e não no cliente: todos os empacotamentos (site, MCP, integrações) herdam o mesmo funil sem lógica duplicada.

Decisão 4: a versão do pacote É a versão do engine — por teste

A decisão mais idiossincrática, nascida de incidente. O pacote MCP reporta a versão do engine que responde pela análise. Um teste garante que a versão do pacote npm é idêntica à versão do engine. Publicar o pacote é afirmar “isto descreve o comportamento desta versão do detector”.

O incidente que fez a regra: uma publicação saiu de um checkout desatualizado, sete releases atrás do main. Ela subiu para o npm um pacote cuja versão dizia uma coisa e cujo código era outra. As guardas que ficaram, em camadas:

  1. prepublishOnly roda a suíte, e a suíte inclui o teste de versão. O publish de árvore velha morre antes de sair.
  2. A ordem de publicação é contrato documentado: deploy do engine → publish no npm → publish no registry MCP. Nunca fora de ordem, porque cada passo afirma algo sobre o anterior.
  3. E a guarda mais inesperada mora no script de backup. A rotina noturna da máquina de operação faz git pull --ff-only dos checkouts principais, com salvaguardas para branch trocada, árvore suja e rebase no meio. Assim, “checkout esquecido no passado” deixa de ser um estado que sobrevive até a próxima publicação humana.

A lição generalizada: artefato publicado que descreve outro sistema precisa de um elo verificável com a versão desse sistema. Sem o elo, a divergência não é risco: é cronograma. E a defesa não mora só no CI: mora em cada lugar onde um humano pode operar sobre estado velho.

Decisão 5: o registry, o namespace via DNS e o repo espelho

Publicar no MCP Registry oficial, o catálogo onde os servers ficam listados, exigiu dois movimentos que valem registro:

  • O namespace é provado por DNS. O nome com.tamperlens/mcp foi reivindicado com um registro TXT no apex do domínio. O registry verifica que quem publica controla o domínio que o nome invoca. É o modelo certo, provar controle em vez de pagar taxa. Publicar um MCP server “oficial” do seu produto começa no seu DNS, não no seu código.
  • O repositório público é um espelho dedicado. O produto vive em monorepo privado, e um link de “source” que dá 404 para o público mina a confiança que o registry existe para criar. O pacote aponta para um repo público próprio. É mais um artefato para manter, e o preço correto de listar algo como aberto.

Publicado, o server ficou encontrável na busca do registry no mesmo minuto. O que nos leva à parte final.

A leitura honesta: registry não é canal — e construí mesmo assim

A revisão interna do produto registra a conclusão sem anestesia: registries MCP estão desconfirmados como canal de distribuição. No estado atual, ninguém descobre produto novo navegando registry de MCP server. O que eles são, hoje, é outra coisa: a resposta pronta para uma objeção de procurement, a área de compras da empresa que avalia.

A cena que justifica o investimento não é “usuário descobre o produto pelo registry”. É outra. A empresa que avalia o produto pergunta: nossos agentes conseguem usar isso? A resposta é npx tamperlens-mcp, com listing oficial, namespace verificado por DNS e versão travada no engine. A mesma leitura vale para o node de automação que empacotei para outro ecossistema: higiene de plataforma, não canal de aquisição. Construí os dois com essa expectativa: pequenos, baratos de manter, à prova de objeção. É diferente de construí-los esperando um funil que os números não sustentam.


O checklist, para empacotar a sua API

  1. Poucos verbos, não trinta endpoints. Superfície MCP é decisão de agente, não espelho de REST.
  2. Binário por referência (caminho/URL), nunca inline. A contrapartida é obrigatória: allowlist de diretórios, symlink resolvido, guarda SSRF.
  3. Funcione sem chave, dentro do free tier que a API já impõe. O funil mora na API; os clientes herdam.
  4. Trave a versão do pacote na versão do sistema descrito, por teste. E feche os caminhos de publicar de árvore velha: prepublish gate, ordem documentada, checkouts que se atualizam sozinhos.
  5. Namespace por DNS, source público de verdade.
  6. Expectativa calibrada: empacote como resposta de procurement e higiene de ecossistema. Se virar canal, foi bônus. Planeje como se não fosse.

Precisa de um projeto técnico sob medida?

Arquitetura, TypeScript, APIs e automação, do protótipo à produção. Quem responde o seu e-mail é quem escreve o código, e o prazo que eu prometo é o prazo que eu consigo cumprir.

Me manda uma mensagem →