@renanlido/tia-openness-mcp
v1.4.0
Published
MCP server (stdio) — thin HTTP client over the TIA Openness `serve` API. Zero Openness/net48 references.
Readme
TIA Openness MCP server
Servidor MCP (stdio) que é um cliente HTTP puro sobre a API serve do TIA Openness
(veja docs/API-HTTP.md no repositório). Não referencia Openness / net48 / x64 — toda a
complexidade (AssemblyResolve, worker serial MTA) vive no processo serve. Aqui só falamos MCP de um
lado e HTTP/JSON do outro.
Cross-platform: o MCP é Node puro (bundle ESM com shebang) e roda em macOS / Linux / Windows
(Node ≥ 20). Só a API serve é Windows-only (net48/x64 + Openness) — por isso o arranjo canônico é
MCP no seu laptop (ex.: Mac) → serve num host/VM Windows, apontado por env (veja abaixo).
Distribuído como pacote npm bundled (esbuild → 1 arquivo self-contained, sem node_modules em runtime),
publicado no npm público via semantic-release — rode com um one-liner, sem auth e sem .npmrc:
npx -y @renanlido/tia-openness-mcpOperating guide embedded (tia_guide)
The harness operating guide ships inside the MCP itself, in three layers:
- Server
instructions— the always-on operating brief (content/brief.md) travels in the MCP handshake (instructionsfield). Any client that honorsinstructions(Claude Code, Claude Desktop, ...) gets the gates/serial-only/pipeline rules automatically, with zero setup. tia_guide(topic)— a tool that returns the bundled guide chapters on demand:toc(default) |full|brief|gates-guards|gui-gates|gotchas|pipeline|recipes|spec-format. Call it with{"topic":"pipeline"}before the first build on a project, and{"topic":"gui-gates"}when a tool returnsrequires_human_actionor a compile error mentions a GUI-only setting.- Teaching errors on gate signals — gate responses (
requires_human_action, theguiGateHintson compile results, etc.) carry the relevant next steps inline, so the guide reinforces itself at the moment a gate is actually hit, not only up front.
tia_guide is pure and offline: it never calls the serve API and never returns isError —
unlike every other tool in this package, it works even with the serve down. The chapters are
generated from mcp/content/*.md (the canonical source) into src/content.gen.ts via
npm run sync — see scripts/sync-guide.mjs.
Tools
Diagnóstico + M1 read-only (classe R, auto-aprováveis)
| Tool | Endpoint | Descrição |
|---|---|---|
| tia_ping | GET /health + GET /readiness | Diagnostica conectividade e ATIVAÇÃO do serve. { base, reachable, activated, latencyMs, hint }. Ideal p/ Mac→VM. |
| tia_readiness | GET /readiness | Prontidão do ambiente no host do serve (x64, grupo Windows, PublicAPI, registro, instâncias). |
| tia_guide | — (bundled content, no HTTP call) | Returns the operating guide (see "Operating guide embedded" above). Topics: toc (default) | full | brief | gates-guards | gui-gates | gotchas | pipeline | recipes | spec-format. Pure/offline — works with the serve down. |
M1 (read-only, 1:1 com os GET da API): tia_instances, tia_status, tia_projects, tia_project_info,
tia_project_languages, tia_plcs, tia_devices, tia_device_tree, tia_device_connections,
tia_plc_blocks/types/tags/watchtables, tia_catalog, tia_connections_diagnose, tia_subnets,
tia_obj_roots/get/items/info/creationinfos/services. Nenhuma muta estado.
M2 — ciclo de vida (classe M-off) + GATE de confiança (G1)
| Tool | Endpoint | Descrição |
|---|---|---|
| tia_start | POST /tia/start | Inicia/anexa o TIA sem projeto (headless opcional). |
| tia_show_ui | POST /tia/show-ui | Relança o TIA headless como visível p/ renderizar o diálogo de confiança (habilita o G1). |
| tia_connect | POST /connect | Abre/anexa um projeto. Pode bloquear no GATE G1 → devolve um envelope requires_human_action (sem retry-storm) com resumeToken. UMAC (G6) só se um humano fornecer. |
| tia_disconnect | POST /disconnect | Desconecta (Gd3: use tia_project_close p/ liberar o lock). |
| tia_project_create | POST /project/create | Cria projeto (Gd4: diretório vazio → senão 409). |
| tia_project_save / tia_project_saveas / tia_project_close / tia_project_archive | POST /project/* | Ciclo de vida do projeto. |
GATE de confiança (G1): na 1ª conexão por processo serve, o TIA exige confirmação manual de um diálogo
de segurança NO HOST. O fluxo proativo é tia_start → tia_show_ui → (humano confirma) → tia_connect.
Se o tia_connect esbarra no diálogo, ele NÃO faz retry-storm: devolve { status:"requires_human_action",
gate:"trust_dialog", youMustDo, resumeToken }. Após o humano confirmar, re-chame tia_connect com o resumeToken.
M3 — criação/autoria offline (classe M-off) + guards
Superfície de criação compliant-by-construction (~28 tools), todas com dryRun (Gd11) e validação por schema (Gd13):
- Hardware/rede:
tia_device_create/plug/unplug,tia_device_group_create,tia_subnet_create,tia_network_connect/address/disconnect. - Tags/constantes:
tia_tagtable_create,tia_tag_create/delete,tia_constant_create. - Blocos/tipos:
tia_fb_create,tia_instancedb_create,tia_block_delete/set_attribute,tia_block_group_create,tia_type_group_create/type_delete. - Código:
tia_source_put(SCL textual — Gd6),tia_import_xml/tia_types_import(SimaticML gráfico — Gd6/Gd7),tia_export_xml. - Watch tables:
tia_watchtable_create/delete. - Camada genérica de escrita:
tia_obj_set_attributes/invoke/create.
Guards (client-side, antes de tocar o Openness): Gd5 — typeIdentifier deve usar /V<fw> (barra), nunca :V
(rejeitado com kind:"guard_violation"; resolva o valor via tia_catalog). Gd11 — dryRun:true valida os guards
e retorna o plano por nome SEM mutar (status:"plan_ok"). Gd6 (advisório) — linguagem textual (SCL) via
tia_source_put, gráfica (LAD/FBD/GRAPH) via tia_import_xml; UDTs antes dos blocos. Gd2 (advisório) — idempotência
por nome (cheque a existência com as tools read-only do M1 antes de criar; o Openness não tem rollback).
M4 — verificação + deploy GATED (hardware)
| Tool | Endpoint | Gate/classe |
|---|---|---|
| tia_compile | POST /plcs/{plc}/compile | M-off — o verificador. Achata a árvore de mensagens + verification:{compiled,errors,warnings} + nextHints (Gd8: só ERRO bloqueia). |
| tia_connection_create | POST /connections | M-off — conexão S7 (G2: exige ≥2 CPUs consistentes; falha anexa diagnóstico). |
| tia_download | POST /plcs/{plc}/download | GATE G3 — não baixa sem aprovação humana vinculada ao planHash. |
| tia_online / tia_offline / tia_online_state | POST /plcs/{plc}/online·/offline·GET …/state | G4 (online) / R (state). |
| tia_accessible_devices | POST /plcs/{plc}/online/accessibledevices | GATE G7 (net scan). |
| tia_mastersecret_set / tia_mastersecret_reset | …/online/mastersecret | GATE G6 (segredo vem do humano, nunca da IA). |
GATE de download (G3): tia_download NUNCA baixa sem aprovação. Fluxo: tia_compile (precondição Gd9: errors=0) →
tia_download dryRun:true (devolve plan + planHash, sem baixar) → um humano aprova → tia_download approved:true
com o mesmo planHash. Hash errado ou approved ausente → envelope requires_human_action / download_approval.
Limitação honesta: o serve ainda auto-confirma StopAll/Overwrite (backlog C# P0.5); até isso ser
re-externalizado, o "Load Preview" real não é exposto e o G3 é a salvaguarda da camada do MCP (não bypassável só por texto do LLM).
M5 — ingestão de project-spec (orquestra M1–M4)
Aceita o project-spec estruturado (docs/TIA-BEST-PRACTICES.md §13.2; JSON Schema em .claude-plugin/schemas/project-spec.schema.json):
tia_spec_validate(R, determinístico, sem serve): valida forma + regras de campo cruzado — R-NAMES (nomes únicos), R-TYPEID (OrderNumber:<MLFB>/V<fw>), R-SUBNET (IP∈CIDR, CPU+IO na mesma subnet, 1 IO-system), R-LANGFAM (STL/GRAPH só S7-1500), R-MODLIMIT, e G5 (safety.required && autonomous ⇒ REJECT).tia_spec_plan(sem serve): transforma um spec válido na sequência ordenada de operações (subnets→devices→módulos→rede→tags→blocos→compile).tia_spec_apply: orquestra o build OFFLINE num projeto aberto (valida → G5 → executa serial → compila), para no 1º erro e nunca baixa (download é o GATE G3, sempre humano).dryRun:truedevolve o plano.
MCP M0–M5 COMPLETO (76 tools), validado em runtime contra um TIA Portal V21 real (incluindo deploy em hardware num S7-1200) e publicado no npm. Roadmap e marcos em
docs/ROADMAP.md§3.
Configuração (env)
| Var | Default | Uso |
|---|---|---|
| TIA_API_BASE | http://localhost:5000 | Base URL da API serve. |
| TIA_API_TIMEOUT_MS | 15000 | Timeout por request (falha rápido se o host/VM não responde). |
O MCP não envia chave. A API é ativada por uma licença configurada na GUI (aba "Licença") — quem autoriza o servidor é a licença do host, não o cliente. O MCP é um cliente HTTP normal: só aponta a base.
Cenário Mac → VM Windows (apontar o servidor)
Na VM Windows, faça tudo pela GUI de bandeja (atalho "TIA Openness API"):
- aba "Licença" → cole a chave de ativação → "Validar" → "Salvar" (a API só aceita conexões externas se estiver ativada);
- aba "API" → Host =
0.0.0.0(aceita conexões de fora;localhostsó atende a própria VM), Porta =5000→ "Iniciar API". O status fica verde ("Rodando em http://0.0.0.0:5000/ …").
Libere a porta no firewall do Windows e garanta rede acessível (bridged ou NAT com port-forward). O controle de quem pode chamar é o firewall/VPN — a licença ativa o servidor, não autentica clientes.
.\bin\Debug\net48\TIAOpenness.exe serve 5000 --host 0.0.0.0 --license TIA1.xxxxx.yyyyyNo Mac, aponte o MCP para a VM:
export TIA_API_BASE="http://<ip-da-vm>:5000"Diagnostique com o tool
tia_ping:reachable:false→ IP/porta/firewall/VM;activated:false→ licença ausente/inválida na VM; ambostrue→ pronto.
Build / bundle
# garanta o Node (no Windows com nvm-windows: $env:Path = "C:\nvm4w\nodejs;" + $env:Path)
cd mcp
npm install
npm run build # typecheck + esbuild -> dist/index.js (self-contained)Instalação
A) Do npm público (uso normal, Mac/Windows/Linux)
Pacote público — sem auth, sem .npmrc. Use direto via npx ou instale o binário global:
npx -y @renanlido/tia-openness-mcp # roda sem instalar (recomendado p/ .mcp.json)
# ou instale o binário `tia-openness-mcp` no PATH:
npm install -g @renanlido/tia-openness-mcpB) Local, sem publicar (dev nesta máquina)
cd mcp
npm install -g . # o prepack compila e instala o binário
# ou: npm pack && npm install -g ./renanlido-tia-openness-mcp-*.tgzPublicação (npm público + semantic-release)
Versionamento automático por commits convencionais (feat → minor, fix → patch, BREAKING CHANGE
→ major). O workflow .github/workflows/release-mcp.yml dispara
no push para main quando algo em mcp/ muda (e semantic-release-monorepo filtra os commits por
esse path), builda e publica no npm público (registry.npmjs.org, publishConfig.access: public).
Usa dois tokens: NPM_TOKEN (secret a configurar — token Automation/Publish do npmjs.org) para o
publish via @semantic-release/npm, e o GITHUB_TOKEN nativo do Actions para criar a release/tag e
commitar o CHANGELOG.
Para ligar (passos com credencial, uma vez):
- Crie o repo no GitHub (
renanlido/TIAOpenness) — ou ajusterepository.url/scope nopackage.jsone o workflow se o owner for outro. - Configure o secret
NPM_TOKENno repositório (Settings → Secrets and variables → Actions): gere um token de Automation em npmjs.org com permissão de publish no pacote@renanlido/tia-openness-mcp. git add . && git commit -m "feat: initial commit"→git branch -M main→git remote add origin <url>→git push -u origin main.- A partir daí, commits convencionais na
maindisparam o release automaticamente.
Config validada localmente: versões dedupadas em
semantic-release@24; o dry-run carregou config/plugins e só parou por o repo remoto ainda não existir.
Registro no Claude Code
Não precisa instalar nada — o recomendado é o npx, que baixa e roda o pacote publicado. Um comando
só (escopo de usuário):
claude mcp add --transport stdio --env TIA_API_BASE=http://localhost:5000 --scope user tia -- npx -y @renanlido/tia-openness-mcpConfira com claude mcp list e claude mcp get tia. O equivalente por .mcp.json na raiz do projeto
(escopo de projeto) — também via npx, sem instalar:
{
"mcpServers": {
"tia": {
"command": "npx", // baixa e roda o pacote do npm — NADA instalado
"args": ["-y", "@renanlido/tia-openness-mcp"],
"env": {
"TIA_API_BASE": "${TIA_API_BASE:-http://localhost:5000}" // IP:porta do serve (use o IP da VM se remoto)
}
}
}
}
tia-openness-mcpNÃO é um arquivo do repositório — é o nome do bin do pacote (package.json→"bin": { "tia-openness-mcp": "dist/index.js" }). Esse atalho só fica no seu PATH se você instalar global (npm install -g @renanlido/tia-openness-mcp); só então faria sentido"command": "tia-openness-mcp", "args": []. Onpxdispensa esse passo — por isso é o recomendado.
Outros clientes (Claude Desktop, Codex, Gemini CLI, Cursor, VS Code, Windsurf): o guia canônico de
instalação — com os formatos exatos de cada um e a pegadinha do cmd /c npx no Windows — está em
docs/INSTALL.md no repositório.
Envs opcionais (default embutido no MCP — só defina para sobrescrever): TIA_API_TIMEOUT_MS (15000),
TIA_SLOW_TIMEOUT_MS (120000), TIA_CONNECT_TIMEOUT_MS (30000). Ex.: --env TIA_SLOW_TIMEOUT_MS=180000
no claude mcp add, ou a chave correspondente no env do .mcp.json.
Como é servidor de escopo de projeto, o Claude Code pede aprovação na 1ª vez: claude mcp list
(deve listar tia), rode claude no projeto e aprove, recarregue a sessão, e peça para chamar
tia_ping / tia_readiness.
Smoke test
npm run smoke # alvo = dist/index.js local
# apontar para o binário global:
MCP_COMMAND=tia-openness-mcp MCP_ARGS='[]' npm run smoke # (Windows: use o caminho do .cmd)Notas
- O MCP não envia chave/segredo. A API é ativada por licença no host (GUI). Segredos (master secret /
UMAC / senha de cert) nunca vão no
.mcp.json. - Serial-only: o backend é um worker serial; o MCP nunca deve paralelizar tool calls (Gd1).
- stdout é do protocolo MCP — logs vão para stderr.
- O bundle é gerado por scripts/build.mjs (esbuild, ESM, shebang +
createRequire, versão injetada).dist/,node_modules/,*.tgzsão artefatos (gitignored). - Ao adicionar/alterar tools, rebuild + reinstalar o binário (
npm run build && npm i -g .) para a instalação local refletir; em produção, o push paramainrepublica.
