---
tags: [note, MCP]
type: "note"
nature: documentation
ressource: true
univers: PERSO
projects:
  - "[[03_PROJETS/VPS-IA]]"
date: "[[01_JOURNAL/2026/2026-10-08]]"
description: "Runtime API en 503 : le sandbox systemd tuait Chromium ; drop-in systemd assoupli."
---

# IA OpenCode — MCP SilverBullet : résolution du problème Chromium / Runtime API

## Contexte

Objectif : connecter l'espace SilverBullet (shizendo) à OpenCode via MCP pour que l'agent puisse lire/écrire les notes et utiliser les outils du plug AI.

SilverBullet ne fournit **pas de serveur MCP intégré** (pas d'endpoint `/mcp` ni `/.mcp`). Deux ponts MCP sont utilisables :
- `silverbullet-mcp` : pont direct sur l'API `/.fs` (léger, 6 outils).
- `silverbullet-ai-mcp` : pont officiel du plug AI (11 outils), **nécessite la Runtime API** (Chrome headless).

## Problème

La Runtime API renvoyait systématiquement :
```
503 {"error":"runtime not ready","code":"bridge_unavailable"}
```
Les logs du service montraient que Chrome se lançait puis **mourait ~5 s après** :
```
INFO  launching isolated headless Chrome (/usr/bin/chromium)
WARN  headless page for http://127.0.0.1:3000/shizendo failed to start: new page: oneshot canceled; retrying in 120s
```

## Diagnostic

1. **Endpoints MCP** : `/mcp`, `/.mcp` → 404. SilverBullet n'expose rien.
2. **Espace multi-espaces** : la racine renvoie « No space here » → l'URL doit inclure le préfixe d'espace : `http://127.0.0.1:3000/shizendo`.
3. **Auth** : `/.fs` sans token → 401 ; avec token `sbt_...` → 200.
4. **Runtime API** : `/.runtime/lua` → 503 `bridge_unavailable`.
5. **Chromium** : installé (`/usr/bin/chromium` → `/usr/lib/chromium/chromium` v154) et **fonctionne** en headless hors sandbox.
6. **Sandbox systemd** : le service YunoHost tourne avec un durcissement très restrictif (`SystemCallFilter`, `NoNewPrivileges`, `PrivateTmp`, `PrivateDevices`, `RestrictNamespaces`, `LockPersonality`, `ProtectProc=invisible`…). C'est lui qui tue Chrome.
7. **Bisection** : désactivation complète du sandbox → Runtime API OK ; réactivation partielle (durcissement lecture seule) → toujours OK.

## Solution

Drop-in systemd qui **assouplit uniquement les réglages bloquants** pour Chrome, en conservant le durcissement « lecture seule » :

```ini
# /etc/systemd/system/silverbullet.service.d/runtime.conf
[Service]
ProtectSystem=full          # réactivé (sûr)
ProtectKernelTunables=yes   # réactivé
ProtectKernelModules=yes    # réactivé
ProtectControlGroups=yes    # réactivé
ProtectHostname=yes         # réactivé
ProtectClock=yes            # réactivé
PrivateTmp=no               # assoupli (bloquait Chrome)
PrivateDevices=no           # assoupli
RestrictNamespaces=no       # assoupli
NoNewPrivileges=no          # assoupli
LockPersonality=no          # assoupli
SystemCallFilter=           # assoupli
```

⚠️ **Le redémarrage du service est obligatoire** après chaque modification du drop-in (`systemctl daemon-reload` + `systemctl restart silverbullet`). Vérifier avec `systemctl show silverbullet -p ExecMainStartTimestamp` (doit afficher l'heure courante).

## Commandes mises en œuvre

### Vérifier les endpoints
```bash
T="sbt_..."
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3000/mcp        # 404
curl -s -H "Authorization: Bearer $T" http://127.0.0.1:3000/shizendo/.fs/  # 200
```

### Tester la Runtime API
```bash
curl -s -X POST -H "Authorization: Bearer $T" -H "X-Timeout: 90" \
  -d '1 + 1' http://127.0.0.1:3000/shizendo/.runtime/lua
# => {"result":2}  (premier boot Chrome : 30-60 s)
```

### Lire les logs du service
```bash
sudo journalctl -u silverbullet --since "1 hour ago" | grep -iE "runtime|chrome|headless"
```

### Appliquer le drop-in
```bash
sudo tee /etc/systemd/system/silverbullet.service.d/runtime.conf <<'EOF'
[Service]
ProtectSystem=full
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
ProtectHostname=yes
ProtectClock=yes
PrivateTmp=no
PrivateDevices=no
RestrictNamespaces=no
NoNewPrivileges=no
LockPersonality=no
SystemCallFilter=
EOF
sudo systemctl daemon-reload
sudo systemctl restart silverbullet
systemctl show silverbullet -p ExecMainStartTimestamp   # doit être ≈ maintenant
```

### Ajouter le MCP dans OpenCode
```bash
opencode mcp add silverbullet-ai --global \
  --env SB_URL=http://127.0.0.1:3000/shizendo \
  --env SB_AUTH_TOKEN=sbt_... \
  -- npx -y silverbullet-ai-mcp
opencode mcp list   # ✓ silverbullet-ai connected
```

### Sécuriser les configs (tokens en clair)
```bash
chmod 600 ~/.config/opencode/opencode.json
chmod 600 ~/opencode.json
```

## État final

- ✅ Runtime API fonctionnelle (Chrome headless démarre).
- ✅ MCP `silverbullet-ai` connecté dans OpenCode (11 outils : read_note, list_pages, create_note, update_note, search_replace, rename_note, update_frontmatter, view_file, get_page_info, eval_lua, refresh_tools).
- ➖ MCP `silverbullet` (pont `/.fs`) retiré : redondant avec `silverbullet-ai` (seuls `delete_note` et `search_notes` manquent).
- 🔒 Configs OpenCode en `chmod 600`.

## Points d'attention

- **Mise à jour YunoHost** : le drop-in `/etc/systemd/system/silverbullet.service.d/runtime.conf` sera probablement écrasé → à recréer (garder une copie).
- **Écritures sans confirmation** : les outils d'écriture du plug AI passent par la Runtime API sans modal d'approbation.
- **Ressources** : un Chrome headless par utilisateur/espace actif (~300 Mo de RAM).
- **Tokens** : stockés en clair dans les configs OpenCode (protégés en 600).
- **RAG** : pas d'outil MCP dédié ; la recherche s'approche via `eval_lua` (requêtes SLIQ) + `read_note`.
