Files
claude-skills/dist-hermes/mcp/using-synology-ops/SKILL.md
vitya 02db589034 feat(skills): using-synology-ops 0.1.1→0.1.2 — fill body
Filled all sections from source docs:
- ~/projects/.workshop/.archive/2026-05-12-using-synology-ops-skill.md
- ~/projects/.wiki/concepts/synology-ops-mcp-design.md

Sections: When to use (triggers), Inputs, Steps (4 flows),
Failure modes, Side effects, What NOT to do (mistakes + red flags).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 20:39:48 +03:00

80 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: using-synology-ops
version: 0.1.2
description: Use when diagnosing docker containers on the Synology NAS — the `synology-ops` HTTP MCP server (https://opsmcp.kzntsv.site/mcp) exposes 4 read-only tools — `ops.docker.ps`, `ops.docker.logs`, `ops.docker.inspect`, `ops.docker.stats` — all routed through tecnativa `synology-docker-proxy-ro` with `POST=0` (write-ops return 403). Triggers on container names (`modulair-rag`, `modulair-pipeline`, `lightrag-modulair`, `tier1-converter`, `modulair-mcp`, `synology-ops-mcp`), on NAS-domain words ("на NAS", "Synology", "синолоджи", "Portainer-стек", "ops-mcp", "опс мсп", "opsmcp.kzntsv.site"), or on incident phrases ("падает", "restart-loop", "не стартует", "unhealthy", "посмотри логи") when NAS-context. Read-only by design — no per-session grant needed. Skip for non-incident mentions, "open Portainer GUI" requests, write-ops, and incident phrases on non-NAS hosts (`books-pipeline`, `vps-*` etc. — only the 6 listed above are NAS-hosted).
---
# using-synology-ops
Trigger-and-guidance skill для `synology-ops-mcp` — read-only HTTP MCP-сервера на NAS, дающего Claude'у видимость состояния docker-контейнеров без юзера-моста (без Portainer copy-paste).
## When to use
**Trigger — любой из трёх сигналов:**
1. **Контейнерные имена** (явный NAS-signal):
- `modulair-rag`, `modulair-pipeline`, `lightrag-modulair`, `tier1-converter`, `modulair-mcp`, `synology-ops-mcp`, `synology-docker-proxy-ro`
2. **Доменные слова Synology:**
- «на NAS», «Synology», «синолоджи», «Portainer-стек», «opsmcp.kzntsv.site», «ops-mcp», «опс мсп», «synology-ops»
3. **Инцидент-фразы** (в NAS-контексте):
- «падает», «restart-loop», «не стартует», «unhealthy», «медленно грузится», «не видит соседа», «посмотри логи», «что с контейнером X»
**Skip:** упоминание в неинцидент-контексте («modulair-rag deploy запланирован на завтра»), явный отказ («открой Portainer GUI»), инцидент-фразы для non-NAS хостов (`books-pipeline`, `vps-*` и т.д.).
## Inputs
- **Имя контейнера** (если есть) — для скоупинга `logs`/`inspect`/`stats`
- **Симптом** — «падает», «медленно грузится», «не видит соседа» — определяет starting tool
- **Scope** — «один контейнер» vs «весь стек» vs «все на NAS»
## Steps
**Флекс-паттерны — рекомендации, не жёсткий чек-лист.**
| Сценарий | Старт-тап | Последовательность |
|----------|-----------|-------------------|
| «Контейнер X падает» | `ops.docker.ps({ name: "X", state: "all" })` → видит restart count | `logs({ name: "X", tail: 200, stream: "both" })` → если dependency error → `ps({ name: "<dep>" })` → если нет соседа → `inspect({ name: "X" })` |
| «Проверь стек целиком» | `ops.docker.ps({ state: "all" })` | Группировка по stack labels → если problem видны сразу — diagnosis, иначе → ask user |
| «Медленно грузится» | `ops.docker.stats({ name: "X" })` | Если CPU/Mem OK → `logs({ name: "X", since: "5m" })` на стартап-фазу |
| «Не видит соседа в сети» | `ops.docker.inspect({ name: "X" })` | Достать `NetworkSettings.Networks` → сверить с `inspect` соседа |
**Формат отдачи юзеру:**
1. **Диагноз** — одна строка («`modulair-pipeline` в restart-loop, ECONNREFUSED `postgres:5432`, контейнера `postgres` в сети `modulair` нет»)
2. **Evidence** — 3-5 строк (релевантные логи / env / networks), hard cap 15 строк
3. **Гипотеза следующего шага** — 1-2 строки
Юзер просит «покажи всё» → отдать всё, дефолт — выжимка.
## Failure modes
| Сценарий | Симптом | Действие |
|----------|---------|----------|
| Контейнер не существует | `ops.docker.logs` error «container not found» | Подсказать доступные: `ps({ state: "all" })` → список |
| Docker proxy недоступен | Timeout / connection refused | «synology-docker-proxy-ro unreachable — check stack health в Portainer» |
| 403 от docker-proxy | Попытка write-op (implicit) | «operation forbidden by tecnativa ACL — это read-only proxy, используй Portainer GUI для restart/exec» |
| Output > 1MB | Логи обрезаны | Вернуть первый MB + `truncated: true, actualBytes: N` |
| Bearer token невалидный | 401 на любой вызов | «check `~/.claude.json``mcpServers.synology-ops.headers.Authorization` соответствует ли токену в Portainer stack env» |
## Side effects
- **Latency** — HTTPS round-trip к NAS ~200ms, batch'ить вопросы, не дёргать в цикле
- **Capping** — `logs` cap 1MB, `tail` max 5000 строк — если нужно больше, ask
- **Маскирование** — env-vars с именами `/PASSWORD|TOKEN|SECRET|KEY|PASS|CREDS/i` заменены на `***` в `inspect` — regex может пропустить кастомные ключи, warning не certainty
## What NOT to do
**Common mistakes:**
- ❌ Звонить `logs` без явного `tail` (default 200, но явный = намеренный)
- ❌ Звонить `logs` для всех контейнеров подряд («покажи всё» — сначала `ps`)
- ❌ Интерпретировать `***` в env как «вижу пароль» — это masked, может быть кастомный ключ
- ❌ Пытаться write-ops (restart/exec/prune) через MCP — 403, направлять юзера в Portainer GUI
- ❌ Кэшировать `ps` long-term — состояние NAS меняется, перезвонить
**Red flags:**
- 🔴 Дёргать в цикле — latency ~200ms через HTTPS, собрать вопросы в один batch
- 🔴 Проверять non-NAS контейнеры этим MCP (`books-pipeline`, `vps-*`) — они не видны synology-ops-mcp
- 🔴 Env-masked regex — не гарантия, могут быть кастомные ключи (`DB_URI`, `API_CREDENTIALS` и т.п.)