Cloudflare Image MCP
by giancta92
README.md
# Cloudflare Image MCP
Servidor MCP local por `stdio` que expone `generate_image` y solicita imágenes a Cloudflare Workers AI. Guarda la respuesta como PNG auténtico; las llamadas pueden generar consumo o cargos.
## Requisitos
- Python 3.11 o posterior.
- OpenCode V2 para usarlo como MCP (opcional para ejecutar pruebas).
- Cuenta Cloudflare con Workers AI habilitado y un API token con los permisos mínimos que Cloudflare indique actualmente para ejecutar Workers AI. Confirma los permisos en documentación oficial; este repositorio no valida una cuenta ni garantiza acceso.
- Internet para generar imágenes. Instalación y pruebas no llaman a Cloudflare.
Dependencias Python: `mcp`, `httpx` y Pillow; dependencias de pruebas en el extra `dev` de `pyproject.toml`.
## Instalación desde cero (Linux/macOS)
Desde la carpeta del repositorio:
```bash
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -e '.[dev]'
```
Todo queda en `.venv`; no se instalan paquetes globales. Para ejecutar manualmente:
```bash
.venv/bin/python -m cloudflare_image_mcp.server
```
El servidor usa `stdio` y normalmente lo inicia OpenCode. No escribas depuración en stdout, canal del protocolo MCP.
## Credenciales seguras
Por defecto se busca `~/.config/opencode/secrets/cloudflare.env`. Crea el archivo fuera del repositorio:
```bash
mkdir -p ~/.config/opencode/secrets
cat > ~/.config/opencode/secrets/cloudflare.env <<'EOF'
CLOUDFLARE_ACCOUNT_ID=REEMPLAZA_CON_TU_ACCOUNT_ID
CLOUDFLARE_API_TOKEN=REEMPLAZA_CON_TU_TOKEN
EOF
chmod 600 ~/.config/opencode/secrets/cloudflare.env
```
Sustituye los marcadores localmente. No compartas el archivo, no lo añadas al repositorio ni pongas tokens en argumentos, configuración OpenCode, prompts o logs. `CLOUDFLARE_CREDENTIALS_PATH` o `CLOUDFLARE_ENV_FILE` pueden apuntar a otro archivo con esas dos claves; no contienen directamente los secretos.
## OpenCode V2 global
Integra este bloque `mcp.servers` en la configuración global del usuario (habitualmente `~/.config/opencode/opencode.json` en Linux), conservando el resto. Sustituye las rutas de ejemplo por rutas absolutas locales: Python de `.venv` y carpeta del proyecto donde guardar imágenes.
```json
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"servers": {
"cloudflare-image": {
"type": "local",
"command": [
"/RUTA/AL/REPOSITORIO/.venv/bin/python",
"-m",
"cloudflare_image_mcp.server"
],
"cwd": "/RUTA/AL/PROYECTO-DE-SALIDA",
"disabled": false,
"timeout": {
"startup": 10000,
"catalog": 10000,
"execution": 180000
}
}
}
}
}
```
Si ya tienes `$schema`, no lo dupliques: integra solo `mcp`. Forma V2 consultada el 2026-10-30; puede cambiar. Referencias: [MCP servers](https://opencode.ai/v2/docs/mcp-servers) y [migración V1 a V2](https://opencode.ai/v2/docs/migrate-v1).
Comprueba el arranque/catálogo sin generar:
```bash
opencode mcp list
```
Que aparezca conectado no autentica con Cloudflare, verifica saldo ni genera una imagen.
## Uso de `generate_image`
Pide explícitamente a OpenCode que invoque `generate_image`. Ejemplo:
```text
Usa generate_image con model="flux-2-klein-4b", prompt="Una casa roja sobre una colina al amanecer", output_path="public/images/casa.png".
```
`output_path` relativo se resuelve bajo la raíz de salida; también se acepta una ruta absoluta dentro de esa raíz. Se rechazan escapes fuera de ella, incluidos `..` y symlinks que escapen. Se crean carpetas padre. No se reemplazan archivos existentes salvo `overwrite=true`. Sin ruta, se crea `generated-image-<marca-de-tiempo>-<id>.png` en la raíz. El resultado informa ruta, modelo y bytes escritos.
| Parámetro | Uso |
|---|---|
| `prompt` | Obligatorio, 1–2048 caracteres. |
| `model` | `flux-2-klein-4b` (predeterminado) o `flux-1-schnell`; admite también ID completo `@cf/...`. |
| `output_path` | Ruta PNG opcional relativa a la raíz. |
| `steps` | Solo Schnell: 1–8, predeterminado 4. |
| `width`, `height` | Solo Klein: 256–1920; predeterminados 1024×768. |
| `guidance`, `seed` | Opcionales, solo Klein. |
| `overwrite` | Predeterminado `false`. |
### FLUX.1 Schnell vs FLUX.2 Klein 4B
- **FLUX.1 Schnell** (`@cf/black-forest-labs/flux-1-schnell`): el servidor envía JSON con `prompt` y `steps` (por defecto 4; rango de esta implementación 1–8).
- **FLUX.2 Klein 4B** (`@cf/black-forest-labs/flux-2-klein-4b`): modelo predeterminado; el servidor envía `multipart/form-data` con `prompt`, dimensiones y, si se especifican, `guidance` y `seed`.
Son interfaces/modelos distintos; no se afirman diferencias de calidad, velocidad o consumo por solicitud como resultados medidos. Modelos, parámetros y disponibilidad pueden cambiar. Pillow convierte formatos compatibles a PNG real, haciendo coincidir extensión y bytes.
## Directorio de salida, `cwd` y override
El código usa `Path.cwd()` del proceso servidor como raíz. Configura explícitamente el `cwd` del MCP en OpenCode como la carpeta de salida deseada. La salida depende del directorio efectivo del proceso hijo, no necesariamente de dónde abriste manualmente la interfaz.
`CLOUDFLARE_IMAGE_MCP_ROOT`, si está definida, reemplaza `Path.cwd()` como raíz. El servidor resuelve `output_path` y restringe la escritura a esa raíz. Si usas el override, defínelo en el entorno heredado por OpenCode antes de iniciarlo. No confundir con `CLOUDFLARE_CREDENTIALS_PATH`, que selecciona el archivo de credenciales.
Las pruebas locales verifican el override, rutas y escritura temporal. No prueban en una instalación concreta qué `cwd` hereda el proceso hijo OpenCode; no se hizo generación remota para demostrarlo.
## Límites gratuitos y facturación
Workers AI consume Neurons y puede generar cargos según plan, uso, cuota disponible y tarifas vigentes. La página oficial de precios consultada el 2026-10-30 indicaba una cuota gratuita publicada de 10.000 Neurons diarios y, para Workers Paid, USD 0,011 por cada 1.000 Neurons sobre esa asignación. Esto no garantiza cuota disponible, plan, requisitos de facturación ni costo de una solicitud concreta. Las tarifas dependen del modelo/unidades y pueden cambiar.
Antes de usar la herramienta, revisa [precios de Workers AI](https://developers.cloudflare.com/workers-ai/platform/pricing/), cuotas, términos y consumo de tu cuenta. El uso de Cloudflare es independiente del plan/proveedor de OpenCode. Conectar MCP no solicita inferencia; invocar `generate_image` sí intenta contactar Cloudflare y puede tener costo.
## Pruebas
```bash
.venv/bin/python -m pytest -q
```
Las pruebas usan mocks/respuestas simuladas y no consumen cuota.
## Resolución de problemas
- **No conectado en `opencode mcp list`:** valida configuración global, ruta de `command`, instalación del paquete y existencia de `cwd`.
- **Dependencia ausente:** instala en `.venv` con `-e '.[dev]'` (o `-e .` sin pruebas).
- **Credenciales no encontradas:** revisa ruta predeterminada o `CLOUDFLARE_CREDENTIALS_PATH`/`CLOUDFLARE_ENV_FILE`, las dos claves requeridas y permisos restrictivos.
- **HTTP 401/403:** confirma token, cuenta, permisos vigentes y facturación en Cloudflare. No pegues el token en reportes.
- **Cuota/costo:** revisa dashboard y precios; el MCP no conoce la cuota disponible.
- **Ruta rechazada:** usa ruta dentro de `cwd` o `CLOUDFLARE_IMAGE_MCP_ROOT`, y comprueba symlinks/`..`.
- **Archivo existente:** selecciona otra ruta o confirma `overwrite=true`.
- **Timeout:** comprueba conexión/disponibilidad y ajusta `execution` si corresponde.
## Licencia
El código propio de este proyecto está aprobado para publicarse bajo la licencia **MIT**; consulta el archivo [`LICENSE`](LICENSE), que identifica el copyright de 2026 de Gian Torres Azaña. Esta licencia cubre únicamente el código propio del proyecto; no concede derechos sobre Cloudflare, Workers AI ni modelos de terceros, cuyos términos se aplican por separado.
## Verificación de esta copia
En la preparación de la distribución, el **30-10-2026**, se instaló esta copia en un entorno virtual temporal y pasaron **17 pruebas** (`17 passed`). Se reutilizaron dependencias ya instaladas, sin descargas; las pruebas usan mocks y no contactan Cloudflare.
## Crear el repositorio GitHub posteriormente
Estos pasos son una guía para cuando se autorice la publicación; **no se han ejecutado**. Antes, confirma la cuenta de destino y revisa que `git status` solo muestre los ocho archivos previstos.
1. Desde esta carpeta, inicializa Git y revisa el contenido antes de confirmar:
```bash
git init
git add .
git status --short
git diff --cached --check
git commit -m "Prepare public distribution"
```
2. Crea en GitHub un repositorio público vacío llamado `cloudflare-image-mcp`, sin README, licencia ni `.gitignore` generados por GitHub (ya están en esta copia).
3. Tras revisar el commit local y autorizar expresamente el envío, conecta el remoto y publica la rama. Por ejemplo, reemplazando `OWNER` por la organización o cuenta aprobada:
```bash
git remote add origin https://github.com/OWNER/cloudflare-image-mcp.git
git branch -M main
git push -u origin main
```
No ejecutes estos comandos hasta que la creación y el `push` estén autorizados. La ruta de publicación y el propietario de GitHub también quedan por decidir.
TDQS
B3.2/5.0
Scored across 1 tool
Disambiguation5/5
With only one tool in the set, there is nothing to confuse it with; its purpose (generate an image and save as PNG) is unambiguous.
Naming Consistency5/5
The single name follows a clear verb_noun convention (generate_image), which is predictable and readable even without siblings.
Tool Count3/5
A one-tool surface is thin: while image generation is the stated purpose, there is no companion operation such as listing models, retrieving the saved file path, or deleting images, so the set feels borderline under-scoped.
Completeness3/5
Generation is covered, but the lifecycle dead-ends after creation — an agent cannot list previously generated images, fetch a specific result by ID, or clean up files, which are natural follow-on operations for this domain.
Maintenance
ActivityMaintained
ResponsivenessNo issues