# LookerHost — Servidor MCP y API

Página canónica: https://lookerhost.com/es/docs/mcp
Catálogo legible por máquina: https://api.lookerhost.com/.well-known/mcp.json

## Qué es LookerHost

LookerHost es una plataforma de hosting en la nube: Cloud VPS, Web Hosting con
panel de control, una App Platform que compila y ejecuta aplicaciones web
directamente desde un repositorio Git, bases de datos gestionadas y WordPress
gestionado.

**LookerHost no es un servicio de alojamiento de código.** No es GitHub, ni Gitea,
ni Forgejo. Tu código se queda donde está; LookerHost lo clona, lo compila y lo
sirve. Nunca agregues un remoto de Git apuntando a `lookerhost.com` — no hay nada
a donde hacer push.

Todo lo que un cliente puede hacer desde el panel está también disponible por una
API REST, y esa API está envuelta en un **servidor MCP** para que un agente de IA
pueda aprovisionar y operar infraestructura sin pasos manuales.

## Puesta en marcha

### 1. Emitir una API key

Entra a [lookerhost.com/dashboard](https://lookerhost.com/dashboard) →
**Ajustes** → **API keys** → **Crear llave**. Ponle un nombre y marca los permisos
que la integración necesite.

El secreto (`lh_live_…`) se muestra **una sola vez**, al crearla. Si se pierde, hay
que revocar la llave y emitir otra: no se puede recuperar.

La cuenta tiene que estar vinculada a una empresa. Las cuentas de operador (admin)
no emiten llaves de cliente: emiten **llaves de plataforma** desde
**Integraciones**, que abarcan toda la plataforma en vez de una sola cuenta.

### 2. Agregar el servidor a tu agente

Crea un archivo llamado **`.mcp.json`** —con punto delante— en la **raíz del
proyecto**:

```json
{
  "mcpServers": {
    "lookerhost": {
      "command": "npx",
      "args": ["-y", "lookerhost-mcp-server@latest"],
      "env": {
        "LOOKERHOST_API_URL": "https://api.lookerhost.com",
        "LOOKERHOST_API_KEY": "lh_live_..."
      }
    }
  }
}
```

> **El fallo más común, con diferencia:** llamar al archivo `mcp.json` en vez de
> `.mcp.json`. Ningún cliente MCP lee un archivo sin el punto inicial, así que el
> agente arranca sin ninguna herramienta de LookerHost y responde que no sabe qué
> es LookerHost. Revisa el nombre del archivo antes que nada.

Con la CLI de Claude Code se hace en un solo comando:

```bash
claude mcp add lookerhost --env LOOKERHOST_API_URL=https://api.lookerhost.com --env LOOKERHOST_API_KEY=lh_live_... -- npx -y lookerhost-mcp-server@latest
```

En Claude Desktop, el mismo bloque `mcpServers` va dentro de
`claude_desktop_config.json`.

El paquete de npm es
[`lookerhost-mcp-server`](https://www.npmjs.com/package/lookerhost-mcp-server).
Fijar `@latest` importa: si no, `npx` reutiliza la versión que dejó cacheada, y de
ahí que un agente insista en que el servidor está desactualizado.

### 3. Comprobar que funciona

Reinicia el agente y pídele la lista de tus servicios. Debería llamar a
`lookerhost_list_services`. Si responde que no tiene esa herramienta, el nombre o
la ubicación del archivo de configuración están mal. Si responde `invalid-token`,
la llave es incorrecta, está revocada o caducó.

## Credencial y permisos

El servidor MCP autentica con la API key como bearer token
(`Authorization: Bearer lh_live_…`). Una llave queda atada a **una** cuenta de
cliente y a un conjunto de permisos, así que el agente solo ve y opera los
servicios de esa cuenta. Lo que la llave no permita se rechaza con
`insufficient-scope`, y la respuesta indica en `need` el permiso que falta.

| Permiso | Habilita |
|---|---|
| `vps:read` | Leer cualquier cosa de la cuenta: servicios, detalle, métricas en vivo y uso de disco, catálogo y planes, actividad, historial de despliegues, backups, facturas, logs de apps. **Todos los GET del portal de cliente lo exigen** — una llave sin `vps:read` no lee nada |
| `vps:write` | Crear VPS y Web Hosting; instalar llaves SSH públicas en un VPS |
| `vps:power` | Encender, apagar y reiniciar cualquier servicio |
| `apps:write` | Desplegar y redesplegar apps, crear bases de datos y WordPress, gestionar deploy keys del repositorio |
| `service:delete` | Eliminar un servicio de forma permanente — irreversible |
| `agent:run` | Lanzar un agente de codificación dentro de las VPS de la cuenta por SSH, aprobar o denegar sus acciones, continuar la conversación, abortar. En modo `auto` el agente cambia el servidor sin revisión: es el permiso más potente después de `service:delete`; viene desmarcado al crear una llave |

## Herramientas

Cuarenta y dos herramientas, con el endpoint REST que llama cada una.

| Herramienta | Permiso | Endpoint | Qué hace |
|---|---|---|---|
| `lookerhost_list_services` | `vps:read` | `GET /api/services` | Todos los servicios de la cuenta: VPS, web hosting, apps, bases de datos, WordPress |
| `lookerhost_get_service` | `vps:read` | `GET /api/services/:id` | Detalle completo de un servicio |
| `lookerhost_get_metrics` | `vps:read` | `GET /api/services/:id/metrics` | CPU, RAM, red y disco en vivo de un VPS (solo VPS) |
| `lookerhost_list_plans` | `vps:read` | `GET /api/services/plans` | Catálogo: planes de VPS, imágenes de SO, tipos de base de datos, variantes de WordPress, más la cuota y el consumo de la cuenta |
| `lookerhost_get_activity` | `vps:read` | `GET /api/services/activity` | Registro de auditoría, por servicio o de toda la cuenta |
| `lookerhost_get_deploy_history` | `vps:read` | `GET /api/services/:id/paas/deploy-history` | Despliegues de una app, del más reciente al más viejo, con los logs de los que fallaron |
| `lookerhost_repo_access` | `vps:read` | `GET /api/services/:id/repository-access` | Con qué credencial se clona el repo: `public`, `github-app`, `deploy-key` o `none` |
| `lookerhost_create_vps` | `vps:write` | `POST /api/services` | Crear un VPS |
| `lookerhost_create_webhosting` | `vps:write` | `POST /api/services/webhosting` | Crear Web Hosting (CloudPanel preinstalado) |
| `lookerhost_add_ssh_key` | `vps:write` | `POST /api/services/:id/vps/ssh-keys` | Instalar una llave SSH pública en un VPS |
| `lookerhost_list_ssh_keys` | `vps:read` | `GET /api/services/:id/vps/ssh-keys` | Listar las llaves autorizadas de un usuario del VPS |
| `lookerhost_generate_ssh_key` | `vps:write` | `POST /api/services/:id/vps/ssh-keys/generate` | Generar un par de llaves, instalarlo y devolver la privada una sola vez |
| `lookerhost_remove_ssh_key` | `vps:write` | `DELETE /api/services/:id/vps/ssh-keys` | Quitar una llave (`confirm: true`) |
| `lookerhost_set_vps_password` | `vps:write` | `POST /api/services/:id/vps/password` | Poner contraseña a un usuario y, opcionalmente, permitirla por SSH (`confirm: true`) |
| `lookerhost_list_port_forwards` | `vps:read` | `GET /api/services/:id/portforwards` | Listar los puertos públicos mapeados a un VPS |
| `lookerhost_open_port` | `vps:write` | `POST /api/services/:id/portforwards` | Abrir un puerto público hacia un puerto del VPS (`confirm: true`; pendiente de aprobación salvo cuentas de confianza) |
| `lookerhost_close_port` | `vps:write` | `DELETE /api/services/:id/portforwards/:pfId` | Liberar un port-forward (`confirm: true`) |
| `lookerhost_deploy_app` | `apps:write` | `POST /api/services/apps` | Crear y desplegar una app desde un repositorio Git |
| `lookerhost_redeploy_app` | `apps:write` | `POST /api/services/:id/paas/deploy` | Redesplegar una app existente (o reiniciar una app IA del catálogo). Devuelve `deployId` para sondear cómo termina |
| `lookerhost_get_deploy` | `vps:read` | `GET /api/services/:id/paas/deploys/:deployId` | Cómo terminó un despliegue (`latest` vale). Si falló, trae `errorCode`, el motivo en una línea y qué hacer |
| `lookerhost_rollback_app` | `apps:write` | `POST /api/services/:id/paas/rollback` | Volver a una versión anterior. Solo apps edge (estáticas y workers), que restauran el artefacto guardado; las apps en contenedor responden `rollback-not-supported` |
| `lookerhost_repo_deploy_key` | `apps:write` | `POST /api/services/:id/repository-access/deploy-key` | Generar una deploy key de solo lectura para un repo privado |
| `lookerhost_create_database` | `apps:write` | `POST /api/services/databases` | PostgreSQL, MySQL, MongoDB o Redis gestionados |
| `lookerhost_create_redis` | `apps:write` | `POST /api/services/redis` | Instancia Redis dedicada en Docker: endpoint propio, usuario/contraseña de ACL y allowlist de IPs. Nace CERRADA: sin IPs autorizadas no hay endpoint público |
| `lookerhost_get_redis` | `vps:read` | `GET /api/services/:id/redis` | Configuración, endpoint, allowlist y estado real del contenedor. Nunca devuelve la contraseña |
| `lookerhost_redis_connection` | `apps:write` | `GET /api/services/:id/redis/connection` | Usuario, contraseña y URI `redis://` completa. Única forma de recuperar la contraseña tras el alta; queda en la auditoría |
| `lookerhost_redis_allowed_ips` | `apps:write` | `PUT /api/services/:id/redis/allowed-ips` | Reemplaza la lista de IPs/CIDR que pueden conectarse. Ampliar exige `confirm: true`; lista vacía cierra el endpoint |
| `lookerhost_update_redis` | `apps:write` | `PATCH /api/services/:id/redis` | Versión, usuario ACL, memoria, política de desalojo o persistencia. Recrea el contenedor; los datos sobreviven |
| `lookerhost_redis_password` | `apps:write` | `POST /api/services/:id/redis/password` | Rota la contraseña del usuario ACL (`confirm: true`): corta toda conexión que use la anterior |
| `lookerhost_create_wordpress` | `apps:write` | `POST /api/services/wordpress` | Sitio WordPress gestionado, con su base de datos |
| `lookerhost_create_aiapp` | `apps:write` | `POST /api/services/aiapps` | App de IA de 1 clic: n8n, Hermes Agent, OpenClaw o Steel Browser |
| `lookerhost_app_volumes` | `apps:write` (listar: `vps:read`) | `GET`/`POST`/`DELETE /api/services/:id/paas/volumes` | Lista, agrega o quita volúmenes persistentes de una app PaaS — sin uno, cada redeploy pierde lo escrito en disco. Quitar exige `confirm: true` |
| `lookerhost_agent_chat` | `apps:write` | `POST /api/services/:id/aiapp/api` | Chatea con el Hermes Agent de la cuenta por su API compatible con OpenAI, por la red interna de LookerHost (la API del agente nunca queda expuesta a internet). `api_key` es el `API_SERVER_KEY` propio de esa app |
| `lookerhost_aiapp_api` | `apps:write` (`GET`: `vps:read`) | `POST /api/services/:id/aiapp/api` | Llamada permitida a la API de una app de IA — runs/jobs de Hermes, sesiones y scraping de Steel Browser |
| `lookerhost_browser_session` | `apps:write` | `POST /api/services/:id/aiapp/api` | Crea, lista, consulta o libera una sesión del Steel Browser de la cuenta — devuelve un endpoint CDP para Playwright/Puppeteer |
| `lookerhost_browser_scrape` | `apps:write` | `POST /api/services/:id/aiapp/api` | Renderiza y extrae una página (markdown, HTML o readability) con el propio Steel Browser de la cuenta, sin manejar sesiones |
| `lookerhost_power_service` | `vps:power` | `POST /api/services/:id/power` | Encender, apagar o reiniciar cualquier servicio |
| `lookerhost_delete_service` | `service:delete` | `DELETE /api/services/:id` | Eliminar un servicio para siempre — además exige `confirm: true` |
| `lookerhost_run_agent` | `agent:run` | `POST /api/agent/jobs` | Lanza un agente autónomo de codificación/operación dentro de una VPS a partir de una tarea en lenguaje natural (como Claude Code conectado al servidor). `approval_mode`: `write-approval` (default), `auto` (exige `confirm: true`), `manual` |
| `lookerhost_agent_job` | `agent:run` | `GET /api/agent/jobs/:id` | Estado, cola del transcript, aprobaciones pendientes y resultado final de un job |
| `lookerhost_list_agent_jobs` | `agent:run` | `GET /api/agent/jobs` | Jobs de la cuenta, opcionalmente por VPS |
| `lookerhost_agent_approve` | `agent:run` | `POST /api/agent/jobs/:id/approval` | Permitir (`confirm: true`) o denegar un comando o escritura que pidió el agente |
| `lookerhost_agent_message` | `agent:run` | `POST /api/agent/jobs/:id/message` | Instrucción o archivos de seguimiento para un job terminado; el agente retoma con todo el contexto |
| `lookerhost_agent_abort` | `agent:run` | `POST /api/agent/jobs/:id/abort` | Detener un job en curso (`confirm: true`) |

El aprovisionamiento es **asíncrono**. Crear un VPS lo devuelve con estado
`provisioning`; hay que consultar `lookerhost_get_service` hasta que diga
`running`, típicamente entre uno y tres minutos. La primera app de una cuenta
además aprovisiona su host Docker, así que ese primer despliegue es bastante más
lento.

## Build packs

`lookerhost_deploy_app` recibe un build pack:

- **`nixpacks`** — detecta solo Astro, Next.js, React, Vue, Svelte, Node.js,
  Python, Go, Rust y PHP. Es el indicado para cualquier cosa que levante un
  servidor; hay que pasarle el puerto en el que escucha.
- **`static`** — compila y sirve la salida estática, como el `dist/` de Astro o la
  build de Vite.
- **`dockerfile`** — compila con el `Dockerfile` del repositorio.
- **`dockercompose`** — compila con el archivo compose del repositorio.
- **`opennextjs-cloudflare`** — un proyecto Next.js con `@opennextjs/cloudflare`,
  que se compila en una VM aislada y se sirve como Cloudflare Worker en lugar de
  ocupar su propia VM.

No hay que commitear nada específico de LookerHost en el repositorio.

Los repositorios públicos solo necesitan su URL. Para uno privado, llama a
`lookerhost_repo_deploy_key` para obtener una llave pública de solo lectura y
agrégala en GitHub en **Settings → Deploy keys**, dejando *Allow write access* sin
marcar. La mitad privada se guarda cifrada en la plataforma y nunca se muestra.
`lookerhost_repo_access` dice qué credencial está en juego: una compilación que
falla con `repository-credential-missing` significa que el repo es privado y
ninguna credencial lo cubre.

## Usar la API REST sin el servidor MCP

El servidor MCP es una comodidad; la misma llave sirve directo.

```bash
curl -s https://api.lookerhost.com/api/services \
  -H "Authorization: Bearer lh_live_..."
```

```bash
curl -s https://api.lookerhost.com/api/services/apps \
  -H "Authorization: Bearer lh_live_..." \
  -H "Content-Type: application/json" \
  -d '{"label":"mi-sitio","repoUrl":"https://github.com/acme/mi-sitio","branch":"main","buildPack":"static","static":true}'
```

## Errores

Todo fallo devuelve un JSON con un código en `error`. Los que conviene manejar:

| Código | Significado |
|---|---|
| `no-token` | No se envió la llave — revisa `LOOKERHOST_API_KEY` |
| `invalid-token` | La llave es inválida, está revocada o caducó |
| `insufficient-scope` | Falta un permiso; `need` dice cuál. Vuelve a emitir la llave con él |
| `no-customer` | El usuario de la llave no está vinculado a una empresa |
| `account-not-active` | Cuenta pendiente o suspendida: solo lectura hasta que la activen |
| `quota-exceeded` | La cuenta llegó a su cuota de servicios |
| `no-docker-host` | Todavía no hay host Docker de PaaS; desplegar una app lo crea |
| `protected` | VM adoptada, protegida contra borrado self-service |
| `rate-limited` | Demasiadas peticiones; espera unos minutos |
| `timeout` | La llamada expiró pero la operación puede seguir en curso — comprueba con `lookerhost_get_service` antes de reintentar |

## Endpoints legibles por máquina

Para agentes que necesiten descubrir todo esto por su cuenta:

- `https://api.lookerhost.com/` — índice JSON de la API
- `https://api.lookerhost.com/.well-known/mcp.json` — el catálogo del MCP:
  herramientas, permisos, endpoints, errores y la configuración lista para pegar
- `https://api.lookerhost.com/llms.txt` — el mismo mapa en texto plano
- `https://lookerhost.com/llms.txt` — resumen de la plataforma a nivel de producto
- `https://lookerhost.com/es/docs/mcp.md` — esta página en markdown crudo

El manifiesto de `/.well-known/mcp.json` es la fuente de verdad de la lista de
herramientas.

## Soporte

Escribe a [support@lookerhost.com](mailto:support@lookerhost.com), o abre un issue
en [github.com/Cloudcity-Colombia/lookerhost](https://github.com/Cloudcity-Colombia/lookerhost/issues).
