# EasyPusher para IAs — implementação e uso via MCP

> Este documento é o contrato operacional para agentes de IA que precisam implementar ou integrar um cliente Pusher Channels ao EasyPusher.

## 1. O que está disponível

O repositório inclui um servidor MCP local, executado por `stdio`, em:

```text
admin/scripts/mcp-server.js
```

Ele não abre uma porta adicional e não publica o token administrativo. O agente MCP recebe somente as variáveis explicitamente configuradas no processo.

O servidor disponibiliza:

| Ferramenta/recurso | Autenticação | Finalidade |
|---|---:|---|
| `health` | não | verificar se o painel responde |
| `get_integration_contract` | não | obter endpoints, camadas, canais e regras de segurança |
| `list_applications` | sessão admin | listar aplicações sem `App Secret` |
| `create_application` | sessão admin | criar aplicação; retorna o `App Secret` somente nessa resposta |
| recurso `easypusher://integration-contract` | não | contrato JSON legível por agentes |

No Hermes, as ferramentas normalmente aparecem com o prefixo:

```text
mcp_easypusher_health
mcp_easypusher_get_integration_contract
mcp_easypusher_list_applications
mcp_easypusher_create_application
```

O manifesto machine-readable está em:

```text
docs/mcp/easypusher-mcp.json
```

## 1.1 Fluxo self-service do cliente

Quando a IA estiver implementando um produto cliente, ela pode usar o portal e
as rotas tenant-aware abaixo. Todas as chamadas autenticadas usam
`Authorization: Bearer <token>`; o token retornado é de cliente e não substitui
a sessão administrativa do MCP.

### Cadastro e primeira aplicação

```http
POST /api/customer/auth/register
Content-Type: application/json

{"name":"Acme","email":"acme@example.com","password":"SENHA_COM_12_OU_MAIS"}
```

O cadastro exige senha com pelo menos 12 caracteres, cria a conta Sandbox e a
primeira aplicação vinculada. A resposta `201` contém `token`, `expiresAt`,
`customer` e `application`; o `application.appSecret` é de uso único e deve ir
somente para o backend do cliente.

### Login e operações autenticadas

```http
POST /api/customer/auth/login
Content-Type: application/json

{"email":"acme@example.com","password":"SENHA_FORA_DO_PROMPT"}
```

Depois do login:

```bash
BASE_URL=https://easypusher.dev.sidsolucoes.com
TOKEN='TOKEN_DE_CLIENTE_FORA_DO_REPOSITORIO'

curl -fsS "$BASE_URL/api/customer/dashboard" -H "Authorization: Bearer $TOKEN"
curl -fsS "$BASE_URL/api/customer/applications" -H "Authorization: Bearer $TOKEN"
curl -fsS "$BASE_URL/api/customer/integration" -H "Authorization: Bearer $TOKEN"
```

Para criar outra aplicação dentro do próprio tenant:

```bash
curl -fsS -X POST "$BASE_URL/api/customer/applications" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  --data '{"name":"Painel web"}'
```

O servidor ignora tentativas de trocar o tenant por um `customerId` enviado pelo
cliente. A resposta de criação contém as credenciais daquela aplicação; trate
o `appSecret` como segredo de uso único. Ao sair:

```http
POST /api/customer/auth/logout
Authorization: Bearer TOKEN_DE_CLIENTE
```

Rotas administrativas (`/api/applications`, `/api/dashboard`, `/api/config` e
`/api/apply`) não devem ser chamadas com token de cliente.

## 2. Configurar o servidor MCP

Requisitos:

- Node.js 22 ou superior;
- EasyPusher disponível localmente ou por URL HTTPS;
- uma sessão administrativa Bearer criada pelo login administrativo;
- arquivo de configuração do agente com permissão restrita.

Exemplo para um cliente MCP compatível com configuração `mcp_servers`:

```yaml
mcp_servers:
  easypusher:
    command: node
    args:
      - /caminho/absoluto/EasyPusher/admin/scripts/mcp-server.js
    env:
      EASY_PUSHER_BASE_URL: https://easypusher.dev.sidsolucoes.com
      EASY_PUSHER_PUBLIC_BASE_URL: https://easypusher.dev.sidsolucoes.com
      EASY_PUSHER_ADMIN_SESSION_TOKEN: "COLOQUE_A_SESSAO_FORA_DO_PROMPT"
    timeout: 30
    connect_timeout: 15
```

A sessão administrativa pode ser obtida pelo endpoint de login. Use o token retornado
no campo `token` como valor de `EASY_PUSHER_ADMIN_SESSION_TOKEN`; não salve a
resposta completa em log:

```bash
curl -fsS -X POST "$EASY_PUSHER_BASE_URL/api/auth/login" \
  -H 'content-type: application/json' \
  --data '{"email":"admin@example.com","password":"SENHA_FORA_DO_PROMPT"}'
```

Resposta esperada, com o valor sensível omitido neste exemplo:

```json
{"token":"TOKEN_DE_SESSAO_REDACTED","expiresAt":0,"user":{"email":"admin@example.com"}}
```

A sessão administrativa é um segredo operacional. Não a coloque em prompt, issue, commit, captura de tela ou documentação pública. Se o cliente MCP não possuir interpolação segura de ambiente, mantenha o arquivo de configuração com modo `600` e substitua o placeholder somente no servidor:

```bash
chmod 600 /caminho/da/configuracao-do-agente
```

O token de sessão expira conforme o TTL administrativo. Quando expirar, faça novo login em `POST /api/auth/login` e reinicie o processo MCP com a nova sessão. O servidor MCP não armazena sessão em disco.

Teste local do protocolo:

```bash
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
  | EASY_PUSHER_BASE_URL=https://easypusher.dev.sidsolucoes.com \
    node admin/scripts/mcp-server.js
```

A resposta deve conter `serverInfo.name` igual a `easypusher-mcp`. O processo não deve escrever logs operacionais em `stdout`, pois `stdout` é reservado para JSON-RPC; mensagens de falha vão para `stderr`.

## 3. Fluxo que uma IA deve seguir

A IA deve executar as etapas abaixo em ordem e pedir confirmação humana antes de criar uma aplicação ou alterar código de negócio.

### Etapa A — descobrir o contrato

Chame:

```json
{"name":"get_integration_contract","arguments":{}}
```

Use o resultado para separar:

- navegador: App Key, `wss://` e porta `443`;
- backend Docker: host `soketi`, porta `6001`, esquema `http`;
- publicação: endpoint `/apps/{APP_ID}/events` com assinatura Pusher;
- canais permitidos no runtime atual: `public` e `private`.

Não invente host, porta, cluster, caminho de WebSocket ou formato de assinatura. Se o contrato retornado pelo MCP divergir desta documentação, o retorno do servidor é a fonte de verdade para aquele ambiente.

### Etapa B — verificar a saúde

Chame:

```json
{"name":"health","arguments":{}}
```

Se o resultado não for saudável, não altere o projeto consumidor. Diagnostique primeiro o painel, o DNS, o TLS, o NGINX, o Soketi e a rede Docker.

### Etapa C — listar ou criar a aplicação

Liste as aplicações existentes:

```json
{"name":"list_applications","arguments":{}}
```

Se for necessário criar uma nova:

```json
{"name":"create_application","arguments":{"name":"Nome do produto"}}
```

Regras obrigatórias:

1. peça confirmação do nome e do ambiente antes da criação;
2. guarde o `appId`, `appKey` e `appSecret` em um cofre ou arquivo de ambiente protegido;
3. mostre o `appSecret` somente ao operador autorizado e somente durante a criação;
4. não escreva o segredo em código frontend, README, prompt, log, telemetria ou commit;
5. se a resposta única for perdida, não tente adivinhar o segredo: gere rotação/recriação pelo fluxo administrativo definido pelo produto.

### Etapa D — implementar o cliente

A IA deve localizar o ponto real de configuração do framework consumidor e produzir duas configurações distintas:

- servidor/backend: App ID, App Key, App Secret e publicação assinada;
- navegador/mobile: somente App Key, endpoint público e transporte WSS.

Não copie `PUSHER_APP_SECRET` para variáveis `MIX_`, `VITE_`, `NEXT_PUBLIC_`, `REACT_APP_` ou equivalentes públicas.

### Etapa E — validar

A IA deve validar, sem imprimir credenciais:

1. Compose e variáveis:
   ```bash
   docker compose --env-file .env config --quiet
   ```
2. resolução interna:
   ```bash
   getent hosts soketi
   ```
3. handshake externo `101 Switching Protocols` com cliente Pusher real;
4. recebimento de `pusher:connection_established`;
5. publicação assinada pelo backend;
6. leitura do evento no cliente;
7. tentativa negativa com App Key inexistente, que deve falhar;
8. ausência do App Secret no bundle frontend e nos logs.

## 4. Configuração de navegador

Exemplo com `pusher-js`:

```bash
npm install pusher-js
```

```javascript
import Pusher from 'pusher-js';

const pusher = new Pusher(import.meta.env.VITE_PUSHER_APP_KEY, {
  cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER || 'mt1',
  wsHost: 'easypusher.dev.sidsolucoes.com',
  wsPort: 443,
  wssPort: 443,
  forceTLS: true,
  enabledTransports: ['ws', 'wss'],
});

const channel = pusher.subscribe('orders');
channel.bind('order.created', (payload) => {
  console.log('pedido recebido', payload);
});
```

O bundle pode conter `VITE_PUSHER_APP_KEY`, mas nunca `VITE_PUSHER_APP_SECRET`.

## 5. Configuração de backend Laravel

Dentro da mesma rede Docker do EasyPusher:

```dotenv
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=app_id_do_ambiente
PUSHER_APP_KEY=app_key_do_ambiente
PUSHER_APP_SECRET=app_secret_do_ambiente
PUSHER_APP_CLUSTER=mt1
PUSHER_HOST=soketi
PUSHER_PORT=6001
PUSHER_SCHEME=http
```

O consumidor Laravel deve declarar a rede externa:

```yaml
networks:
  soketi-network:
    external: true
    name: sidsolucoes
```

Para um backend fora da rede Docker, use o endpoint público HTTPS na publicação e mantenha o App Secret somente no ambiente do servidor. Nunca permita que um request do navegador escolha livremente `appSecret`, `customer_id` ou a aplicação de outro tenant.

## 6. Canais privados

O cliente deve solicitar autorização ao backend da própria aplicação. O backend deve:

1. autenticar o usuário;
2. validar que ele pode acessar o recurso;
3. assinar a autorização usando a biblioteca Pusher compatível;
4. retornar somente a resposta de autorização esperada pelo cliente.

O EasyPusher não deve receber autorização baseada apenas em um ID enviado pelo navegador. A regra de negócio e o isolamento do tenant pertencem ao backend consumidor.

## 7. Publicação de eventos

A publicação de eventos deve ocorrer no servidor, usando App ID, App Key e App Secret. A URL pública tem o formato:

```text
https://easypusher.dev.sidsolucoes.com/apps/{APP_ID}/events
```

A requisição Pusher deve conter a assinatura HMAC e os parâmetros canônicos da biblioteca utilizada. Prefira o SDK oficial/compatível do ecossistema Pusher em vez de implementar a assinatura manualmente.

Exemplo conceitual de payload — os parâmetros finais devem ser gerados pelo SDK:

```json
{
  "name": "order.created",
  "channel": "orders",
  "data": "{\"id\":123,\"status\":\"paid\"}"
}
```

Não coloque `APP_SECRET` no payload, query string, frontend ou URL. Ele é usado somente para assinar a requisição no backend.

## 8. Limites de segurança para agentes

| Dado | Pode ir para o navegador? | Pode ir para o prompt? | Local correto |
|---|---:|---:|---|
| App ID | não é necessário | somente se o operador autorizar | backend/servidor |
| App Key | sim | sim, se necessário | frontend e backend |
| App Secret | não | não | cofre/.env do backend |
| Sessão MCP admin | não | não | ambiente do processo MCP |
| endpoint WSS | sim | sim | configuração pública |
| token de cliente | conforme o app | nunca em documentação | sessão do cliente |

A IA deve interromper a implementação e pedir orientação se encontrar:

- segredo em bundle, template ou variável pública;
- token administrativo em arquivo versionado;
- tentativa de abrir a porta `6001` na Internet;
- aplicação sem isolamento entre tenants;
- requisito de presence/encrypted/cache não validado no runtime;
- resposta HTTP `200` tratada como sucesso sem verificar o corpo ou o estado Pusher.

## 9. Contrato de erro

O servidor MCP retorna falhas de ferramenta no formato MCP com `isError: true` e uma mensagem sanitizada. O agente deve classificar:

- `EASY_PUSHER_ADMIN_SESSION_TOKEN não configurado`: falta de pré-requisito local;
- `401`: sessão ausente, expirada ou inválida;
- `404`: endpoint ou aplicação inexistente;
- `409`: conflito de cadastro;
- `5xx`: falha do serviço ou infraestrutura.

Não tente contornar `401` usando o App Secret, token legado ou credenciais inventadas.

## 10. Checklist de entrega da IA

Antes de declarar a integração concluída, o agente deve informar:

- repositório e branch alterados;
- arquivos de configuração modificados;
- App ID e App Key mascarados ou parcialmente identificados, sem App Secret;
- endpoint WSS e modo de transporte;
- se o backend usa `soketi:6001` ou HTTPS público;
- teste de handshake e `pusher:connection_established`;
- teste de publicação assinada;
- resultado do teste frontend/backend;
- confirmação de que não houve segredo em diff, logs ou bundle;
- limitações funcionais ainda não implementadas.

Uma IA não deve afirmar “compatibilidade Pusher completa” sem testar cada recurso solicitado. O runtime atual anuncia apenas o núcleo validado de canais públicos/privados e publicação compatível.
