RunComfy MCP
Servidor MCP oficial remoto para la API Serverless de RunComfy (ComfyUI): administra despliegues de GPU y ejecuta inferencia asíncrona de imágenes/videos.
Documentación
RunComfy MCP
Servidor MCP para la plataforma RunComfy — API sin servidor (ComfyUI), API de modelos y API de entrenamiento. Gestiona implementaciones, ejecuta modelos alojados, entrena LoRAs y recupera resultados desde asistentes de IA como Claude, Cursor y Windsurf.
Endpoint: https://mcp.runcomfy.com/mcp
Documentación: docs.runcomfy.com/mcp
Qué hace
31 herramientas que reflejan la documentación de RunComfy 1:1, en tres productos más el saldo de tu cuenta.
API sin servidor (ComfyUI) — tus propios flujos de trabajo en endpoints dedicados
Documentación: docs.runcomfy.com/serverless
| Categoría | Herramientas |
|---|---|
| Gestión de implementaciones | list_deployments, get_deployment, create_deployment, update_deployment, delete_deployment |
| Inferencia | submit_request, get_request_status, get_request_result, cancel_request |
| Avanzado | call_instance_proxy |
API de modelos — modelos del catálogo alojados, bajo demanda
Documentación: docs.runcomfy.com/model-apis
| Categoría | Herramientas |
|---|---|
| Catálogo | list_models, get_model, list_model_categories |
| Inferencia | run_model, get_model_request_status, get_model_request_result, cancel_model_request |
Sin implementación que gestionar y facturación por solicitud. list_models explora el
catálogo por palabra clave o capacidad (category=image-to-video), get_model
devuelve el esquema de entrada de un modelo — tipos de propiedades, valores predeterminados, enumeraciones y
rangos — y run_model lo ejecuta. Así, un asistente puede pasar de "hazme un
video" a una solicitud válida sin salir de las herramientas ni adivinar un parámetro.
Las entradas también incluyen description, base_price_usd por price_unit y un
model_url a la página del modelo.
model_id es el identificador que se muestra en la página del modelo en
runcomfy.com/models, incluidas las barras — p. ej.
blackforestlabs/flux-1-kontext/pro/edit. Las entradas de archivos deben ser URLs HTTPS públicas.
API de entrenamiento — conjuntos de datos y entrenamiento de LoRA con AI Toolkit
Documentación: docs.runcomfy.com/trainer-apis
| Categoría | Herramientas |
|---|---|
| Conjuntos de datos | create_dataset, list_datasets, get_dataset_status, delete_dataset |
| Cargas de conjuntos de datos | upload_dataset_file_from_url, upload_dataset_text_file, get_dataset_upload_urls |
| Trabajos de entrenamiento | submit_training_job, get_training_job_status, get_training_job_result, cancel_training_job, resume_training_job, edit_training_job |
Flujo típico: crea un conjunto de datos → sube medios y leyendas .txt coincidentes →
consulta hasta que esté READY → envía un trabajo con una configuración YAML de AI Toolkit → consulta el estado
→ extrae los checkpoints del resultado.
Debido a que el servidor se ejecuta de forma remota, no puede leer archivos locales. Sube medios a los que
pueda acceder por HTTP con upload_dataset_file_from_url, escribe leyendas en línea
con upload_dataset_text_file, y para archivos locales o de más de 150 MB usa
get_dataset_upload_urls y PUT los bytes a la URL firmada tú mismo.
Cuenta
| Categoría | Herramientas |
|---|---|
| Saldo | get_balance |
Una sola billetera financia los tres productos. get_balance informa lo que queda, en
balance_usd para lectura y balance_microdollars (millonésimas de dólar)
para comprobaciones exactas de umbrales. Se sirve desde api.runcomfy.net en lugar de
duplicarse por producto, porque solo hay una cifra que informar.
Interacción entre ellos
Un LoRA entrenado se ejecuta sin ninguna implementación: pasa el model_id de su modelo base
a run_model y el LoRA como entrada, p. ej.
{"lora": {"path": "my_first_lora_3000.safetensors"}} — ya sea un nombre de tus
Activos LoRA o una URL
pública como un checkpoint de get_training_job_result. Para un endpoint
dedicado con el hardware elegido, impleméntalo y usa las herramientas sin servidor en su lugar.
Configuración rápida
Cada cliente se autentica con un token de API de RunComfy desde tu página de Perfil. Dos formas de proporcionarlo:
- Encabezado de token de API — funciona en cualquier cliente HTTP Streamable. Es la más simple y la única opción para clientes sin flujo OAuth en navegador.
- OAuth en navegador — sin token en un archivo de configuración. Compatible con Claude.ai, Cursor y clientes locales que registran una devolución de llamada de bucle local, como Claude Code.
Claude Code
Encabezado de token (un comando, nada más que hacer):
claude mcp add --transport http runcomfy https://mcp.runcomfy.com/mcp --header "Authorization: Bearer YOUR_RUNCOMFY_TOKEN"
O OAuth en navegador — omite el encabezado y luego ejecuta /mcp dentro de Claude Code y elige
Autenticar:
claude mcp add --transport http runcomfy https://mcp.runcomfy.com/mcp
--transport http es el transporte HTTP Streamable. streamable-http no es un
valor que Claude Code acepte, y -transport / -header con un solo guion tampoco
lo son — ambas formas fallan antes de que el servidor sea contactado.
Compruébalo con claude mcp list, que debería mostrar runcomfy: connected.
Claude.ai
Añade https://mcp.runcomfy.com/mcp en Configuración → Conectores → Añadir conector
personalizado y luego selecciona Conectar. Claude descubre los endpoints OAuth 2.1
de RunComfy, abre una página de consentimiento de RunComfy y solicita uno de los tokens de API
mostrados en tu Perfil de RunComfy. El token
es validado por RunComfy y cifrado dentro de la concesión de autorización MCP; nunca
se devuelve a Claude.
Cursor
.cursor/mcp.json:
{
"mcpServers": {
"runcomfy": {
"url": "https://mcp.runcomfy.com/mcp",
"headers": { "Authorization": "Bearer YOUR_RUNCOMFY_TOKEN" }
}
}
}
VS Code (Copilot)
.vscode/mcp.json:
{
"servers": {
"runcomfy": {
"type": "http",
"url": "https://mcp.runcomfy.com/mcp",
"headers": { "Authorization": "Bearer YOUR_RUNCOMFY_TOKEN" }
}
}
}
Windsurf
Configuración → MCP:
{
"mcpServers": {
"runcomfy": {
"serverUrl": "https://mcp.runcomfy.com/mcp",
"headers": { "Authorization": "Bearer YOUR_RUNCOMFY_TOKEN" }
}
}
}
Cualquier otro cliente
- URL:
https://mcp.runcomfy.com/mcp - Transporte: HTTP Streamable
- Autenticación:
Authorization: Bearer <token>en cada solicitud, o OAuth 2.1 con una URI de redirección de bucle local o una devolución de llamada de cliente compatible exacta
Solución de problemas
| Síntoma | Causa |
|---|---|
401 con RunComfy rejected this API token | El token es incorrecto, caducó o se truncó al copiarlo. Genera uno nuevo en Perfil — el cuerpo de la respuesta indica la solución. |
401 sin error_description | No llegó ningún encabezado Authorization al servidor. Verifica que el encabezado esté entre comillas como un solo argumento: --header "Authorization: Bearer ...". |
invalid_client_metadata durante OAuth | El cliente registró una devolución de llamada fuera de la lista de permitidos de bucle local y clientes exactos. Usa una devolución de llamada compatible o el encabezado de token. |
invalid_target durante OAuth | La URL configurada debe ser exactamente https://mcp.runcomfy.com/mcp — sin barra final. RFC 8707 vincula el token a ese recurso exacto. |
503 con Retry-After | No se pudo contactar la API de RunComfy para verificar el token. Reintenta. |
429 | Más de 600 solicitudes autenticadas con token por minuto desde una misma IP. |
Revoca el acceso regenerando el token en tu Perfil de RunComfy. Eso invalida el encabezado de token y cualquier concesión OAuth basada en él, porque cada solicitud MCP revalida el token en el servidor.
Arquitectura
MCP Client ──RunComfy API token──┐
│ Cloudflare Worker (/mcp)
MCP Client ──MCP OAuth token─────┤ validates the credential, resolves
│ it to one user's RunComfy token
▼
Cloudflare Container
(Python FastMCP app)
│ request-scoped RunComfy credential
┌───────────────┼───────────────┐
▼ ▼ ▼
api.runcomfy.net model-api. trainer-api.
(Serverless) runcomfy.net runcomfy.net
(Model) (Trainer)
Un solo token de RunComfy autentica los tres productos, por lo que la misma resolución de credenciales cubre todas las herramientas.
Ambos tipos de credenciales convergen en el mismo encabezado de identidad con ámbito de solicitud
antes de llegar al contenedor. Se distinguen por su forma: los tokens de acceso OAuth siempre
son userId:grantId:secret, y un token de API de RunComfy nunca contiene
dos puntos.
- Cloudflare Worker (
src/index.ts) — servidor de autorización OAuth 2.1 y límite de recursos protegidos. Las credenciales faltantes, inválidas, caducadas o con audiencia incorrecta se rechazan antes de la inicialización de MCP o el descubrimiento de herramientas. - Token de API directo (
src/index.ts) — un token de Perfil de RunComfy presentado comoAuthorization: Bearerse revalida contraapi.runcomfy.neten cada solicitud, con límite de velocidad por IP de origen, y nunca se reenvía tal cual. - Consentimiento OAuth (
src/oauth-bridge.ts) — valida un token de Perfil de RunComfy existente, lo almacena solo en datos de concesión OAuth cifrados y emite un token de acceso MCP separado vinculado a la audiencia. El registro dinámico de clientes acepta devoluciones de llamada de bucle local (Claude Code y otros clientes locales), una lista exacta de devoluciones de llamada de clientes alojados y la devolución de llamada heredada exacta de la aplicación de Cursor. Cursor registracursor://anysphere.cursor-mcp/oauth/callback,https://www.cursor.com/agents/mcp/oauth/callbackyhttp://localhost:8787/callbackjuntos; los tres deben aceptarse incluso cuando la redirección activa usa localhost. Los protocolos personalizados arbitrarios y las variantes de devolución de llamada siguen rechazados, y se requiere PKCE S256. - Contenedor Python (
server.py) — aplicación FastMCP con 31 herramientas en las API sin servidor, de modelos y de entrenamiento. No tiene credencial compartida/de operador y falla de forma segura a menos que el borde autenticado proporcione el token de RunComfy con ámbito de solicitud del usuario actual. - Cloudflare Container se inicia automáticamente en la primera solicitud y se duerme después de 10 minutos de inactividad.
Estructura del proyecto
.github/workflows/deploy.yml CI: typecheck, test, deploy to Cloudflare
src/index.ts Cloudflare Worker entrypoint
src/oauth-bridge.ts OAuth consent and RunComfy token validation
server.py MCP tool definitions (31 tools)
runcomfy_client.py RunComfy API clients (serverless, model, trainer)
container_app.py ASGI middleware (request IDs, token forwarding)
container_entrypoint.py Uvicorn startup
container_runtime.py Env validation, structured logging
wrangler.jsonc Cloudflare Worker + Container config
Dockerfile Container image
.env.example Local dev config
Desarrollo local
# Python 3.11+
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
python -m container_entrypoint
Endpoints locales:
http://127.0.0.1:8000/healthzhttp://127.0.0.1:8000/mcp
El endpoint Python local no tiene intencionalmente ninguna credencial de respaldo compartida. Las llamadas a herramientas protegidas deben pasar por el límite del Worker autenticado.
Implementación
Al enviar a main se implementa automáticamente mediante .github/workflows/deploy.yml:
la verificación de tipos, las pruebas del Worker y las pruebas del contenedor deben pasar, luego
wrangler deploy --containers-rollout immediate envía el Worker y el
contenedor Python juntos. Las solicitudes de extracción ejecutan las mismas verificaciones sin
implementar. El flujo de trabajo también se puede ejecutar manualmente desde la pestaña Acciones.
Se requiere un secreto de repositorio:
| Secreto | Propósito |
|---|---|
CLOUDFLARE_API_TOKEN | Un token con permiso Editar Cloudflare Workers en la cuenta en wrangler.jsonc |
CLOUDFLARE_ACCOUNT_ID | Opcional. account_id ya está confirmado en wrangler.jsonc; configúralo solo para implementar bajo una cuenta diferente. |
Para implementar manualmente (requiere el plan Cloudflare Workers Paid con Containers habilitado):
npm install
npm run check
npm test
npx wrangler deploy --containers-rollout immediate
El endpoint MCP se activa en https://mcp.runcomfy.com/mcp (dominio personalizado configurado en wrangler.jsonc).
Variables de entorno y enlaces
Deliberadamente no hay ningún secreto compartido de clave de API de RunComfy. El estado de OAuth se mantiene
en el enlace OAUTH_KV y cada solicitud ascendente está vinculada al usuario que
autorizó la concesión OAuth.
Variables del Worker (en wrangler.jsonc)
| Nombre | Predeterminado | Descripción |
|---|---|---|
CONTAINER_INSTANCE_NAME | runcomfy-unified | Nombre de instancia de Durable Object |
CONTAINER_STARTUP_TIMEOUT_MS | 15000 | Espera máxima para el inicio del contenedor |
CONTAINER_PORT_READY_TIMEOUT_MS | 30000 | Espera máxima para que el puerto esté listo |
MCP_MAX_BODY_BYTES | 1048576 | Tamaño máximo del cuerpo de la solicitud |
OPENAI_APPS_CHALLENGE | Token de envío actual | Token público de verificación de dominio de OpenAI, servido textualmente en GET /.well-known/openai-apps-challenge; si no está configurado o está vacío, devuelve 404. Verifica la propiedad de cualquier token existente antes de reemplazarlo. |
MCP_DIRECT_TOKEN_RATE_LIMITER | 600 / 60s | Límite por IP en solicitudes /mcp autenticadas con token de API |
RUNCOMFY_SERVERLESS_BASE_URL | https://api.runcomfy.net | URL base de la API sin servidor |
RUNCOMFY_MODEL_API_BASE_URL | https://model-api.runcomfy.net | URL base de la API de modelos |
RUNCOMFY_TRAINER_API_BASE_URL | https://trainer-api.runcomfy.net | URL base de la API de entrenamiento |
Desarrollo Python local (archivo .env)
| Nombre | Requerido | Descripción |
|---|---|---|
RUNCOMFY_SERVERLESS_BASE_URL | No | Anula la URL base sin servidor (predeterminado: https://api.runcomfy.net) |
RUNCOMFY_MODEL_API_BASE_URL | No | Anula la URL base de la API de modelos (predeterminado: https://model-api.runcomfy.net) |
RUNCOMFY_TRAINER_API_BASE_URL | No | Anula la URL base de la API de entrenamiento (predeterminado: https://trainer-api.runcomfy.net) |
RUNCOMFY_MCP_MOUNT_PREFIX | No | Prefijo de ruta para el montaje de MCP (predeterminado: vacío) |