Skip to main content
Glama
devCMSS

tds-mcp

by devCMSS
README.md
# tds-mcp

Servidor [MCP](https://modelcontextprotocol.io) que dá a um assistente de IA (Claude Code,
Claude Desktop, ou qualquer cliente MCP) a capacidade de **compilar fontes AdvPL/TLPP,
gerar e aplicar patches e inspecionar o RPO** de servidores TOTVS Protheus.

Por baixo usa o `advpls` — o mesmo TDS Language Server que a extensão
[tds-vscode](https://github.com/totvs/tds-vscode) utiliza — falando JSON-RPC via stdio.
Reaproveita a configuração que você já tem no TDS: servidores, ambientes, includes e tokens.

> **Não distribui binários da TOTVS.** O `advpls` é localizado na extensão tds-vscode já
> instalada na sua máquina. Você precisa ter o TDS instalado e um servidor configurado.

> **Fork.** Baseado no [tds-mcp do Guilherme Pegoraro](https://github.com/Guipegoraro/tds-mcp).
> Acrescenta a blindagem contra falso positivo de compilação e a tool `tds_rpo_delete`
> — veja [Divergências deste fork](#divergências-deste-fork).

## Requisitos

- **Windows** (veja [Limitações](#limitações))
- Node.js 18+
- Extensão [totvs.tds-vscode](https://marketplace.visualstudio.com/items?itemName=totvs.tds-vscode)
  instalada, com pelo menos um servidor configurado e **já conectado uma vez** pelo VS Code
- AppServer Protheus acessível (build 7.00.x)

## Instalação

```bash
git clone https://github.com/Guipegoraro/tds-mcp.git
cd tds-mcp
npm install          # o script "prepare" já compila o TypeScript
```

Registre no Claude Code:

```bash
claude mcp add --scope user tds node "<caminho-do-clone>/dist/index.js"
```

Ou, em qualquer cliente MCP, via configuração JSON:

```json
{
  "mcpServers": {
    "tds": {
      "command": "node",
      "args": ["C:\\caminho\\para\\tds-mcp\\dist\\index.js"]
    }
  }
}
```

## Como a conexão funciona (zero-config)

O MCP lê `~/.totvsls/servers.json` — o arquivo global onde o TDS guarda seus servidores.
Você não precisa cadastrar nada duas vezes:

```
Cliente MCP (Claude)
  └── tds-mcp (Node, stdio)
        ├── lê ~/.totvsls/servers.json  (servidores, ambientes, includes, tokens)
        ├── spawn advpls.exe language-server
        └── JSON-RPC: $totvsserver/connect, compilation, patchGenerate, patchApply, ...
```

Autenticação, em ordem:

1. **Token de reconexão salvo pelo TDS** — funciona sem senha nenhuma. Se expirar, basta
   conectar no servidor pelo VS Code uma vez para renovar.
2. **Credenciais em `~/.tds-mcp/config.json`** — fallback opcional (veja
   [Configuração](#configuração)).

A conexão do MCP é independente da do VS Code: ambos podem estar conectados ao mesmo tempo.

## Tools

| Tool | Descrição | Efeito |
|---|---|---|
| `tds_list_servers` | Servidores do servers.json, ambientes e sessão ativa | read-only |
| `tds_use_server` | Conecta/autentica em servidor + ambiente | sessão |
| `tds_compile` | Compila fontes/pastas no RPO | **grava no RPO** |
| `tds_syntax_check` | Valida sintaxe sem commitar no RPO | nenhum |
| `tds_generate_ppo` | Fonte pré-processado (debug de `#define`/`#include`) | nenhum |
| `tds_rpo_objects` | Lista objetos do RPO (filtro + datas) | read-only |
| `tds_rpo_functions` | Lista funções do RPO (fonte + linha) | read-only |
| `tds_rpo_info` | Versão do RPO + histórico de patches aplicados | read-only |
| `tds_rpo_delete` | **Apaga** fontes/funções do RPO (dry-run por padrão) | **destrutivo** |
| `tds_patch_generate` | Gera PTM com manifesto e rastreabilidade | read-only no RPO |
| `tds_patch_validate` | Valida patch contra o RPO sem aplicar | read-only |
| `tds_patch_info` | Lista o conteúdo de um `.ptm` | read-only |
| `tds_patch_apply` | **Aplica** patch no RPO (deploy) | **destrutivo** |
| `tds_server_log` | Últimas mensagens do advpls (diagnóstico) | read-only |

### Segurança operacional (leia antes de usar em cliente)

`tds_compile`, `tds_patch_generate` e `tds_patch_apply` **alteram o RPO de um servidor real**.
Recomendação forte: configure seu cliente MCP para **sempre pedir confirmação** nessas três.
No Claude Code, em `~/.claude/settings.json`:

```json
{
  "permissions": {
    "ask": [
      "mcp__tds__tds_compile",
      "mcp__tds__tds_patch_generate",
      "mcp__tds__tds_patch_apply",
      "mcp__tds__tds_rpo_delete"
    ]
  }
}
```

As demais tools são read-only e podem ser liberadas sem risco.

## Semântica das datas (importante — evita conclusão errada)

O campo de data que o RPO expõe por objeto (`dataFonte` em `tds_rpo_objects`, `date` em
`tds_patch_info`, `rpoDate` no manifesto, `dataPatch`/`dataRPO` em `tds_patch_validate`)
é o **mtime do arquivo-fonte registrado no momento da compilação** — **não** o instante
em que a compilação ocorreu.

- `dataFonte` == mtime do arquivo em disco (±2s) → o RPO **contém o conteúdo atual**.
- mtime do disco > `dataFonte` → fonte alterado depois da última compilação → recompilar.
- **Nunca** compare com data de commit git: commit posterior ao mtime é normal (editou num
  dia, commitou no outro) e **não** significa RPO desatualizado.

Exceção: `tds_rpo_info.dataGeracao` e as datas do histórico de patches (`geradoEm`,
`aplicadoEm`) são datas de evento reais.

## Rastreabilidade de patches

Cada `tds_patch_generate` produz em `<patchesRoot>/<cliente>/<ticket>/`:

- `DDMMAA_HHMM_<slug>.ptm` — data/hora (padrão brasileiro) lideram o nome, ex.
  `190726_2037_tec10r06.ptm`. Colisão no mesmo minuto ganha segundos (`DDMMAA_HHMMSS`).
- `DDMMAA_HHMM_<slug>.manifest.json` — título e descrição recomendados, sha256, fontes com
  data do RPO, servidor/ambiente/build de origem, autor, commit git (opcional)
- `historico.jsonl` — append-only por ticket (gerações, validações, aplicações)
- `<patchesRoot>/historico-global.jsonl` — histórico consolidado

Título recomendado (data e hora primeiro): `19/07/2026 20:37 — Cliente ticket — FONTE.PRW`

## Configuração

Opcional. Copie `config.example.json` para `~/.tds-mcp/config.json`:

```json
{
  "patchesRoot": "C:\\TOTVS\\patches",
  "advplsPath": "",
  "credentials": {
    "NomeDoServidorNoTDS": { "user": "usuario", "password": "senha" }
  }
}
```

- `patchesRoot` — raiz da árvore de patches (padrão `C:\TOTVS\patches`)
- `advplsPath` — só se o advpls não estiver na extensão instalada. Também aceita a variável
  de ambiente `TDS_MCP_ADVPLS`
- `credentials` — **senhas em texto plano**. Prefira deixar vazio e usar o token do TDS.
  O arquivo fica fora do repositório; nunca o versione.

## Desenvolvimento e testes

```bash
npm run build                                  # compila TypeScript

node test/smoke.mjs <servidor> [ambiente]      # read-only: conecta e inspeciona o RPO
node test/debug-protocol.mjs [host] [porta]    # JSON-RPC cru (diagnóstico de protocolo)

node test/e2e-mcp.mjs <servidor> [ambiente]    # E2E: COMPILA um fonte de teste no RPO
node test/cleanup.mjs <servidor> [ambiente]    # remove o fonte de teste do RPO
```

O E2E compila `test/zTstMcp1.prw` (User Function inofensiva) e gera um patch. **Use apenas
em ambiente de desenvolvimento descartável** e rode o cleanup depois.

## Divergências deste fork

### 1. Compilação não retorna mais sucesso sem evidência

**O problema.** O AppServer pode abortar o build **antes** de compilar qualquer fonte (RPO
travado, ambiente inválido). Nesse caminho ele devolve `compileInfos` **vazio** — e o código
original derivava sucesso de "nenhum erro no array", produzindo:

```json
{ "totalFontes": 1, "sucesso": true, "erros": 0, "resultados": [] }
```

...enquanto o log do servidor, no mesmo instante, dizia:

```
Starting build for environment p12dev.
Start build error: Server returned:
COMPILEERROR-300 Failed to open repository
```

O fonte não entrou no RPO. Quem confiasse no retorno mandaria rodar uma função inexistente.

**A correção.** Três regras, em `src/verdict.ts`:

1. **Falha do servidor é propagada.** As mensagens de `window/*Message` emitidas *durante* a
   operação são isoladas por cursor de log e varridas por `Start build error`,
   `COMPILEERROR-*`, `PATCHERROR-*` e afins. Detectou → `sucesso:false`, `erros>=1`, com
   `falhaServidor` e `logServidor` no retorno.
2. **Ausência de evidência nunca é sucesso.** `resultados` vazio com `totalFontes > 0` vira
   `indeterminado:true` + `sucesso:false`, com aviso para conferir no RPO.
3. **`SKIPPED` não é validação.** Fonte já compilado volta como
   `SKIPPED / "Source already compiled"` — o servidor **não** o analisou, mas ainda loga
   *"All files compiled successfully"*. Era o que mascarava erros reais (um
   `C9905 Invalid use of NAMESPACE command` só apareceu num recompile forçado). Agora
   `tds_syntax_check` usa `forcar=true` por padrão (seguro: `syntaxOnly` não grava no RPO) e,
   se ainda assim vier tudo `SKIPPED`, devolve `sintaxeOk:false` + `indeterminado:true`.

`tds_patch_validate` / `tds_patch_apply` receberam a mesma blindagem: resposta ausente ou
sem o campo `error` vira `indeterminado`, não sucesso. `tds_patch_generate` aborta se o
servidor sinalizou falha, em vez de adotar um `.ptm` antigo da pasta.

### 2. Nova tool: `tds_rpo_delete`

Expõe o *Delete source/resource from RPO* do TDS (`$totvsserver/deletePrograms`), que faltava.
Necessária para dois casos rotineiros:

- **fonte renomeado** (`ABC0187.PRW` → `ABC0187.tlpp`) deixa o antigo no RPO e gera
  `Duplicated function U_ABC0187() ... found in ABC0187.PRW`;
- **funções órfãs**, compiladas e sem fonte correspondente.

```jsonc
// Simulação (padrão) — mostra o alcance e não apaga nada
tds_rpo_delete({ "programas": ["ABC0187.PRW"] })

// Execução
tds_rpo_delete({ "programas": ["ABC0187.PRW"], "confirmar": true })
```

Salvaguardas:

- **dry-run por padrão**: sem `confirmar:true` nada é apagado;
- **aceita fonte ou função**: `U_ABC0187` é resolvido para o fonte que a contém — e o retorno
  deixa explícito que o **fonte inteiro** vai embora;
- **blast radius**: lista todas as funções que morrem junto antes de você confirmar;
- **recusa alvo inexistente** em vez de apagar por engano;
- **verifica depois**: relê o RPO e confirma que sumiu, em vez de confiar no `returnCode` —
  a mesma lição do bug acima.

### Testes

```bash
npm run test:verdict   # regressão do falso positivo, com o log real do incidente
npm run test:live      # contra servidor real, só read-only e dry-run (sem efeito colateral)
npm run test:delete    # round-trip do delete — COMPILA E APAGA, só em ambiente descartável
```

`test:live` não grava nada no RPO — pode rodar em ambiente de cliente:

```bash
node test/live-safe.mjs "MEU SERVIDOR" p12dev C:/fontes/ABC0187.tlpp ABC0187.PRW
```

`test:delete` faz o caminho completo (compila `test/zTstMcp1.prw`, apaga, confirma que sumiu,
e checa que apagar o inexistente recusa em vez de fingir sucesso). **Só em ambiente de
desenvolvimento descartável:**

```bash
node test/roundtrip-delete.mjs "MEU SERVIDOR DEV" DEV01
```

## Limitações

- **Windows apenas** por enquanto: a resolução do binário procura
  `bin/windows/advpls.exe` na extensão tds-vscode. O `advpls` existe para Linux e macOS
  (`@totvs/tds-ls`), então o suporte é uma mudança pequena em `resolveAdvplsPath()` —
  PRs bem-vindos.
- **O protocolo `$totvsserver/*` não é um contrato público da TOTVS.** Ao atualizar a
  extensão TDS, o binário muda junto; se algo quebrar, `tds_server_log` ajuda a
  diagnosticar. A especificação viva é
  [`src/protocolMessages.ts`](https://github.com/totvs/tds-vscode/blob/master/src/protocolMessages.ts).
- O advpls **não aceita** o handshake LSP `initialize` com params mínimos (derruba o
  processo com `0xC0000409`). Os requests `$totvsserver/*` são enviados diretamente — é o
  que o `@totvs/tds-languageclient` oficial também faz.
- Fora do escopo da v1 (mas mapeados no protocolo): monitor de usuários conectados,
  `defragRPO`, `rpoCheckIntegrity`, `deletePrograms`, `wsdlGenerate`.

## Alternativas headless

Se você precisa de CI/CD em vez de um assistente:

- `advpls cli <script.ini>` — modo CLI oficial do TDS Language Server (script INI em CP1252)
- `appserver.exe -compile` — compilação/patch direto pelo AppServer, usado nos pipelines
  oficiais da TOTVS ([totvs/protheus-ci-universo](https://github.com/totvs/protheus-ci-universo))

## Créditos

Este projeto não é afiliado à TOTVS. O protocolo foi derivado do código-fonte público do
[tds-vscode](https://github.com/totvs/tds-vscode) (Apache-2.0) e da documentação do
[tds-ls](https://github.com/totvs/tds-ls). Protheus, AdvPL, TLPP e TOTVS são marcas de
seus respectivos proprietários.

## Licença

MIT — veja [LICENSE](LICENSE).

TDQS

A4/5.0

Scored across 13 tools

Disambiguation5/5

Every tool targets a distinct operation in the Protheus development workflow: server selection, compilation, syntax checking, RPO analysis, and patch management. No two tools overlap in purpose.

Naming Consistency4/5

Most tools follow a predictable 'tds_verb_noun' or 'tds_noun_verb' pattern (e.g., tds_list_servers, tds_rpo_delete). However, a few tools like 'tds_compile' lack a resource prefix, and 'tds_syntax_check' omits an explicit resource, introducing minor inconsistency.

Tool Count5/5

13 tools is well-scoped for a Protheus MCP server, covering connection, compilation, RPO inspection, and patching without unnecessary bloat. Each tool serves a clear, non-redundant purpose.

Completeness4/5

The tool surface covers core lifecycle operations for Protheus development (compile, syntax check, RPO management, patching). Minor gaps exist, such as no explicit disconnect tool or server configuration editor, but these do not impede typical agent workflows.

Maintenance

ActivityStale
ResponsivenessNo issues