[2026-05-10] obsidian-mcp-wrapper: large payload fix + watchdog + MAX_RETRY=10
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# obsidian-mcp-wrapper
|
# obsidian-mcp-wrapper
|
||||||
|
|
||||||
> **Файл**: `~/scripts/obsidian-mcp-wrapper.js`
|
> **Файл**: `~/scripts/obsidian-mcp-wrapper.js`
|
||||||
> **Назначение**: прокси-обёртка над `obsidian-mcp`, решает два системных бага
|
> **Назначение**: прокси-обёртка над `obsidian-mcp`, решает четыре системных бага
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -25,13 +25,35 @@
|
|||||||
**Fix**: wrapper буферизует все tool-вызовы до завершения handshake
|
**Fix**: wrapper буферизует все tool-вызовы до завершения handshake
|
||||||
(`initialize` → ответ → `notifications/initialized`), потом флашит очередь.
|
(`initialize` → ответ → `notifications/initialized`), потом флашит очередь.
|
||||||
|
|
||||||
|
### 3. Corrupted large payloads (UTF-8 chunk split)
|
||||||
|
|
||||||
|
При больших tool-вызовах (~200KB+) Node.js доставляет stdin в нескольких chunk-ах.
|
||||||
|
Старый код делал string split — JSON разрезался по байтам → UTF-8 multibyte символы
|
||||||
|
портились, `JSON.parse` падал, сообщение дропалось молча.
|
||||||
|
|
||||||
|
**Симптом**: `edit_note` с большим контентом тихо зависал (30s timeout), в логах:
|
||||||
|
```
|
||||||
|
[obsidian-wrapper] Non-JSON from Hermes (forwarding verbatim): {"jsonrpc": "2.0", "method": "tools/call", "id": 3, "params": {"name": "edit-not
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix**: stdin и stdout читаются через `Buffer.concat` + `Buffer.slice` на `0x0a`.
|
||||||
|
Строка собирается полностью до передачи в `JSON.parse`.
|
||||||
|
|
||||||
|
### 4. Per-call watchdog (зависший child)
|
||||||
|
|
||||||
|
Если child не ответил на `tools/call` / `tools/list` / `resources/*` за **5s** —
|
||||||
|
watchdog убивает процесс. После авторестарта call автоматически уходит в голову
|
||||||
|
очереди и ретраится.
|
||||||
|
|
||||||
|
**Fix**: `armWatchdog(callLine)` → `setTimeout 5000ms` → `child.kill()` → `startChild()`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Как работает
|
## Как работает
|
||||||
|
|
||||||
```
|
```
|
||||||
Hermes (stdin) → wrapper → obsidian-mcp (child)
|
Hermes (stdin) → wrapper → obsidian-mcp (child)
|
||||||
↑ auto-restart при краше (до 5 раз)
|
↑ auto-restart при краше (до 10 раз)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Состояния**:
|
**Состояния**:
|
||||||
@@ -45,12 +67,16 @@ Hermes (stdin) → wrapper → obsidian-mcp (child)
|
|||||||
4. Отправляет `notifications/initialized` (не форвардит Hermes — он не просил)
|
4. Отправляет `notifications/initialized` (не форвардит Hermes — он не просил)
|
||||||
5. `ready = true` → флаш очереди
|
5. `ready = true` → флаш очереди
|
||||||
|
|
||||||
|
**Shutdown**:
|
||||||
|
На stdin EOF (`Hermes` закрыл процесс) — child убивается без авторестарта, wrapper выходит чисто.
|
||||||
|
|
||||||
**Логи** (все в stderr с timestamp):
|
**Логи** (все в stderr с timestamp):
|
||||||
```
|
```
|
||||||
[obsidian-wrapper] 2026-05-09T12:00:00.000Z Spawning obsidian-mcp (vault=/Users/admin/obsidian)
|
[obsidian-wrapper] 2026-05-09T12:00:00.000Z Spawning obsidian-mcp (vault=/Users/admin/obsidian)
|
||||||
[obsidian-wrapper] 2026-05-09T12:00:00.500Z Hermes → child (handshake complete): notifications/initialized
|
[obsidian-wrapper] 2026-05-09T12:00:00.500Z Hermes → child (handshake complete): notifications/initialized
|
||||||
[obsidian-wrapper] 2026-05-09T12:00:00.501Z Child ready — flushing queue (3 items)
|
[obsidian-wrapper] 2026-05-09T12:00:00.501Z Child ready — flushing queue (3 items)
|
||||||
[obsidian-wrapper] 2026-05-09T12:00:01.200Z Stripped id:null from notification: notifications/initialized
|
[obsidian-wrapper] 2026-05-09T12:00:01.200Z Stripped id:null from notification: notifications/initialized
|
||||||
|
[obsidian-wrapper] 2026-05-09T12:00:06.000Z WATCHDOG: child did not respond in 5000ms for tools/call #7 — killing and restarting
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -72,11 +98,17 @@ Wrapper сам вызывает `/opt/homebrew/bin/obsidian-mcp /Users/admin/obs
|
|||||||
|
|
||||||
- Инициализация: ~587ms (без ZodError)
|
- Инициализация: ~587ms (без ZodError)
|
||||||
- Overhead wrapper: negligible (pure Node.js child_process, нет npm-зависимостей)
|
- Overhead wrapper: negligible (pure Node.js child_process, нет npm-зависимостей)
|
||||||
|
- MAX_RETRY: 10
|
||||||
|
- CALL_TIMEOUT_MS: 5000ms (watchdog)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## История
|
## История
|
||||||
|
|
||||||
**2026-05-09** — создан после диагностики 58 ошибок `obsidian/... call failed` в логах Hermes.
|
**2026-05-09 (1)** — создан после диагностики 58 ошибок `obsidian/... call failed` в логах Hermes.
|
||||||
Корневая причина — ZodError + race condition при старте. Wrapper написан вместо патча
|
Корневая причина — ZodError + race condition при старте. Wrapper написан вместо патча
|
||||||
исходников obsidian-mcp (патч не нужен, wrapper чище и не ломается при обновлении пакета).
|
исходников obsidian-mcp (патч не нужен, wrapper чище и не ломается при обновлении пакета).
|
||||||
|
|
||||||
|
**2026-05-09 (2)** — фикс large payload: Buffer-based line splitting вместо string split
|
||||||
|
(`edit_note` с большим контентом молча дропался). Добавлен per-call watchdog (5s timeout → kill & retry).
|
||||||
|
MAX_RETRY повышен с 5 до 10.
|
||||||
|
|||||||
Reference in New Issue
Block a user