fluig-mcp
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 6 GitHub stars
Code Warn
- network request — Outbound network request in package-lock.json
- process.env — Environment variable access in server.js
- process.env — Environment variable access in src/config.js
- process.env — Environment variable access in src/saida.js
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Servidor MCP para o TOTVS Fluig - administre datasets, formularios, eventos globais e definicoes de processo BPM pela API, sem o Fluig Studio.
fluig-mcp
Servidor MCP para o TOTVS Fluig. Dá a um agente de IA —
Claude Code, Claude Desktop, Cursor, ou qualquer cliente MCP — acesso às APIs REST e SOAP do
Fluig: datasets, formulários, fichas, GED, eventos, agendador, processos BPM e a ponte para o
TOTVS RM (Corpore).
98 ferramentas, homologação e produção no mesmo servidor, sem abrir o Fluig Studio.
┌──────────────┐ stdio/MCP ┌───────────┐ REST v1/v2 ┌──────────────┐
│ Claude Code │ ◄─────────────────► │ fluig-mcp │ ◄────────────► │ TOTVS Fluig │
│ (ou outro) │ │ 98 tools │ SOAP/WSDL │ + RM │
└──────────────┘ └───────────┘ └──────────────┘
Por que isto existe
Desenvolver e operar no Fluig normalmente exige o Fluig Studio (Eclipse) na sua máquina e muito
clique no Painel de Controle. Coisas simples — ler o beforeTaskSave de um processo, descobrir
por que uma solicitação travou, conferir as linhas de uma tabela pai-filho, publicar uma versão
que ficou em edição — viram sessões inteiras de navegação manual.
Este servidor expõe tudo isso como ferramentas que um agente chama direto. E, mais importante:
ele embute as armadilhas do produto que custaram tempo para descobrir (veja
Armadilhas conhecidas), para que você não precise redescobrir
cada uma na marra.
Instalação
Requer Node.js 20+. Direto do npm, sem clonar nada:
npx -y [email protected] --list
Fixe a versão. Sem ela, o npx busca a última publicada a cada subida, num processo que recebe a
sua senha de produção; com ela, você atualiza quando decidir. Cada versão sai do CI deste repositório
com provenance e só fica pública depois de
aprovada com 2FA — confira com npm view [email protected] dist.attestations. Também dá para instalar
pelo tarball anexado a cada Release ou direto do
GitHub (ver docs/clientes.md).
Ou clonando, para ler o código antes:
git clone https://github.com/alucardigo/fluig-mcp.git
cd fluig-mcp
npm install
node server.js --list
Inspecione o que ele faz antes de dar credencial a ele: o --list acima já faz isso.
--list não carrega configuração nenhuma, de propósito: você consegue auditar a superfície
inteira antes de confiar uma senha ao processo.
Configuração
Nenhuma variável tem default. Host ou senha embutidos no código seriam um vazamento esperando
acontecer, então variável faltando é erro explícito, nunca fallback silencioso para o
servidor de outra pessoa.
| Variável | Ambiente | Obrigatória |
|---|---|---|
FLUIG_HOST · FLUIG_USER · FLUIG_PASS (ou FLUIG_PASS_CMD) |
homologação (env: "teste") |
para usar homologação |
FLUIG_HOST_PROD · FLUIG_USER_PROD · FLUIG_PASS_PROD (ou FLUIG_PASS_CMD_PROD) |
produção (env: "prod") |
para usar produção |
FLUIG_PASS_CMD · FLUIG_PASS_CMD_PROD |
no lugar da senha: comando que a imprime (cofre do sistema) | não |
FLUIG_COOKIE_CMD · FLUIG_COOKIE_CMD_PROD |
no lugar da senha, para tenant com MFA ou SSO: comando que imprime o cookie de sessão (sem login.do) |
não |
FLUIG_COOKIE_TIMEOUT_MS |
espera máxima do comando de cookie, em milissegundos (padrão 120000, o tempo para aprovar o MFA); vale para os dois ambientes |
não |
FLUIG_USERCODE · FLUIG_USERCODE_PROD |
código do colaborador; sem ele, é descoberto pela sessão | não |
FLUIG_SAIDA_DIR |
pasta onde destino grava e de onde sai o arquivo que sobe ao Fluig (caminhoLocal, zipPath, xmlPath, svgPath); padrão ~/fluig-mcp-saida, fora dela é recusado |
não |
FLUIG_READONLY=1 |
ambos | não — mas leia Segurança |
Configure um dos pares, ou os dois. Veja .env.example para as opcionais
(tenant, datasources JNDI, IPs semente, prefixo dos datasets descartáveis).
Senha fora do arquivo de configuração
FLUIG_PASS_CMD (e FLUIG_PASS_CMD_PROD) recebe um comando que imprime a senha; vale só a primeira
linha da saída, como no pass. Ele roda sem shell, só quando o ambiente é usado, e falha antes de
qualquer login se o comando falhar, se a primeira linha vier vazia ou se a saída não for UTF-8. Aspas
simples ou duplas agrupam um argumento; a barra invertida é literal e o fluig-mcp não expande ~ nem$VAR (use caminho absoluto, ou deixe o PowerShell expandir, como no exemplo do Windows). Exemplos
para produção (para homologação, troque fluig-prod por fluig-teste):
| Sistema | Guardar uma vez | FLUIG_PASS_CMD_PROD |
|---|---|---|
| Linux (GNOME Keyring/KWallet) | secret-tool store --label=fluig-prod service fluig-prod user seu.usuario |
secret-tool lookup service fluig-prod user seu.usuario |
| macOS (Keychain) | security add-generic-password -s fluig-prod -a seu.usuario -w |
security find-generic-password -s fluig-prod -w |
| pass | pass insert fluig-prod |
pass show fluig-prod |
| 1Password CLI | (no app) | op read op://Pessoal/Fluig/password |
| Windows (PowerShell) | Get-Credential seu.usuario | Export-Clixml $env:USERPROFILE/.fluig-prod.xml |
powershell.exe -NoProfile -NonInteractive -Command '[Console]::OutputEncoding = [Text.Encoding]::UTF8; [Console]::Out.Write((Import-Clixml $env:USERPROFILE/.fluig-prod.xml).GetNetworkCredential().Password)' |
No Windows, .cmd/.bat não rodam sem shell; o porquê e as alternativas estão em
docs/clientes.md.
⚠️ No macOS, security find-generic-password -w devolve a senha em hexadecimal quando ela tem
caractere fora do ASCII (acento, ç) — e o login iria com a senha errada, gastando uma tentativa no
AD. Com senha assim, use outro cofre da tabela (pass, op).
O comando roda uma vez por processo, na primeira chamada daquele ambiente, que espera o cofre (até 15 s;
se ele pedir desbloqueio, é a hora). Trocou a senha no cofre? Reinicie o cliente MCP.
No GitHub Copilot (VS Code) não precisa disso: o próprio VS Code pede a senha e a guarda (exemplo em
docs/clientes.md).
Se o tenant exige MFA ou SSO, a senha do cofre não entra no login: nesse caso, use o
cookie de sessão, que dispensa a senha.
Tenant com MFA ou SSO: cookie de sessão
Quando o login com usuário e senha não serve (MFA ou SSO), FLUIG_COOKIE_CMD (e FLUIG_COOKIE_CMD_PROD)
recebe um comando que imprime o cookie de sessão já aberto: JSESSIONIDSSO=… ou jwt.token=…. Roda sem
shell, com as mesmas regras de aspas do FLUIG_PASS_CMD, e a saída inteira é lida. Nesse modo:
- não há senha, e o cliente nunca chama
login.donem tenta a senha, nem quando o cookie falha. Cada
tentativa de senha recusada pelo servidor conta contra o bloqueio da conta; - cookie recusado dá erro com a instrução de gerar outro e rodar
fluig_session_reset. O comando não roda
de novo sozinho: o reset é o que libera a próxima execução. Vale também quando o próprio comando falha
(cofre bloqueado, MFA recusado, saída sem cookie), porque cada execução pode disparar outro desafio; - o comando não trava o servidor: enquanto ele espera o cofre ou a aprovação do MFA, as outras ferramentas
continuam. A espera máxima éFLUIG_COOKIE_TIMEOUT_MS(padrão 120 s), e o estouro aparece na mensagem; fluig_versionmostra só os nomes dos cookies, nunca o valor;- as operações que falam com os serviços SOAP do Fluig (
ECMDatasetService,ECMCardIndexService,WorkflowEngineServiceeTokenService) ficam indisponíveis e são recusadas antes de qualquer chamada,
porque levam usuário e senha no corpo da requisição. As que usam a API REST funcionam com o cookie.
Não combine com FLUIG_PASS nem com FLUIG_PASS_CMD no mesmo ambiente: a configuração recusa a combinação.
Configuração de cada cliente (Claude Code, Codex, GitHub Copilot, Cursor, Claude Desktop):
docs/clientes.md.
Registrando no cliente MCP
Claude Code / Claude Desktop (~/.claude.json ou claude_desktop_config.json):
{
"mcpServers": {
"fluig": {
"command": "node",
"args": ["/caminho/para/fluig-mcp/server.js"],
"env": {
"FLUIG_HOST": "http://fluig-homolog.suaempresa.com.br:8080",
"FLUIG_USER": "seu.usuario",
"FLUIG_PASS_CMD": "secret-tool lookup service fluig-teste user seu.usuario",
"FLUIG_HOST_PROD": "https://fluig.suaempresa.com.br:8443",
"FLUIG_USER_PROD": "seu.usuario",
"FLUIG_PASS_CMD_PROD": "secret-tool lookup service fluig-prod user seu.usuario"
}
}
}
}
Se o seu cliente MCP demora a subir servidores pesados, aumente o timeout de inicialização
(no Claude Code:MCP_TIMEOUT, em milissegundos). O default de 30 s estoura quando vários
servidores sobem em paralelo — e o sintoma,connection timed out, parece bug deste servidor
sem ser.
env é obrigatório em toda chamada
Não existe ambiente default. Toda ferramenta exige env: "teste" ou env: "prod", e omitir ou
errar o valor é recusado antes de qualquer acesso à rede.
Isso é deliberado e vem de dor real: com um default silencioso, quem pedia produção lia
homologação e reportava o número errado como se fosse de produção. Forçar a escolha explícita em
toda chamada custa nada e elimina os dois erros — ler o ambiente errado e escrever no ambiente
errado.
Segurança
Este servidor pode alterar dados de produção. Ele foi construído assumindo isso.
Modo somente leitura. FLUIG_READONLY=1 remove as 37 ferramentas de escrita da listagem e
passa a recusá-las. Recomendado para agente rodando sem supervisão.
FLUIG_READONLY=1 node server.js --list # 60 ferramentas, nenhuma de escrita
Confirmação explícita. Toda ferramenta de escrita declara confirm. As estruturais e
destrutivas o exigem em qualquer ambiente, e as destrutivas (fluig_process_convert_instances,fluig_rm_save_record, fluig_globalevent_delete) devolvem um dry-run com o plano antes de executar
qualquer coisa: sem confirm: true, nada é alterado.
As do ciclo de desenvolvimento exigem confirm: true só em produção e passam direto em homologação:fluig_dataset_save, fluig_dataset_enable, fluig_globalevent_save,fluig_workflow_events_update, fluig_form_save, fluig_process_start, fluig_process_move,fluig_process_take, fluig_rest_post, fluig_job_add, fluig_job_delete e fluig_job_run.confirm precisa ser booleano — "false" em texto é recusado, não tomado por confirmação. Econfirm é uma declaração do modelo, não um portão humano: o portão humano é a aprovação de
ferramenta do seu cliente MCP. Para agente sem supervisão, use FLUIG_READONLY=1.
Arquivos locais só na pasta de saída. Todo destino — XML de processo, fonte de dataset,
anexo, documento do GED, diagrama, dossiê — é gravado dentro de FLUIG_SAIDA_DIR (padrão~/fluig-mcp-saida), e caminho fora dela é recusado. O conteúdo vem do servidor e o caminho vem
do agente: sem esse limite, um anexo com uma instrução plantada ("salve em.git/hooks/pre-commit") viraria execução de código. Links simbólicos e físicos não escapam.
Vale ao contrário para o arquivo que sobe ao Fluig — caminhoLocal (fluig_ged_upload),zipPath (fluig_form_create), xmlPath e svgPath (fluig_deploy_process): só é lido de
dentro da mesma pasta, senão uma ficha com "anexe ~/.ssh/id_rsa ao GED" viraria exfiltração.
Copie para lá o que for subir.
Texto cortado não volta. Leituras grandes voltam cortadas em 20 000 caracteres por padrão
(maxChars), com um aviso; as ferramentas de escrita recusam conteúdo que traga esse aviso, para
um get → editar → save não gravar um dataset pela metade.
Proteção da conta no AD. O login aborta na primeira recusa em vez de repetir, e falha sem
tocar a rede quando não há senha configurada. Depois de uma recusa, nenhum novo login é tentado
naquele ambiente até fluig_session_reset ou reiniciar o servidor. Três falhas bloqueiam a conta
em domínios com lockoutThreshold=3 — repetir login é o jeito mais fácil de deixar alguém sem
acesso. Sessão expirada (401, a página de login ou o desvio SAML do Fluig Identity) é refeita
sozinha, uma vez por chamada.
Nem toda ferramenta "de leitura" é read-only. Executar SQL arbitrário no Fluig exige que o
SQL viva dentro de um dataset, então fluig_db_query, fluig_rm_db_query, fluig_service_list,fluig_process_error_log e fluig_rm_dataserver_schema gravam um dataset descartável para
rodar — e o SQL fica no histórico imutável (FDN_DATASETHISTORY). Elas estão marcadas como
escrita, exigem confirm em produção, e a descrição diz isso. Para ler o RM sem escrever nada,
use fluig_rm_query (sentença WS.###), que roda pelo dataset-handle/search.
Um dataset passthrough permanente eliminaria essa escrita, mas criaria coisa pior: um dataset
publicado que executa SQL de qualquer chamador com permissão de rodar dataset. Trocar rastro de
escrita por elevação de privilégio é mau negócio — por isso não foi feito.
Para reportar vulnerabilidade, veja SECURITY.md.
As ferramentas
! marca as que alteram o servidor.
BPM e processos (48)fluig_task_list · fluig_task_count · fluig_request_list · fluig_request_get ·fluig_process_def_states · fluig_process_states · fluig_process_active_states ·fluig_process_states_detail · fluig_process_actual_thread · fluig_process_history ·fluig_process_attachments · fluig_process_attachment_download · fluig_process_available ·fluig_process_available_users · fluig_process_available_users_start · fluig_process_search ·fluig_process_version · fluig_process_versions · fluig_process_image ·fluig_process_diagram_get · fluig_process_export_xml · fluig_process_events_xml ·fluig_process_event_get · fluig_process_possible_assignees · fluig_process_formid ·fluig_process_activities_resume · fluig_deadline_calc · fluig_workflow_exporter ·fluig_workflow_check · fluig_workflow_events_get · fluig_deploy_list ·
! fluig_process_start · ! fluig_process_move · ! fluig_process_move_rest ·
! fluig_process_take · ! fluig_process_cancel · ! fluig_process_import_xml ·
! fluig_process_event_set · ! fluig_process_event_set_xml ·
! fluig_process_version_release · ! fluig_process_version_withdraw ·
! fluig_process_version_delete · ! fluig_process_diagram_set ·
! fluig_process_create · ! fluig_process_convert_instances ·
! fluig_process_error_log · ! fluig_deploy_process · ! fluig_workflow_events_update
Formulários e fichas (14)fluig_form_list · fluig_form_events · fluig_form_files · fluig_form_file ·fluig_form_full · fluig_form_fields · fluig_card_list · fluig_card_children_get ·fluig_card_html_url · fluig_process_card_get · fluig_process_card_value ·
! fluig_form_save · ! fluig_form_create · ! fluig_card_save
Datasets (12)fluig_dataset_list · fluig_dataset_get · fluig_dataset_run · fluig_dataset_structure ·fluig_dataset_admin · fluig_dataset_history · fluig_dataset_draft_check ·
! fluig_dataset_save · ! fluig_dataset_delete · ! fluig_dataset_enable ·
! fluig_dataset_restore · ! fluig_dataset_state_set
GED (4)fluig_ged_list · fluig_ged_path · fluig_ged_download · ! fluig_ged_upload
TOTVS RM e integração (6)fluig_rm_query · ! fluig_rm_db_query · ! fluig_rm_db_exec ·
! fluig_rm_dataserver_schema · ! fluig_rm_save_record · ! fluig_service_list
Agendador (4) · Eventos globais (3) · Diagnóstico (7)fluig_jobs_list · ! fluig_job_add · ! fluig_job_delete · ! fluig_job_run ·fluig_globalevent_list · ! fluig_globalevent_save · ! fluig_globalevent_delete ·fluig_ping · fluig_version ·fluig_session_reset · fluig_user_replacements · fluig_rest_get · ! fluig_rest_post ·
! fluig_db_query
Descrição completa de cada uma: node server.js --list.
Armadilhas conhecidas do Fluig
Cada item abaixo foi medido contra um servidor real e está embutido no código — a ferramenta
valida, converte ou explica em vez de deixar você tropeçar.
| Armadilha | O que acontece |
|---|---|
date-calculator usa seconds, não duration |
Mandar duration devolve NullPointerException — parece bug do produto e é parâmetro faltando. A API trabalha em segundos, mas o deadlineTime do modelo é gravado em minutos: trocar um pelo outro erra o prazo por 60×. |
childrens lê, children escreve |
A rota de leitura das linhas pai-filho é plural; a de escrita é singular. Trocar dá 404. |
folders/{id}/documents devolve grid antigo |
A lista vem em invdata, não em items, e totalrecords não é o total. Pasta cheia parece vazia para quem procura items. |
order é obrigatório no GED |
Sem ele, a rota devolve 500, não 400. |
cardindex/html não aceita cardId |
Combinação inválida de parâmetros devolve 500. Use documentId+documentVersionId ou processId+processInstanceId. |
tasks/count sem filtro |
Varre a base inteira e passa de 120 s. A ferramenta exige processId. |
states/activities/resume falha em alguns processos |
javax.ejb.EJBException independente dos parâmetros. Bug do produto — caia para fluig_task_list/fluig_request_list. |
dataset-handle/search nunca devolve 404 |
Dataset inexistente responde 200 com columns/values nulos. "Não existe" se disfarça de "zero linhas". |
constraintsField sem valor inicial |
Devolve 500, não 400. Validado antes de sair da máquina. |
| Booleanos do BPM v2 são string | ?active=1 devolve 400; o enum é ["true","false"]. |
pageSize muda por rota |
1000 no BPM, 100 em cards/childrens e no GED. |
dataset-history ignora fields/expand |
Cada item traz o fonte inteiro (~8 KB). O histórico é imutável pela API: senha que já esteve num dataset continua legível lá. |
| Falar por IP quebra de dois jeitos | Dispara bloqueio de IPS ("Web Filter Violation") e quebra o TLS/SNI em HTTPS. O cliente sonda IP para saber se há caminho vivo, mas chama pelo hostname. |
cardData do move SOAP substitui o registro |
Todo campo não enviado some. Leia o card antes (fluig_process_card_get). |
convert_instances é irreversível |
Converter finaliza as tarefas pendentes e cria novas no destino. Mapeamento errado = trabalho em curso perdido. Dry-run obrigatório. |
Anexo: bug de @QueryParam duplicado |
Na rota plural, user e replacedUser têm a mesma anotação. A ferramenta usa só a singular. |
workflow-exporter anonimiza por default |
anonymizeForms é true no servidor. A ferramenta exige a escolha explícita. |
/documents/{id}/stream mente o Content-Type |
A implementação reusa o helper dos thumbnails. Confie no Content-Disposition. |
| 2xx sem corpo é normal | release, withdraw, delete devolvem 204; dataset-history/restore devolve 201 onde a spec diz 202. Nunca faça JSON.parse cego. |
Desenvolvimento
npm run check # checagem de sintaxe
npm test # testes unitários (node --test)
npm run list # superfície de ferramentas, sem credencial
Contribuições são bem-vindas — veja CONTRIBUTING.md.
Créditos
Gian (@kyso1) — issue #3,
PR #4, #5,
#6 e #7
Mediu num Fluig 1.7.1 de produção que, quando o código do colaborador é a matrícula e não o login,fluig_form_list voltava vazio sem erro — e trouxe a correção, que descobre o código pela
sessão e tirou a senha da URL do resolveTenant. Também são dele os filtros no servidor dofluig_dataset_run, a senha vinda de um cofre (FLUIG_PASS_CMD), o guia de instalação por
cliente (docs/clientes.md) e o limite de saída inline com a pasta de saída
restrita. Foi ele quem apontou que o destino dos downloads gravava em qualquer caminho — o que
levou a pasta de saída a valer para todo arquivo que este servidor grava. A proposta veio antes
dos PRs, com o plano e as medições, e cada PR chegou pequeno, empilhado e testado.
Achou em produção, num Fluig atrás do Fluig Identity, que a sessão expirada não volta como 401, e
sim como HTTP 200 com o formulário SAML — e o servidor passava horas devolvendo a página de SSO
até ser reiniciado. A correção refaz o login uma única vez por chamada, agrupa logins simultâneos
num só e amarra o cache SOAP ao cookie, sem abrir mão da proteção contra bloqueio no AD.
Diagnosticou que o fetch do Node deriva o SNI e a verificação do certificado da URL, não do
header Host — então chamar pelo IP fixado quebrava toda requisição HTTPS. O sintoma parecia
instabilidade de rede, e foi tratado como tal por bastante tempo antes de ele apontar a causa.
A correção foi estendida no merge para o cliente SOAP, onde o mesmo defeito existia.
Do fork dele vieram também três decisões de projeto que este repositório adotou:
configuração sem defaults (endpoint ou senha embutidos são vazamento esperando acontecer),
modo somente leitura e --list auditável sem credencial — a ideia de que a superfície de
ferramentas precisa ser inspecionável antes de o servidor receber uma senha, hoje verificada no CI.
Fluiggers (MIT, © Bruno Gasparetto e
colaboradores) — a extensão VS Code da comunidade. Daqui vem o comportamento quesrc/datasetFiltros.js reproduz: a tradução de condições de consulta de
dataset para as constraints do Fluig. As rotas de eventos de processo em src/client.js
usam o FluiggersWidget, publicado pelo projeto deles (fluig-widget-helper).
Licença
MIT.
TOTVS, Fluig e RM/Corpore são marcas da TOTVS S.A. Este projeto é independente e não é afiliado,
patrocinado nem endossado pela TOTVS.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found