Backup automatico script del 2026-08-23 12:04
This commit is contained in:
1 parent
11823447a2
commit
795a15a7b6
66 files changed
+8546
No files matched your search
@@ -0,0 +1,297 @@
|
||||
# Loogle MCP Hub — Architettura e parametri
|
||||
|
||||
Documento di riferimento per la piattaforma MCP domestica LOOGLE.IT.
|
||||
Ultimo aggiornamento: 2026-08-22
|
||||
|
||||
---
|
||||
|
||||
## Scopo
|
||||
|
||||
**Loogle MCP Hub** espone agli assistenti AI (Claude, ChatGPT, Gemini, Cursor) due capacità principali:
|
||||
|
||||
1. **Archivio contesto** — memoria persistente per progetti e task, isolata per utente
|
||||
2. **Knowledge base RAG** — ricerca semantica su documenti Paperless e sui contesti salvati
|
||||
|
||||
Tutti i dati restano in LAN/NAS; l’accesso esterno avviene solo via HTTPS + OAuth.
|
||||
|
||||
---
|
||||
|
||||
## Architettura logica
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Client AI (ChatGPT / Claude / Gemini / Cursor) │
|
||||
└───────────────────────────┬─────────────────────────────────┘
|
||||
│ HTTPS + OAuth Bearer
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ NPM VIP 192.168.128.85 → mcp.loogle.it:443 │
|
||||
└───────────────────────────┬─────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Pi-1 :8700 loogle-mcp (FastAPI) │
|
||||
│ ├── /mcp JSON-RPC MCP │
|
||||
│ ├── /oauth/* OAuth 2.1 PKCE │
|
||||
│ └── /dashboard UI famiglia │
|
||||
│ Pi-1 :8700 loogle-mcp-indexer (worker Paperless→vector) │
|
||||
└───────┬─────────────────────────────┬───────────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────────────┐ ┌─────────────────────┐
|
||||
│ SQLite │ │ Vector store │
|
||||
│ /data/*.db │ │ Qdrant DS920 :6333 │
|
||||
│ utenti OAuth │ │ o fallback SQLite │
|
||||
└───────────────┘ └─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ NFS /mnt/ha-apps/mcp/context/{utente}/projects/... │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Paperless docs.loogle.it (sorgente documenti + OCR) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Componenti e percorsi
|
||||
|
||||
| Componente | Host | Porta | Percorso / container |
|
||||
|------------|------|-------|----------------------|
|
||||
| MCP Gateway | Pi-1 | 8700 | `loogle-mcp` |
|
||||
| Indexer | Pi-1 | — | `loogle-mcp-indexer` |
|
||||
| Qdrant (primario) | DS920 | 6333 | opzionale, compose extrema |
|
||||
| Vector fallback | Pi-1 | — | `/data/vector_fallback.db` |
|
||||
| Context NFS | NAS | — | `/mnt/ha-apps/mcp/context/` |
|
||||
| DB SQLite | Pi-1 | — | `/home/daniely/docker/loogle-mcp/data/loogle_mcp.db` |
|
||||
| Compose locale | Pi-1 | — | `/home/daniely/docker/loogle-mcp/` |
|
||||
| Compose failover | Pi-1/Pi-2 | — | `/home/daniely/rete/compose/failover/loogle-mcp-compose.yml` |
|
||||
| Runbook | — | — | `/home/daniely/rete/ha/RUNBOOK-mcp.md` |
|
||||
|
||||
---
|
||||
|
||||
## URL e endpoint
|
||||
|
||||
| Servizio | URL |
|
||||
|----------|-----|
|
||||
| MCP (client AI) | `https://mcp.loogle.it/mcp` |
|
||||
| Dashboard web | `https://mcp.loogle.it/dashboard` |
|
||||
| Health | `https://mcp.loogle.it/health` |
|
||||
| OAuth authorize | `https://mcp.loogle.it/oauth/authorize` |
|
||||
| OAuth token | `https://mcp.loogle.it/oauth/token` |
|
||||
| Metadata OAuth | `https://mcp.loogle.it/.well-known/oauth-authorization-server` |
|
||||
| Metadata risorsa MCP | `https://mcp.loogle.it/.well-known/oauth-protected-resource` |
|
||||
|
||||
---
|
||||
|
||||
## DNS
|
||||
|
||||
| Record | Tipo | Valore | Dove configurato |
|
||||
|--------|------|--------|------------------|
|
||||
| `mcp.loogle.it` | A | `192.168.128.85` (VIP NPM) | Pi-hole `/etc/pihole/pihole.toml` → hosts |
|
||||
| Risoluzione LAN | — | Pi-hole → Unbound → split-horizon | Come `docs.loogle.it`, `pass.loogle.it` |
|
||||
|
||||
**Script setup:** `/home/daniely/rete/scripts/setup-mcp-dns-npm.sh`
|
||||
|
||||
**Verifica:**
|
||||
```bash
|
||||
dig +short mcp.loogle.it @127.0.0.1 # → 192.168.128.85
|
||||
curl -sf https://mcp.loogle.it/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NPM (reverse proxy)
|
||||
|
||||
| Parametro | Valore |
|
||||
|-----------|--------|
|
||||
| Proxy host ID | 30 |
|
||||
| Dominio | `mcp.loogle.it` |
|
||||
| Upstream normale | `192.168.128.80:8700` |
|
||||
| Certificato TLS | `npm-65` (Let's Encrypt) |
|
||||
| Failover route | `rete/ha/npm-routes.conf` riga `30\|mcp.loogle.it\|8700\|...` |
|
||||
| Websocket | ON |
|
||||
| Force SSL | ON |
|
||||
|
||||
**Failover:** `npm-failover-route.sh` aggiorna upstream su Pi-2 / DS920 in base allo scenario HA.
|
||||
|
||||
---
|
||||
|
||||
## Variabili d'ambiente (`.env`)
|
||||
|
||||
File: `/home/daniely/docker/loogle-mcp/.env`
|
||||
|
||||
| Variabile | Descrizione | Esempio |
|
||||
|-----------|-------------|---------|
|
||||
| `MCP_BASE_URL` | URL pubblico (issuer JWT) | `https://mcp.loogle.it` |
|
||||
| `MCP_JWT_SECRET` | Segreto firma token OAuth | *(stringa lunga casuale)* |
|
||||
| `MCP_OAUTH_CLIENT_ID` | Client OAuth pre-registrato | `loogle-mcp-public` |
|
||||
| `PAPERLESS_URL` | API documenti | `https://docs.loogle.it` |
|
||||
| `PAPERLESS_API_TOKEN` | Token API admin (fallback) | vedi [PAPERLESS-TOKEN.md](PAPERLESS-TOKEN.md) |
|
||||
| `PAPERLESS_API_TOKEN_{USER}` | Token API per utente | `DANIELE`, `LUCIA`, `DAVIDE`, `LUCA` |
|
||||
| `QDRANT_URL` | Vector DB remoto | `http://192.168.128.100:6333` |
|
||||
| `OLLAMA_URL` | Embedding locale | `http://192.168.128.100:11434` |
|
||||
| `OLLAMA_EMBED_MODEL` | Modello embedding | `nomic-embed-text` |
|
||||
| `OPENAI_API_KEY` | Fallback embedding cloud | *(opzionale)* |
|
||||
| `INDEXER_INTERVAL_MINUTES` | Intervallo sync Paperless | `30` |
|
||||
| `THERMAL_TEMP_HARD_C` | Pausa embedding se CPU DS920 ≥ °C | `70` |
|
||||
| `THERMAL_TEMP_SOFT_C` | Rallenta embedding sopra °C | `58` |
|
||||
| `THERMAL_CPU_TARGET_PCT` | Cap load1 (nproc × %) | `40` |
|
||||
| `OLLAMA_NUM_THREAD` | Thread CPU per richiesta embed | `1` |
|
||||
| `OLLAMA_EMBED_DELAY_S` | Pausa tra embed (duty-cycle lento) | `10` |
|
||||
| `DS920_THERMAL_URL` | Probe temp/load DS920 | `http://192.168.128.100:9191/thermal` |
|
||||
|
||||
---
|
||||
|
||||
## Utenti e isolamento
|
||||
|
||||
| Persona | Username | Ruolo | Password iniziale |
|
||||
|---------|----------|-------|-------------------|
|
||||
| Daniele | `daniele` | admin | `daniele` *(cambiarla)* |
|
||||
| Lucia | `lucia` | user | `lucia` |
|
||||
| Davide | `davide` | user | `davide` |
|
||||
| Luca | `luca` | user | `luca` |
|
||||
|
||||
- Ogni utente vede **solo** i propri progetti in `/mnt/ha-apps/mcp/context/{username}/`
|
||||
- I token OAuth JWT contengono `sub` = username; ogni tool filtra per utente
|
||||
- L’admin può `reindex_document`, vedere audit completo, revocare refresh token
|
||||
|
||||
**Scope OAuth:** `context:read`, `context:write`, `knowledge:read`, `knowledge:write`, `gitea:read`, `gitea:write`, `home:read`, `irrigation:read`, `turni:read`, `admin` (solo daniele)
|
||||
|
||||
---
|
||||
|
||||
## Tool MCP esposti
|
||||
|
||||
| Tool | Scope minimo | Funzione |
|
||||
|------|--------------|----------|
|
||||
| `ping` | — | Test connettività |
|
||||
| `whoami` | — | Utente e scope attivi |
|
||||
| `list_projects` | context:read | Elenco progetti |
|
||||
| `create_project` | context:write | Nuovo progetto |
|
||||
| `get_project_context` | context:read | Legge memoria progetto |
|
||||
| `save_context` | context:write | Salva/appende memoria |
|
||||
| `archive_project` | context:write | Archivia progetto |
|
||||
| `search_context` | context:read | Ricerca semantica contesti |
|
||||
| `search_knowledge` | knowledge:read | RAG Paperless + contesti + Gitea + app |
|
||||
| `search_gitea_knowledge` | knowledge:read | RAG solo Gitea |
|
||||
| `search_apps_knowledge` | knowledge:read | RAG Irrigazione + Turni |
|
||||
| `list_apps_indexed` | knowledge:read | Stato indicizzazione app |
|
||||
| `reindex_apps` | admin | Re-sync RAG app |
|
||||
| `get_document` | knowledge:read | Testo documento Paperless |
|
||||
| `list_recent_documents` | knowledge:read | Ultimi doc indicizzati |
|
||||
| `reindex_document` | admin | Re-indicizza documento |
|
||||
| `get_home_dashboard` | home:read | Dashboard Loogle Casa |
|
||||
| `get_home_weather` | home:read | Meteo casa |
|
||||
| `get_network_overview` | home:read | Panoramica rete LAN |
|
||||
| `get_network_failover_status` | home:read | Stato failover cluster |
|
||||
| `get_ha_entity` | home:read | Entità Home Assistant |
|
||||
| `list_ha_entities` | home:read | Elenco entità HA |
|
||||
| `search_ha_entities` | home:read | Cerca entità HA |
|
||||
| `get_irrigation_status` | irrigation:read | Stato irrigazione |
|
||||
| `get_irrigation_zones` | irrigation:read | Zone irrigazione |
|
||||
| `get_irrigation_history` | irrigation:read | Storico irrigazioni |
|
||||
| `get_turni_status` | — | Stato servizio Turni |
|
||||
| `get_my_shifts` | turni:read | Turni utente corrente |
|
||||
| `list_turni_doctors` | turni:read | Medici Turni-Live |
|
||||
|
||||
Vedi anche tool Gitea in `docs/GITEA-TOKEN.md` e app homelab in `docs/APPS-INTEGRATION.md`.
|
||||
|
||||
---
|
||||
|
||||
## Storage contesto (per progetto)
|
||||
|
||||
```
|
||||
/mnt/ha-apps/mcp/context/{username}/projects/{project-id}/
|
||||
meta.json # titolo, tag, date, stato, gitea_repo (opz.)
|
||||
context.md # memoria persistente
|
||||
sessions/ # snapshot conversazioni
|
||||
artifacts/ # file generati dagli agenti
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Vector store / RAG
|
||||
|
||||
| Collection Qdrant | Contenuto |
|
||||
|-------------------|-----------|
|
||||
| `kb_shared_family` | Documenti famiglia (tag non personali) |
|
||||
| `kb_personal_{user}` | Documenti personali |
|
||||
| `ctx_{user}` | Embedding dei contesti agente |
|
||||
| `gitea_shared_family` | File testo da repo Gitea non privati |
|
||||
| `gitea_personal_{user}` | File testo da repo Gitea privati dell'owner |
|
||||
| `apps_shared_family` | Export Irrigazione + Turni (P7) |
|
||||
|
||||
**Nota Pi 5:** Qdrant locale su ARM (page size 16K) non è supportato. Default: Qdrant su DS920 o fallback SQLite in `/data/vector_fallback.db`.
|
||||
|
||||
**Pipeline indexer:** ogni 30 min:
|
||||
1. Paperless → chunk → embedding (Ollama DS920) → upsert `kb_*`
|
||||
2. Gitea (repo configurati in `GITEA_INDEX_REPOS_*`) → file `.md`/`.py`/`.sh` → chunk → upsert `gitea_*`
|
||||
3. Irrigazione + Turni → snapshot/storico → upsert `apps_shared_family` (vedi `docs/APPS-INTEGRATION.md`)
|
||||
|
||||
---
|
||||
|
||||
## Sicurezza
|
||||
|
||||
- TLS terminato su NPM (Let's Encrypt)
|
||||
- OAuth 2.1 Authorization Code + PKCE
|
||||
- JWT access token 1h + refresh token 30 giorni (revocabili)
|
||||
- Audit log: `{timestamp, user, tool, resource_id}` in SQLite
|
||||
- CrowdSec attivo su NPM
|
||||
- Nessun accesso cross-user ai dati
|
||||
|
||||
---
|
||||
|
||||
## Operazioni comuni
|
||||
|
||||
```bash
|
||||
# Stato servizi
|
||||
cd /home/daniely/docker/loogle-mcp && docker compose ps
|
||||
|
||||
# Log
|
||||
docker logs -f loogle-mcp
|
||||
docker logs -f loogle-mcp-indexer
|
||||
|
||||
# Redeploy
|
||||
./scripts/deploy.sh
|
||||
|
||||
# DNS + NPM (se reinstall)
|
||||
sudo /home/daniely/rete/scripts/setup-mcp-dns-npm.sh
|
||||
|
||||
# Failover route
|
||||
/home/daniely/rete/scripts/npm-failover-route.sh normal
|
||||
|
||||
# Backup dati MCP
|
||||
/home/daniely/rete/infra-monitor/mcp-restic-backup.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Failover (tier-b)
|
||||
|
||||
| Scenario | Comportamento |
|
||||
|----------|---------------|
|
||||
| Pi-1 down, Pi-2 up | Stack MCP su Pi-2, NPM upstream → `.81:8700` |
|
||||
| Extrema DS920 | NPM3 + upstream DS920 |
|
||||
| Monitoraggio | Probe `mcp_ok` in `failover-status.sh` |
|
||||
|
||||
---
|
||||
|
||||
## Da completare (post-install)
|
||||
|
||||
1. **`PAPERLESS_API_TOKEN_*`** in `.env` — vedi [PAPERLESS-TOKEN.md](PAPERLESS-TOKEN.md)
|
||||
2. **Ollama su DS920** con `nomic-embed-text` per embedding locali
|
||||
3. **Qdrant su DS920** (opzionale): `rete/compose/extrema-ds920/loogle-mcp-compose.yml`
|
||||
4. **Cambio password** per tutti gli utenti dal dashboard
|
||||
5. **`MCP_JWT_SECRET`** — impostare valore robusto in produzione
|
||||
|
||||
---
|
||||
|
||||
## Riferimenti
|
||||
|
||||
- [Guida utenti famiglia](docs/GUIDA-UTENTI.md)
|
||||
- [Onboarding tecnico client AI](docs/ONBOARDING.md)
|
||||
- [Runbook operativo](/home/daniely/rete/ha/RUNBOOK-mcp.md)
|
||||
- [README progetto](README.md)
|
||||
Reference in new issue
Block a user