Skip to main content
Glama
ragomes102030-cpu

MCP EAP Server

README.md
# MCP EAP Server

Servidor MCP (Model Context Protocol) de EAP (Estrutura Analítica do Projeto)
para obras de construção civil. Expõe 13 ferramentas via HTTP/streamable
para clientes MCP (Claude Desktop, VS Code, etc.).

**Projeto = obra**: cada obra vive no seu `project_id` (tabela `eap_project`
com metadados: nome, tipo_obra, área, método, região, cliente). As tools de
nó aceitam `project_id` opcional (padrão `default`) e são escopadas ao projeto.

## Ferramentas (13 tools)

### Projetos
| Tool | Descrição |
|---|---|
| `criar_projeto` | Cria uma obra/projeto com metadados (project_id, nome, tipo_obra, area_m2, método, região, cliente) |
| `atualizar_projeto` | Atualiza metadados de um projeto existente |
| `listar_projetos` | Lista projetos com metadados e contagem de nós |
| `deletar_projeto` | Remove todas as EAPs e os metadados de um projeto (irreversível) |

### Estrutura
| Tool | Descrição |
|---|---|
| `criar_eap_node` | Cria nó hierárquico, gera EAP_ID (ex.: "1.2.3") e calcula NIVEL |
| `get_eap_tree` | Retorna a árvore completa ou subárvore em JSON aninhado |
| `get_eap_node` | Retorna os dados de um nó específico |
| `validar_estrutura` | Audita a árvore: órfãos, duplicidades, NIVEL, dupla contagem e coerência de tipo_frente |

### Manutenção
| Tool | Descrição |
|---|---|
| `atualizar_eap_node` | Atualiza campos de um nó (valida unidade e tipo_frente) |
| `deletar_eap_node` | Deleta nó (folha) ou subárvore inteira (`cascade=true`) |
| `mover_eap_node` | Move nó + subárvore para outro pai, reenumerando EAP_ID/NIVEL e bloqueando ciclos |

### Consultas e referência
| Tool | Descrição |
|---|---|
| `listar_por_tipo_frente` | Filtra nós por tipo de frente de serviço (ex.: fundacao, estrutura) |
| `listar_templates` | Lista templates de EAP reais (referência histórica de orçamento) |

## Como rodar localmente

```bash
pip install -r requirements.txt
python server.py            # porta padrão 10000
# ou
uvicorn server:app --host 0.0.0.0 --port 10000
```

O servidor expõe o endpoint em `http://localhost:10000/mcp`.
O endpoint `GET /healthz` retorna `{"ok": true}` para probes de disponibilidade.

## Schema do nó (ARES)

- `project_id`: identificador do projeto (PK composta com `eap_id`)
- `eap_id`: código hierárquico gerado (ex.: "1.2.3")
- `parent_id`: auto-referência (NULL = raiz)
- `nivel`: nível armazenado (INTEGER, `pai.nivel + 1`)
- `frente_id`, `local_id`, `tipo_frente`, `nome`, `unidade`, `quantidade`

### Regras de integridade
- **PK composta** `(project_id, eap_id)` — permite várias obras sem colidir códigos.
- **Unidade** em vocabulário fechado (`m², m³, ml, un, kg, conj, vb, pt`), normalizada
  na entrada (`m2` → `m²`).
- **tipo_frente** em vocabulário fechado (`fundacao, estrutura, alvenaria, cobertura,
  instalacoes, esquadrias, revestimento, pintura, acabamento, ...`), normalizado e validado.
- **Quantidade** só permitida em nós-folha (auditado por `validar_estrutura`).
- **Movimentação**: `mover_eap_node` renumera a subárvore para o novo pai (`EAP_ID`/`NIVEL`)
  e bloqueia ciclos (destino não pode ser o próprio nó nem descendente).
- **Auditoria em 2 canais**: `validar_estrutura` retorna `problemas` (estruturais,
  invalidam a árvore) e `avisos` (semânticos — múltiplas raízes, CAIXA ALTA,
  agregador com unidade de medida, tipo divergente no nível 2).

### Idempotência
As tools de **escrita** (`criar_eap_node`, `atualizar_eap_node`, `deletar_eap_node`,
`mover_eap_node`, `deletar_projeto`) aceitam um parâmetro opcional `request_id`. Reenviar o mesmo
`request_id` devolve a resposta anterior em vez de executar de novo — evita duplicar
nós quando um cliente (ex.: Claude) faz retry após timeout. Registros antigos são
removidos a cada inicialização (TTL de 24h).

### Migração automática
Na inicialização, o servidor detecta bancos SQLite no regime antigo (PK simples em `eap_id`)
e os **migra** automaticamente para a PK composta, preservando os dados (atribui
`project_id='default'` aos nós antigos). Bancos **Turso/libSQL novos** já nascem com a
PK composta. Se você reutilizar um database Turso antigo, aplique o novo SCHEMA
manualmente antes do deploy.

## ⚠️ Aviso importante sobre o SQLite

O banco padrão é um arquivo SQLite local (`eap.db`). Em ambientes como o Render,
o sistema de arquivos é **efêmero** — dados são perdidos a cada redeploy. Configure
`TURSO_URL`/`TURSO_TOKEN` para usar Turso/libSQL persistente em produção.

Para migrar um banco criado antes desta versão (PK simples), basta subir o servidor:
a migração é aplicada automaticamente ao primeiro `init_db()`.

**Turso (libSQL)**: o servidor usa o Turso sempre que `TURSO_URL` e `TURSO_TOKEN`
estiverem definidas. URLs `libsql://...` são convertidas automaticamente para
`https://` (Turso novos recusam o handshake WebSocket do Hrana com HTTP 400);
bancos Turso **novos** já nascem com a PK composta.

## Corpus de referência (gerador de EAPs)

`gerador_corpus.py` cria **N obras com EAP 100% válida por construção**
(`validar_estrutura` → `0 problemas` **e** `0 avisos` em todos os projetos):
1 raiz por obra, nomes capitalizados, `tipo_frente` coerente pai→filho,
quantidade só em folhas e unidades no vocabulário fechado.

```bash
python gerador_corpus.py --projetos 300 --seed 7 --db _corpus.db
```

Medido (seed 7, sqlite local): 300 projetos / 10.500 nós em ~3 min.
Determinístico (mesmo `--seed` → mesmo corpus) e **nunca roda contra Turso**
(aborta se `TURSO_URL` estiver definida). Use para testes, benchmarks e
referência histórica antes de popular produção.

## Deploy no Render

1. Conecte o repositório GitHub
2. Build: `pip install -r requirements.txt`
3. Start: `uvicorn server:app --host 0.0.0.0 --port $PORT`
4. (O `Procfile` já contém o comando de start)

Para persistência, defina `TURSO_URL` e `TURSO_TOKEN` nas variáveis de ambiente.
# Updated 2026-09-17T16:01:35Z