wrmmax-criativo-mcp
Enables an AI assistant to generate and edit brand-compliant marketing images through MCP tools, including creating visuals from prompts, modifying reference photos, and refining results based on prior output.
README
wrmax-criativo
Pipeline de geração e edição de imagem da WRMax. Claude Code é o cérebro; este repo é a mão.
O código não sabe nada sobre marketing — ele recebe parâmetros e devolve arquivo. Quem decide formato, ângulo e prompt é o Claude, que depois olha a peça gerada e decide se aceita ou refaz. É esse loop fechado que caracteriza a orquestração.
O código, os comentários e as mensagens estão em inglês. A documentação e a conversa com o time seguem em português.
Setup (5 minutos)
npm install
export OPENAI_API_KEY="sua-chave" # https://platform.openai.com/api-keys
Importante: assinatura do ChatGPT Pro ou do app Gemini não dá acesso à API. São cobranças separadas. Precisa de chave de API com billing ativo.
Motor B (ainda não implementado):
export IMAGE_PROVIDER=gemini
export GEMINI_API_KEY="sua-chave"
Estrutura
Cada pasta tem uma responsabilidade, e nenhum arquivo acumula duas.
bin/ entradas executáveis
cli.js CLI
mcp-server.js servidor MCP (só escolhe o transporte)
src/
bootstrap/ carga do .env e resolução de caminhos
config/ ÚNICO ponto que lê process.env; tabelas de modelo,
formato e qualidade
brands/ brand kit, compliance e montagem do prompt
media/ entrada, redução e saída de imagem (Drive, download,
arquivo local, preview, upload)
providers/ motores de imagem, por registro
core/ regra de negócio: artwork-service, artifact-store,
delivery
mcp/ servidor MCP, tools e transportes
http/ app Express, middleware, rotas e views
auth/ OAuth com Google
cli/ args, ajuda e orquestração do CLI
test/ node --test, sem chave e sem custo
scripts/ smoke — gasta crédito ou precisa de rede viva
brand/ um JSON por cliente
out/ saída local (só com PERSIST_OUTPUT=true)
O desenho central: src/core/artwork-service.js não sabe o que é MCP nem o
que é CLI. Ele recebe um pedido simples e devolve um resultado simples. Quem
formata content block é src/mcp/tool-result.js; quem escreve JSON no stdout é
src/cli/run.js. Por isso os dois frontends compartilham um caminho só.
Toda dependência (config, artifact store, diretório de brand) é injetada, não importada como singleton — é o que permite testar a rota, a tool e o serviço sem tocar no ambiente.
Uso
Gerar do zero:
node bin/cli.js --brand forno-paulista --format feed \
--prompt "Studio product shot of a rustic pizza on a wooden board, steam rising"
Editar foto real do cliente (troca de fundo preservando o produto):
node bin/cli.js --brand forno-paulista --format square \
--ref fotos/produto.jpg \
--prompt "Change only the background to a clean warm studio gradient. Keep the product, its label and the lighting on it exactly unchanged."
Rascunho barato antes de gastar no final:
node bin/cli.js --quality draft --prompt "..."
Sempre rascunho antes do final. Custa uma fração e evita refazer caro.
Servidor MCP
npm run mcp # stdio — é o que o Claude Code fala
npm run mcp:http # Streamable HTTP em :8787/mcp — é o que conector remoto exige
Ferramentas expostas: list_brands, generate_image, edit_image.
Não existe ferramenta que liste, busque ou navegue imagens no servidor, e isso é proposital: quem escolhe o arquivo é o usuário. Uma ferramenta de busca transformaria um prompt injetado numa foto de cliente em varredura do ambiente.
Detalhes de transporte, autenticação e destino da resolução cheia estão em
CLAUDE.md.
Como o Claude Code usa o CLI
O comando imprime JSON no stdout e log no stderr. Isso é proposital: o Claude roda, lê o JSON, abre o PNG, avalia e encadeia a próxima chamada. Sem humano no meio de cada iteração.
{"ok":true,"file":"out/1755777.png","seconds":6.2,"aspectRatio":"4:5"}
Códigos de saída: 0 sucesso · 1 falha técnica · 2 bloqueado por
compliance — o 2 existe para um hook distinguir os dois casos.
Compliance
brand/*.json tem um array forbidden_terms. O assertPromptAllowed() roda
antes da chamada e bloqueia — economiza crédito e, mais importante, não
depende do modelo obedecer instrução.
{
"name": "Forno Paulista",
"visual": {
"style": "appetizing food photography, rustic warmth, artisanal",
"colors": ["wood brown", "tomato red", "warm cream"],
"lighting": "warm golden light, natural window light",
"avoid": ["cold blue tones", "plastic-looking food"]
},
"forbidden_terms": [],
"compliance_reason": ""
}
| Marca | Bloqueio |
|---|---|
cliente-medico |
paciente, antes/depois, corpo, resultado de procedimento — CFM 2.336/2023 |
Teste rápido do guarda-corpo, sem chave e sem custo:
node bin/cli.js --brand cliente-medico --prompt "before and after of a patient"
# x BLOCKED by compliance rules for "Cliente médico (template CFM)"
Testes
npm test # 110 testes, sem chave de API, sem rede externa, sem custo
Cobre: compliance, brand kit, config, artifact store, conversão de link do Drive, todos os modos de falha de download, redução, upload, tabelas de tamanho, o fluxo OAuth inteiro (com um Google de mentira), a descoberta que o claude.ai faz, e os dois transportes MCP de ponta a ponta.
Os testes que gastam crédito ou dependem de rede viva ficam fora da suíte,
em scripts/:
npm run probe # ~US$ 0,005 — separa "chave ruim" de "pipeline ruim"
npm run smoke:drive # ~US$ 0,01 — link do Drive de ponta a ponta
npm run smoke:edit # ~US$ 0,02 — o modelo edita ou só regenera?
npm run smoke:stateless # ~US$ 0,01 — não deixa um byte para trás
Variáveis de ambiente
| Variável | Padrão | Para quê |
|---|---|---|
OPENAI_API_KEY |
— | Obrigatória com o provider openai |
IMAGE_PROVIDER |
openai |
Troca o motor de imagem |
MCP_TRANSPORT |
stdio |
stdio ou http |
PORT |
8787 |
Porta do modo HTTP |
MCP_PATH |
/mcp |
Caminho do endpoint MCP |
MCP_TOKEN |
— | Bearer fixo (script e teste; o claude.ai não aceita) |
MCP_BASE_URL |
— | Obrigatória com OAuth: é o issuer, e precisa ser fixa |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
— | Ligam o OAuth |
MCP_EMAILS |
— | Quem pode autorizar. Conta Google válida não é permissão |
PERSIST_OUTPUT |
false |
Salva a resolução cheia em out/ (só dev local) |
ARTIFACT_TTL_MS |
900000 |
Validade do link de download |
ARTIFACT_MAX_BYTES |
134217728 |
Teto de memória do depósito de peças |
Hospedagem (EasyPanel, ou qualquer host de container)
O servidor guarda estado em memória de propósito — clientes OAuth, tokens e o
depósito de peças são Map(). Isso exige um processo vivo e único, e é o
que descarta plataforma serverless: lá o POST /register cairia numa instância
e o GET /authorize em outra, que não conhece o cliente. O login falharia de
forma intermitente, com sintoma que não parece com a causa.
Por isso o deploy é container, e a regra vale para qualquer host: uma réplica só. Para escalar além disso, troque os três armazenamentos em memória por Redis primeiro.
O Dockerfile na raiz serve a qualquer plataforma de container. Os passos
abaixo são do EasyPanel; em outro host muda a interface, não o conteúdo.
O domínio vem antes
O Google não aceita endereço IP como redirect de OAuth, e exige HTTPS. Ou seja, um domínio é pré-requisito, não acabamento.
Aponte um registro A do subdomínio para o IP do servidor. Quem não tiver
domínio pode usar DNS curinga — mcp.<ip-com-hifens>.sslip.io resolve sozinho
para o IP embutido no nome, e o Let's Encrypt emite normalmente desde que a
porta 80 esteja aberta.
Serviço
-
Criar serviço → App, com source neste repositório e branch
main. -
Build: Dockerfile, na raiz.
-
Environment:
Variável Valor PORT8787MCP_BASE_URLhttps://<seu-dominio>— sem barra no fimOPENAI_API_KEYa chave da OpenAI GOOGLE_CLIENT_IDdo cliente OAuth (Aplicativo da Web) GOOGLE_CLIENT_SECRETdo mesmo cliente MCP_EMAILSquem pode autorizar, separado por vírgula MCP_TRANSPORT=httpjá vem doDockerfile— não defina. -
Domains: o subdomínio apontando para a porta
8787, com HTTPS ligado. -
Deploy.
-
Google Cloud Console → Credenciais → seu cliente OAuth, adicione o redirect autorizado, exatamente:
https://<seu-dominio>/oauth/google/callback -
claude.ai → conectores:
https://<seu-dominio>/mcp.
O MCP_BASE_URL vira o issuer do OAuth e é comparado caractere por caractere
com o que o cliente descobre. Domínio diferente do configurado, ou barra
sobrando, faz o vínculo falhar sem mensagem útil.
Conferindo
curl https://<seu-dominio>/health
O campo que importa é "auth":"oauth". Se vier "none", alguma variável do
Google não chegou — e aí o servidor subiu aberto, aceitando qualquer
chamada e gastando a chave de quem hospeda.
Notas de API que economizam debug
- O
Kdeimage_sizeé maiúsculo.2ké rejeitado. gpt-image-2aceita qualquer WxH divisível por 16; os menores só aceitam três tamanhos fixos. Story/reels final precisa degpt-image-2.- Na edição, a imagem vem antes do texto no array de input.
- Não existe refação encadeada no provider
openai:previous_interaction_idé da Interactions API do Gemini. Para ajustar, reenvie a imagem como referência. - Entrada por URL manda
User-Agentpróprio: várias origens (Wikimedia entre elas) devolvem 400/403 para requisição sem UA identificável. - Peça com texto: defina a copy primeiro, depois peça a imagem com aquela copy.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.