wrmmax-criativo-mcp
Officialwrmax-criativo
Пайплайн генерации и редактирования изображений WRMax. Claude Code — мозг; этот репозиторий — руки.
Код ничего не знает о маркетинге — он получает параметры и возвращает файл. Формат, ракурс и промпт решает Claude, который затем смотрит на сгенерированную работу и решает, принять её или переделать. Именно этот замкнутый цикл характеризует оркестрацию.
Код, комментарии и сообщения написаны на английском. Документация и общение с командой — на португальском.
Setup (5 минут)
npm install
export OPENAI_API_KEY="sua-chave" # https://platform.openai.com/api-keysВажно: подписка ChatGPT Pro или приложения Gemini не даёт доступ к API. Это отдельные платежи. Нужен ключ API с активным биллингом.
Движок B (ещё не реализован):
export IMAGE_PROVIDER=gemini
export GEMINI_API_KEY="sua-chave"Related MCP server: MCP OpenAI Image Generation Server
Структура
У каждой папки одна ответственность, и ни один файл не совмещает две.
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)Центральная идея: src/core/artwork-service.js не знает, что такое MCP, и не знает, что такое CLI. Он получает простой запрос и возвращает простой результат. Content block форматирует src/mcp/tool-result.js; JSON в stdout пишет src/cli/run.js. Поэтому оба фронтенда используют один общий путь.
Все зависимости (config, artifact store, каталог бренда) внедряются, а не импортируются как синглтон — это позволяет тестировать маршрут, инструмент и сервис, не трогая окружение.
Использование
Сгенерировать с нуля:
node bin/cli.js --brand forno-paulista --format feed \
--prompt "Studio product shot of a rustic pizza on a wooden board, steam rising"Отредактировать реальное фото клиента (замена фона с сохранением товара):
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."Дешёвый черновик перед тратами на финал:
node bin/cli.js --quality draft --prompt "..."Всегда черновик перед финалом. Он стоит лишь малую часть и избавляет от дорогой переделки.
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Доступные инструменты: list_brands, generate_image, edit_image.
На сервере нет инструмента, который перечислял бы, искал или просматривал изображения, и это намеренно: файл выбирает пользователь. Инструмент поиска превратил бы промпт, внедрённый в фото клиента, в сканирование окружения.
Детали транспорта, аутентификации и того, куда сохраняется полное разрешение, — в CLAUDE.md.
Как Claude Code использует CLI
Команда выводит JSON в stdout, а лог — в stderr. Это намеренно: Claude запускает команду, читает JSON, открывает PNG, оценивает и формирует следующий вызов. Без человека в каждой итерации.
{"ok":true,"file":"out/1755777.png","seconds":6.2,"aspectRatio":"4:5"}Коды выхода: 0 успех · 1 техническая ошибка · 2 заблокировано комплаенсом — 2 нужен, чтобы хук различал эти два случая.
Комплаенс
В brand/*.json есть массив forbidden_terms. assertPromptAllowed() запускается до вызова и блокирует — экономит кредиты и, что важнее, не полагается на то, что модель выполнит инструкцию.
{
"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": ""
}Бренд | Блокировка |
| пациент, до/после, тело, результат процедуры — CFM 2.336/2023 |
Быстрая проверка гардрейла — без ключа и без затрат:
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)"Тесты
npm test # 110 testes, sem chave de API, sem rede externa, sem custoПокрытие: комплаенс, бренд-кит, config, artifact store, конвертация ссылок Drive, все режимы сбоя download, уменьшение размера, upload, таблицы размеров, весь поток OAuth целиком (с фейковым Google), обнаружение, которое выполняет claude.ai, и оба транспорта MCP из конца в конец.
Тесты, которые тратят кредиты или зависят от реальной сети, вынесены из набора в 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Переменные окружения
Переменная | По умолчанию | Назначение |
| — | Обязательна при провайдере |
|
| Меняет движок генерации изображений |
|
|
|
|
| Порт режима HTTP |
|
| Путь к эндпоинту MCP |
| — | Фиксированный Bearer (для скрипта и тестов; claude.ai его не принимает) |
| — | Обязательна с OAuth: это issuer, и он должен быть фиксированным |
| — | Включают OAuth |
| — | Кто может авторизоваться. Наличие аккаунта Google — не разрешение |
|
| Сохраняет полное разрешение в |
|
| Срок действия ссылки на скачивание |
|
| Потолок памяти хранилища работ |
Хостинг (EasyPanel или любой контейнерный хост)
Сервер намеренно хранит состояние в памяти — OAuth-клиенты, токены и хранилище работ — это Map(). Это требует одного живого процесса, и именно это исключает serverless-платформы: там POST /register попал бы в один инстанс, а GET /authorize — в другой, который не знает о клиенте. Вход в систему сбоил бы с перебоями, с симптомом, который не похож на причину.
Поэтому деплой — контейнер, и правило действует для любого хоста: только одна реплика. Чтобы масштабироваться дальше, сначала замените три хранилища в памяти на Redis.
Dockerfile в корне подходит для любой контейнерной платформы. Шаги ниже описаны для EasyPanel; на другом хосте меняется интерфейс, но не содержание.
Сначала домен
Google не принимает IP-адрес как OAuth-редирект и требует HTTPS. То есть домен — это обязательное условие, а не финальный штрих.
Укажите A-запись поддомена на IP сервера. У кого нет домена, можно использовать wildcard DNS — mcp.<ip-com-hifens>.sslip.io сам резолвится в IP, встроенный в имя, а Let's Encrypt выдаёт сертификат как обычно, если порт 80 открыт.
Сервис
Создать сервис → App, с source из этого репозитория и веткой
main.Build: Dockerfile, в корне.
Environment:
Переменная
Значение
PORT8787MCP_BASE_URLhttps://<seu-dominio>— без слэша в концеOPENAI_API_KEYключ OpenAI
GOOGLE_CLIENT_IDиз OAuth-клиента (веб-приложение)
GOOGLE_CLIENT_SECRETиз того же клиента
MCP_EMAILSкто может авторизоваться, через запятую
MCP_TRANSPORT=httpуже задан вDockerfile— не определяйте.Domains: поддомен, указывающий на порт
8787, с включённым HTTPS.Deploy.
Google Cloud Console → Учётные данные → ваш OAuth-клиент, добавьте авторизованный redirect — точно:
https://<seu-dominio>/oauth/google/callbackclaude.ai → коннекторы:
https://<seu-dominio>/mcp.
MCP_BASE_URL становится issuer OAuth и сравнивается посимвольно с тем, что обнаруживает клиент. Домен, отличный от настроенного, или лишний слэш приводят к сбою привязки без внятного сообщения.
Проверка
curl https://<seu-dominio>/healthВажное поле — "auth":"oauth". Если пришло "none", какая-то переменная Google не дошла — значит, сервер запустился открытым, принимая любые вызовы и расходуя ключ того, кто его хостит.
Заметки по API, которые экономят отладку
Буква
Kвimage_size— заглавная.2kотклоняется.gpt-image-2принимает любые WxH, кратные 16; модели поменьше принимают только три фиксированных размера. Для финального story/reels нуженgpt-image-2.При редактировании изображение идёт перед текстом в массиве input.
У провайдера
openaiнет цепочек доработок:previous_interaction_id— из Interactions API Gemini. Чтобы скорректировать, отправьте изображение заново как референс.Вход по URL отправляет собственный
User-Agent: многие источники (среди них Wikimedia) возвращают 400/403 на запрос без опознаваемого UA.Работа с текстом: сначала задайте copy, затем запросите изображение с этой copy.
This server cannot be deployed
Maintenance
Related MCP Connectors
Generate marketing images, videos and audios for campaigns, product content, and brand assets.
On-brand AI image and video campaigns with persistent characters and products, from any MCP client.
Generate on-brand images from your AI agent: design, edit, and render templates over MCP.
Brand-safe MCP for AI agents to create editable, on-brand graphics and automate variants.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides tools for generating and editing images using OpenAI's gpt-image-1 model via an MCP interface, enabling AI assistants to create and modify images based on text prompts.15Apache 2.0
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to generate and edit images through OpenAI's DALL-E models via MCP tools. Supports text-to-image generation and image-to-image editing with configurable parameters for size, quality, and style.-
- AlicenseNot gradedqualityNot gradedmaintenanceEnables image generation, editing, and blending using Gemini 2.5 Flash capabilities, plus text generation for AI-powered creative workflows through MCP tools.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI-powered image generation and editing using Gemini and Imagen models, supporting text-to-image, image editing, and multi-image composition through MCP tools.MIT