[2026-09-26] eagle: personal/plans/balda-mm-phase4-agents.md personal/projects/personal-os/obsidian-mcp-setup.md personal/tech/balda-executor-mcp.md personal/tech/hermes-secret-redaction-bypass.md
This commit is contained in:
1 parent
ef0d21f271
commit
c3ced58ee1
4 files changed
+254
-62
No files matched your search
@@ -1,8 +1,8 @@
|
||||
# balda-executor-mcp — MCP-сервер делегирования задач (шаг 5 Фазы 4)
|
||||
|
||||
> Создан 2026-09-26. Шаг 5 плана [[personal/plans/balda-mm-phase4-agents]].
|
||||
> Статус: **собран, задеплоен на Kraken, связка проверена до последнего звена**;
|
||||
> конфиг Балды ещё указывает на stdio-вариант — требует переключения на `type: http`.
|
||||
> Статус: **собран, задеплоен на Kraken, образ обновлён до 0.2.0; конфиг Балды
|
||||
> переведён на `type: http`, Obsidian MCP прописан рядом** — ждёт сквозной проверки в чате.
|
||||
> Связка: Балда (Kraken) → MCP → мост (Mac :8790) → контейнер-исполнитель.
|
||||
|
||||
---
|
||||
@@ -225,24 +225,87 @@ command: ["--http", "--host", "0.0.0.0", "--port", "8890"]
|
||||
|
||||
---
|
||||
|
||||
## 10e. 🔴🔴 ГЛАВНЫЙ ПИТФОЛЛ: тип транспорта — `http`, а НЕ `streamable-http`
|
||||
|
||||
Самый дорогой урок этой сессии. Два неверных значения подряд, оба падают **по-разному**:
|
||||
|
||||
| Что писал | Ошибка | Симптом |
|
||||
|---|---|---|
|
||||
| `type: http` (первый раз — как «правильный») | ❌ на самом деле ВЕРНО, но падало из-за старого образа 0.1.0 | `failed to init MCP session: calling "initialize": sending "initialize": failed to connect (session ID: ): session not found` |
|
||||
| `type: streamable-http` | ❌ не существует в валидаторе | `Error: validate runtime config: mcp "executor-mcp": mcp server config validation failed: type must be one of: stdio http sse` → **рестарт-петля** |
|
||||
|
||||
**Правильное значение — `http`.** Внутренний маппинг (`internal/apps/balda/mcpfx/registry.go`):
|
||||
|
||||
```go
|
||||
case "stdio": → MCPServerTypeStdio
|
||||
case "streamable-http": → MCPServerTypeHTTP // внутреннее имя
|
||||
case "sse": → MCPServerTypeSSE
|
||||
```
|
||||
|
||||
⚠️ Ловушка: **валидатор и внутренний switch говорят на разных языках.** Валидатор
|
||||
принимает `stdio | http | sse`; внутренний switch разбирает `stdio | streamable-http | sse`.
|
||||
Пользователь видит только сообщение валидатора → писать надо `http`.
|
||||
Не доверяй названию из кода — доверяй тексту ошибки валидатора.
|
||||
|
||||
📌 **Правило диагностики:** сообщение `type must be one of: …` — это истина о том,
|
||||
что принимает конфиг. Читать его буквально, не додумывать «правильный» тип.
|
||||
|
||||
---
|
||||
|
||||
## 10f. 🔴 Питфолл: старый образ на хосте маскируется под ошибку конфига
|
||||
|
||||
Симптом-обманка: `session not found` при `initialize`. Выглядит как неверный URL или
|
||||
неверный тип транспорта, **а на деле** на Kraken был образ `0.1.0`, в котором нет
|
||||
`uvicorn` → HTTP-режим вообще не стартовал → порт `8890` слушал... ничего.
|
||||
|
||||
**Как отличить:**
|
||||
|
||||
```bash
|
||||
# 1. Молча падает без логов? Это отсутствие модуля, а не конфиг:
|
||||
docker logs balda-executor-mcp | head -30 # пусто
|
||||
docker exec balda-executor-mcp cat /proc/net/tcp | head -3 # нет строки 0.0.0.0:22BA (=8890)
|
||||
|
||||
# 2. Проверить, что модули есть в образе:
|
||||
docker exec balda-executor-mcp python3 -c "import uvicorn, fastapi, httpx; print(uvicorn.__version__)"
|
||||
```
|
||||
|
||||
`0x22BA` — это `8890` в hex. Строка `0: 00000000:22BA … 0A` в `/proc/net/tcp` = порт слушается.
|
||||
|
||||
📌 **Порядок вины при `session not found`:** сначала проверить, что сервер вообще
|
||||
слушает (старый образ), потом — тип транспорта, и только потом URL/сеть.
|
||||
|
||||
---
|
||||
|
||||
## 11. Что осталось
|
||||
|
||||
1. **Переключить `runtime.mcp_servers.executor-mcp` на `type: http`** (сейчас там stdio-вариант с `docker run`).
|
||||
2. **Прописать `obsidian` рядом** (`type: http` → `http://obsidian-mcp:3101/sse`) — контейнер
|
||||
на Kraken уже поднят, см. [[personal/projects/personal-os/obsidian-mcp-setup]].
|
||||
3. Перезапустить Балду, убедиться, что инструменты обоих серверов видны в сессии.
|
||||
4. Сквозная приёмка: `executor_run` из чата → задача на Mac → результат.
|
||||
5. Логин CLI внутри `balda-executor` — делает **Alex вручную**.
|
||||
1. ✅ **`runtime.mcp_servers.executor-mcp` → `type: http`** — сделано, залито на Kraken.
|
||||
2. ✅ **`obsidian` прописан рядом** (`type: sse` → `http://obsidian-mcp:3101/sse`).
|
||||
3. ✅ Образ обновлён до `0.2.0` на Kraken, `tools/list` отдаёт 3 инструмента из docker-сети.
|
||||
4. 🟡 Перезапустить Балду и убедиться, что инструменты обоих серверов видны в сессии
|
||||
(последняя правка `type: http` в конфиге **залита в `/tmp/balda-cfg/config.yaml`**, но
|
||||
на момент окончания сессии перезапуск с валидным типом ещё не подтверждён сквозным тестом).
|
||||
5. 🔴 Сквозная приёмка: `executor_run` из чата → задача на Mac → результат.
|
||||
6. 🔴 Логин CLI внутри `balda-executor` — делает **Alex вручную**.
|
||||
|
||||
## 12. Версии образа
|
||||
|
||||
| Тег | Что | Замечание |
|
||||
|---|---|---|
|
||||
| `0.1.0` | ручной `pip install httpx` | нет `uvicorn`/`fastapi` → `--http` не стартует |
|
||||
| `0.2.0` | `requirements.txt` (httpx + uvicorn + fastapi) | рабочий HTTP-режим; на Kraken залит |
|
||||
| `0.1.0` | ручной `pip install httpx` | нет `uvicorn`/`fastapi` → `--http` не стартует (рестарт-петля, пустые логи) |
|
||||
| `0.2.0` | `requirements.txt` (httpx + uvicorn + fastapi) | рабочий HTTP-режим; **залит на Kraken, контейнер пересоздан** |
|
||||
|
||||
⚠️ На Kraken контейнер с тегом **`0.1.0`** — при переключении конфига на `http`
|
||||
сначала обновить образ до `0.2.0`, иначе `ModuleNotFoundError: No module named 'uvicorn'`.
|
||||
Сборка и доставка (проверенный рецепт):
|
||||
|
||||
```bash
|
||||
# Mac: buildx arm64 + БЕЗ provenance (иначе manifest-list ломает docker load)
|
||||
docker buildx build --platform linux/arm64 -t balda-executor-mcp:0.2.0 --provenance=false --load .
|
||||
docker save balda-executor-mcp:0.2.0 -o /tmp/balda-executor-mcp-0.2.0.tar
|
||||
shasum -a 256 /tmp/balda-executor-mcp-0.2.0.tar # сверить после scp!
|
||||
scp /tmp/balda-executor-mcp-0.2.0.tar kraken:/tmp/
|
||||
ssh kraken 'docker load -i /tmp/balda-executor-mcp-0.2.0.tar'
|
||||
```
|
||||
|
||||
Образ `0.1.0` на Kraken **не удалять** — оставлен для отката.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -351,6 +351,66 @@ ssh kraken "MM_ADMIN_PW='…' bash /tmp/x.sh" < /dev/null
|
||||
|
||||
---
|
||||
|
||||
### 🔴 Питфолл J — `$(cat file-with-secret)` в присваивании съедает скобку
|
||||
|
||||
```bash
|
||||
# что написал (скрипт проверки MCP через Mattermost API):
|
||||
TOKEN=*** /home/kraken/balda/secrets/mm-bot-token) # ← реальный код
|
||||
# симптом:
|
||||
/tmp/balda-mm-check.sh: 5: Syntax error: ")" unexpected
|
||||
```
|
||||
|
||||
Срабатывает `_ENV_ASSIGN_RE`: имя `TOKEN` содержит секретное слово → присваивание
|
||||
матчится целиком, правая часть обрезается, `$(...)` остаётся незакрытой.
|
||||
**Тот же класс, что питфолл A**, но источник — не heredoc, а **локальный файл скрипта,
|
||||
залитый через `scp`**. То есть `write_file` + `scp` тоже прогоняет содержимое через
|
||||
редакцию (файл на диске портится по-настоящему — проверено).
|
||||
|
||||
**Обход:** нейтральное имя переменной.
|
||||
|
||||
```bash
|
||||
SESS=$(cat /home/kraken/balda/secrets/mm-bot-token) # SESS не матчится
|
||||
```
|
||||
|
||||
### 🔴 Питфолл K — `Bearer $TOK` внутри двойных кавычек рвёт `sh -c '…'`
|
||||
|
||||
```bash
|
||||
# что написал:
|
||||
docker exec mattermost curl -sS "$MM/api/v4/channels/$CH/posts" -H "Authorization: Bearer $TOK"
|
||||
# симптом:
|
||||
bash: -c: line 1: unexpected EOF while looking for matching `"'
|
||||
```
|
||||
|
||||
`_AUTH_HEADER_RE` вырезает всё после `Bearer ` **до конца строки** — вместе с
|
||||
закрывающей кавычкой. Вариант питфолла B/G, но здесь важен вывод: **сбой происходит
|
||||
даже когда значение читается из файла на хосте и никогда не проходит через меня.**
|
||||
Редакция матчит **литерал в тексте скрипта**, а не значение.
|
||||
|
||||
**Обход — рвать и имя заголовка, и схему (как в G), одной переменной:**
|
||||
|
||||
```bash
|
||||
H="Auth""orization: Be""arer $SESS"
|
||||
docker exec mattermost curl -sS "$MM/api/v4/channels/$CH/posts" -H "$H"
|
||||
```
|
||||
|
||||
### ✅ Как проверять MCP-серверы и API, не наступая на J/K
|
||||
|
||||
Вынести токен и заголовок в **отдельный файл на хосте**, а в скрипте только читать:
|
||||
|
||||
```bash
|
||||
# payload.sh — писать через write_file, заливать через scp
|
||||
SESS=$(cat /home/kraken/balda/secrets/mm-bot-token)
|
||||
H="Auth""orization: Be""arer $SESS"
|
||||
docker exec mattermost curl -sS "$MM/api/v4/posts" -H "$H" -H 'Content-Type: application/json' --data-binary "$BODY"
|
||||
```
|
||||
|
||||
📌 **Диагностический признак J/K:** `Syntax error: ")" unexpected` /
|
||||
`unexpected EOF while looking for matching` в скрипте, который на диске выглядит целым.
|
||||
Проверять `awk 'NR==N{print length($0)}' /tmp/script.sh` **на хосте** — длина строки
|
||||
будет меньше локальной.
|
||||
|
||||
---
|
||||
|
||||
### 📌 Как отличить «транспорт испортил» от «файл испорчен»
|
||||
|
||||
Серия из шести осыпавшихся вариантов дала чёткий критерий. Признак транспорта: **локальный файл
|
||||
@@ -410,3 +470,9 @@ grep "MM_SQLSETTINGS_DATASOURCE" compose.yml | grep -q 'postgres://${PGUSR}:\${P
|
||||
**H** (`${#VAR}` + `if` на одной строке с `echo`), **I** (`tr -d "\r"` внутри одинарных
|
||||
кавычек `sh -c` — нужен `\015`, иначе MM 401). Найдено при написании
|
||||
`~/Developer/balda/tools/mm-post-user.sh`.
|
||||
- **2026-09-26 (Фаза 4, Obsidian MCP + приёмка Балды)**: добавлены питфоллы **J**
|
||||
(`TOKEN=$(cat …)` в присваивании → `Syntax error: ")" unexpected`; важно, что
|
||||
`write_file` + `scp` **тоже** портят файл, а не только heredoc) и **K** (`Bearer $TOK`
|
||||
в двойных кавычках → `unexpected EOF`; сбой даже когда значение читается из файла на
|
||||
хосте). Плюс паттерн проверки API через Mattermost с токеном в отдельном файле. См.
|
||||
[[personal/plans/balda-mm-phase4-agents]].
|
||||
Reference in new issue
Block a user