Pular para conteúdo

MCP para agentes

Além do site, este projeto expõe um servidor MCP — a interface feita para um agente de IA, não para um navegador.

https://tlpp.stellvick.fun/mcp

Mesmo domínio do wiki. O roteamento é por caminho: /mcp vai para o servidor MCP, todo o resto para o site. Quem faz essa separação é um gateway Caddy no mesmo stack (o Coolify prende um domínio a um único serviço, então dois serviços HTTP atrás do mesmo host exigem um gateway).

Por que existe

O site é feito para olhos: tabelas formatadas, navegação, tema. Um agente não quer isso — ele quer dados precisos, em Markdown, sem casca. E há uma coisa que só existe no MCP: os relacionamentos entre tabelas, que ficaram fora do repositório por volume (são ~75% do JSON de uma tabela) mas são exatamente o que um agente precisa.

Necessidade do agente Como o site resolve Como o MCP resolve
Estrutura de uma tabela página de busca, clique campos("SD1") → Markdown
Em quais tabelas existe um campo busca por campo buscar_campo("D1_COD")
Ligação entre tabelas não tem relacionamentos("SD1")
O que já está escrito no wiki ler a página buscar_wiki / ler_pagina
Página TOTVS externa limpa abrir no navegador ler_externo(url)

Ferramentas

Ferramenta O que responde
buscar_tabela(termo, limite) código (SD1) ou nome (clientes) → tabelas
campos(tabela) estrutura SX3 completa: campo, título, descrição, tipo, contexto, tamanho
buscar_campo(campo, limite) em quais tabelas o campo existe (prefixo: D1_ = todo o SD1)
indices(tabela) chaves e nicknames (SIX), na ordem
relacionamentos(tabela, direcao, limite) ligações SX9 — só aqui
buscar_texto(termo, limite) busca por significado em nomes e descrições
buscar_wiki(termo, limite) trechos do wiki, com o caminho da página
ler_pagina(pagina) Markdown integral de uma página, pelo slug
ler_externo(url) página externa → Markdown limpo
listar_exemplos(status) exemplos guardados, com o estado de avaliação
ler_exemplo(slug) o código de um exemplo, com o aviso de estado
salvar_exemplo(...) guarda código gerado como exemplo/template — escrita trancada
marcar_avaliado(slug, como_testou) promove de nao-avaliada para avaliada — escrita trancada

Duas decisões que valem explicar

Não há extração de HTML para o nosso próprio wiki. O fonte já é Markdown — a forma mais limpa que existe. Passar Defuddle no HTML gerado do site seria um passo para trás. O Defuddle entra onde ele realmente vale: página externa (TDN, fórum, Terminal de Informação), que chega como HTML de 720 KB cheio de casca. Medido: a página do SD1 no Terminal de Informação rende ~60 KB de Markdown limpo.

Não há servidor de banco. O índice é um arquivo SQLite com FTS5, construído no build da imagem a partir do repositório. Um escritor (o build), leitores somente-leitura, ~54 MB de dados: nada que justifique um Postgres para operar — backup, versão, conexões — sem retorno. O FTS5 ainda resolve a busca textual sem precisar montar um índice invertido à mão.

Exemplos gerados: nascem nao-avaliada

Um agente que gera código pode guardá-lo como exemplo ou template. O que ele não pode é apresentá-lo como confiável.

Todo exemplo salvo por salvar_exemplo entra no estado nao-avaliada — não foi compilado, não foi executado, não foi testado contra um Protheus real. A página do exemplo carrega o aviso, e o índice mostra o estado.

Para promover a avaliada existe marcar_avaliado, e ela recusa sem o campo como_testou: o estado exige o registro de como o código foi testado e qual foi o resultado. Sem isso, "avaliada" seria um selo de confiança sem lastro — exatamente o que este repositório existe para não fazer.

A escrita falha fechada

Todas as ferramentas de escrita recusam enquanto GITHUB_TOKEN e EXEMPLOS_CHAVE não estiverem definidos no serviço mcp. Um endpoint público com poder de commit e sem trava seria entregar o repositório: qualquer um que descobrisse a URL escreveria no repo. Sem os dois, as ferramentas apenas respondem o que falta configurar.

Publicação

Site e MCP são reconstruídos juntos, da mesma imagem de repositório: um push em main dispara um webhook do GitHub que o gateway encaminha ao Coolify. Não há etapa de revisão entre o push e a produção — quem publica testa antes.

Conectar um cliente

claude mcp add --transport http advpl-tlpp https://tlpp.stellvick.fun/mcp
mcp_servers:
  advpl-tlpp:
    url: https://tlpp.stellvick.fun/mcp

O mesmo servidor roda sem rede, lendo o banco local:

python3 scripts/tabelas/build_db.py
python3 mcp/servidor.py            # stdio, sem dependências

Limites, declarados

Lacuna: o servidor responde sobre o que já foi coletado. A coleta é incremental; buscar_tabela devolve o que existe no banco naquele momento.

Segurança: ler_externo só aceita uma lista de domínios conhecidos (TOTVS, fórum, Terminal de Informação). Um endpoint público que busca URL arbitrária é um vetor de SSRF — a lista é a defesa, e é configurável por EXTERNO_PERMITIDO.