From ccab72c58673b81930388666a1ccec2a8d16e771 Mon Sep 17 00:00:00 2001 From: xavix-yo Date: Wed, 22 Jul 2026 22:52:01 +0100 Subject: [PATCH] Nuovo sistema: index.json + fragment.json + compile.py (SHA-256 automatici) --- SKALD.md | 139 +++++-- connectors/connectors.json | 445 ++++++++++++----------- connectors/context7/fragment.json | 33 ++ connectors/drive/fragment.json | 32 ++ connectors/email/fragment.json | 26 ++ connectors/exa/fragment.json | 32 ++ connectors/firecrawl/fragment.json | 134 +++++++ connectors/gcal/fragment.json | 30 ++ connectors/gmail/fragment.json | 31 ++ connectors/gmaps/fragment.json | 56 +++ connectors/google-trends/fragment.json | 45 +++ connectors/http-fetch/fragment.json | 54 +++ connectors/index.json | 1 + connectors/serpapi-flights/fragment.json | 29 ++ connectors/ssh/fragment.json | 27 ++ connectors/tavily/fragment.json | 43 +++ connectors/weather/fragment.json | 24 ++ connectors/whatsapp/fragment.json | 26 ++ connectors/wikipedia/fragment.json | 24 ++ scripts/compile.py | 130 +++++++ 20 files changed, 1121 insertions(+), 240 deletions(-) create mode 100644 connectors/context7/fragment.json create mode 100644 connectors/drive/fragment.json create mode 100644 connectors/email/fragment.json create mode 100644 connectors/exa/fragment.json create mode 100644 connectors/firecrawl/fragment.json create mode 100644 connectors/gcal/fragment.json create mode 100644 connectors/gmail/fragment.json create mode 100644 connectors/gmaps/fragment.json create mode 100644 connectors/google-trends/fragment.json create mode 100644 connectors/http-fetch/fragment.json create mode 100644 connectors/index.json create mode 100644 connectors/serpapi-flights/fragment.json create mode 100644 connectors/ssh/fragment.json create mode 100644 connectors/tavily/fragment.json create mode 100644 connectors/weather/fragment.json create mode 100644 connectors/whatsapp/fragment.json create mode 100644 connectors/wikipedia/fragment.json create mode 100644 scripts/compile.py diff --git a/SKALD.md b/SKALD.md index 90f3c81..ac7bf4e 100644 --- a/SKALD.md +++ b/SKALD.md @@ -15,7 +15,13 @@ _Updated: 2026-07-22_ Il branch **`main`** è il branch di **release**. Solo codice pronto per produzione finisce qui. Sviluppo e versioni alfa-staranno su branch separati in futuro. -Per deployare l'ultima versione del marketplace sul server: +Deploy rapido con MCP SSH: + +```bash +mcp__ssh__exec alias=skald-home-server command="/home/dguiducci/marketplace_deploy.sh" +``` + +Oppure via SSH classico: ```bash ssh dguiducci@skald-home-server /home/dguiducci/marketplace_deploy.sh @@ -28,6 +34,11 @@ Lo script sul server fa: La directory `/var/www/connectors.skaldagent.net/` è di proprietà di `dguiducci`, quindi non serve sudo per la copia. +**Prima del deploy**, ricordarsi di rigenerare l'indice: +```bash +python3 scripts/compile.py +``` + ## Cos'è Il **marketplace** è il catalogo dei connector testati per Skald. Ogni connector è un adattatore che permette a Skald di interfacciarsi con un servizio esterno (API, email, calendario, ricerca, messaggistica, ecc.). @@ -56,18 +67,22 @@ Stato attuale (2026-07-21): tutti i 13 connector del marketplace hanno `title` n ``` connectors/ -├── connectors.json ← INDICE (radice di fiducia unica) +├── index.json ← lista ordinata degli id dei connector (input per compile.py) +├── connectors.json ← INDICE COMPILATO (generato da compile.py, non editare) +├── compile.py ← genera connectors.json ├── index.html ← Catalogo UI (legge connectors.json via fetch) ├── oauth/ │ └── show.html ← OAuth callback receiver (client-side, no backend) ├── gmail/ ← Un connector per cartella +│ ├── fragment.json ← Frammento dell'indice (id, name, type, ..., SENZA files[]) │ ├── connector.json ← Configurazione tecnica │ ├── gmail_mcp_server.py ← Script MCP │ ├── gmail_oauth_setup.py ← Script setup OAuth │ ├── requirements.txt ← Dipendenze Python │ ├── icon_sm.svg ← Icona piccola (48×48) -│ └── icon_lg.svg ← Icona grande (es. preview) +│ └── icon_lg.svg ← Icona grande (es. 96×96) ├── email/ +│ ├── fragment.json │ ├── connector.json │ ├── email_mcp_server.py │ ├── verify.py @@ -75,17 +90,21 @@ connectors/ │ ├── icon_sm.svg │ └── icon_lg.svg ├── ssh/ +│ ├── fragment.json │ ├── connector.json │ ├── ssh_mcp_server.py │ ├── requirements.txt │ ├── icon_sm.svg │ └── icon_lg.svg └── tavily/ + ├── fragment.json ├── connector.json ├── verify.py ├── icon_sm.png └── icon_lg.png ``` + └── icon_lg.png +``` ## Schema — connectors.json (root) @@ -436,28 +455,103 @@ il test scrivendo `verify`. ## Integrità file (sha256) -- Gli hash sha256 sono **solo in `connectors.json`** (l'indice) -- `connector.json` **non contiene hash di sé stesso** — è il file manifesto -- L'indice è l'unica radice di fiducia; in futuro si può firmare digitalmente solo l'indice -- Sui file locali, per calcolare/aggiornare gli hash: - ```bash - python3 -c "import hashlib; print(hashlib.sha256(open('file.py','rb').read()).hexdigest())" - ``` +- Gli SHA-256 sono generati **automaticamente** da `scripts/compile.py` a partire + dai file fisici presenti in ogni cartella — mai manuali, mai stale. +- L'unico file firmato (in futuro) sarà `connectors.json` (l'indice). +- `fragment.json` e `index.json` non hanno hash — sono solo input di compilazione. + +## Struttura directory + +``` +connectors/ +├── index.json ← lista ordinata degli id dei connector (input per compile.py) +├── connectors.json ← INDICE COMPILATO (generato da compile.py, non editare) +├── compile.py ← genera connectors.json (lanciato da scripts/compile.py) +├── index.html ← Catalogo UI (legge connectors.json via fetch) +├── oauth/ +│ └── show.html ← OAuth callback receiver +├── gmail/ ← Un connector per cartella +│ ├── fragment.json ← Frammento dell'indice (id, name, type, ..., SENZA files[]) +│ ├── connector.json ← Configurazione tecnica (mcp_config, auth.deliver, ...) +│ ├── gmail_mcp_server.py ← Script MCP +│ ├── gmail_oauth_setup.py ← Script setup OAuth +│ ├── requirements.txt ← Dipendenze Python +│ ├── icon_sm.svg ← Icona piccola (48×48) +│ └── icon_lg.svg ← Icona grande (es. 96×96) +├── email/ +│ ├── fragment.json +│ ├── connector.json +│ ├── email_mcp_server.py +│ ├── verify.py +│ ├── requirements.txt +│ ├── icon_sm.svg +│ └── icon_lg.svg +└── ... +``` ## Workflow locale -1. Lavora su file nella cartella `connectors/` -2. Modifica `connectors.json`, `connector.json`, script, icone -3. **Prima del deploy** aggiorna gli sha256 in `connectors.json`: +1. **Aggiungere un nuovo connector**: + - Crea cartella `connectors//` + - Crea `fragment.json` (id, name, type, scope, icone, auth, tools, ...) + - Crea `connector.json` (config tecnica: mcp_config, launch_command, ...) + - Aggiungi script MCP, icone, verify.py, requirements.txt + - Aggiungi l'id a `connectors/index.json` + - Lancia `python3 scripts/compile.py` + +2. **Modificare un connector esistente**: + - Modifica i file nella cartella del connector + - **Non toccare** `connectors.json` — viene rigenerato + - Lancia `python3 scripts/compile.py` + +3. **Prima del deploy**: ```bash - python3 scripts/update_hashes.py + python3 scripts/compile.py # rigenera connectors.json con SHA-256 fresh + python3 scripts/compile.py --verify # (opzionale) verifica che sia aggiornato ``` -4. Fai l'upload sul server con rsync: + +4. **Deploy sul server**: ```bash - rsync -avz --delete connectors/ dguiducci@skald-server:/var/www/connectors.skaldagent.net/ + ssh dguiducci@skald-home-server /home/dguiducci/marketplace_deploy.sh ``` + oppure con MCP SSH: + ```bash + # via mcp__ssh__exec alias "skald-home-server" + /home/dguiducci/marketplace_deploy.sh + ``` + (Il deploy script fa `git pull` + `cp -r connectors/* /var/www/connectors.skaldagent.net/`) + 5. Verifica su `https://connectors.skaldagent.net/` +## Fragment.json + +Vedi [connector.manifest_guide.md](docs/connector.manifest_guide.md) per i dettagli. + +`fragment.json` contiene tutti i campi dell'entry di `connectors.json` **tranne** `files[]`. +Questi sono i campi obbligatori: + +| Campo | Obbligatorio | Descrizione | +|-------|-------------|-------------| +| `id` | ✅ | Identificatore unico (match con folder name) | +| `name` | ✅ | Nome visualizzato | +| `type` | ✅ | `mcp_remote` o `mcp_local` | +| `scope` | ✅ | `global` o `user` | +| `icon_small` | ✅ | Path relativo dalla root del marketplace | +| `icon_large` | ✅ | Path relativo dalla root del marketplace | +| `user_description` | ✅ | Descrizione breve per la UI | +| `requires` | ✅ | Array di enum requisiti | +| `tags` | ✅ | Array di tag per filtraggio | +| `folder` | ✅ | Nome della cartella del connector (match con `id`) | +| `version` | ✅ | Intero per-connector, +1 a ogni modifica dei file | +| `version_string` | ✅ | Semver (solo display) | +| `version_release_date` | ✅ | Data ISO 8601 (solo display) | +| `tools` | ✅ | Array di `{name, display_name}` per friendly names UI | +| `auth` | opzionale | Configurazione autenticazione (se diversa da `"none"`) | + +Nota: l'array `files[]` (con SHA-256 e size) viene aggiunto **automaticamente** +da `compile.py` scansionando i file presenti nella cartella — non va mai scritto +a mano. + ## Deploy su server remoto Il server remoto è: @@ -468,19 +562,6 @@ Il server remoto è: - **Proprietario**: `caddy:caddy` - **Sudo**: richiesto per scrivere in `/var/www/` -Comando di deploy (da eseguire con sudo o con rsync): - -```bash -# Sync se il server permette rsync via SSH -rsync -avz --delete ./connectors/ dguiducci@skald-server:/var/www/connectors.skaldagent.net/ -``` - -Dopo il deploy, verificare i permessi: -```bash -sudo chown -R caddy:caddy /var/www/connectors.skaldagent.net/ -sudo find /var/www/connectors.skaldagent.net/ -type f -exec chmod 644 {} \; -``` - ## Connector attuali | ID | Nome | Tipo | Scope | Auth | Verify | diff --git a/connectors/connectors.json b/connectors/connectors.json index 15a3e1c..87e56b5 100644 --- a/connectors/connectors.json +++ b/connectors/connectors.json @@ -100,24 +100,24 @@ "size": 38437 }, { - "path": "verify.py", - "sha256": "d994ae435d8a5a3d9cdc85c8f73805a877c1a8818637b2912f6c31c693fdded4", - "size": 3429 + "path": "icon_lg.svg", + "sha256": "b5daeeaaebba5b6d5ea31fd51bc63887225dee8aa1a42b571e49263f930895a9", + "size": 479 }, { "path": "icon_sm.svg", "sha256": "477ab05d24b40aaf4209c37e30558878fd0833dfbcfa8648b0ab9b903bd171d3", "size": 473 }, - { - "path": "icon_lg.svg", - "sha256": "b5daeeaaebba5b6d5ea31fd51bc63887225dee8aa1a42b571e49263f930895a9", - "size": 479 - }, { "path": "requirements.txt", "sha256": "41a908f999095b052865efdcf793cfe7b032a3609c0cdd9f7711b2af5b3b7827", "size": 54 + }, + { + "path": "verify.py", + "sha256": "d994ae435d8a5a3d9cdc85c8f73805a877c1a8818637b2912f6c31c693fdded4", + "size": 3429 } ] }, @@ -164,14 +164,9 @@ "size": 20124 }, { - "path": "verify.py", - "sha256": "3f1da92f15e7f6898545bb170f7123610025088c7403edd2021ce8b3499713e2", - "size": 3304 - }, - { - "path": "requirements.txt", - "sha256": "3f659cc5e5f0543f132699b06ccf9016ffe9afb40f9df4d110e0445b8d20f63e", - "size": 82 + "path": "icon_lg.png", + "sha256": "723b1ec7c72309f75d2ea0ea38ff526502f6fd1cf4c849090bfb6b3a4e69efd3", + "size": 3997 }, { "path": "icon_sm.png", @@ -179,9 +174,14 @@ "size": 1860 }, { - "path": "icon_lg.png", - "sha256": "723b1ec7c72309f75d2ea0ea38ff526502f6fd1cf4c849090bfb6b3a4e69efd3", - "size": 3997 + "path": "requirements.txt", + "sha256": "3f659cc5e5f0543f132699b06ccf9016ffe9afb40f9df4d110e0445b8d20f63e", + "size": 82 + }, + { + "path": "verify.py", + "sha256": "3f1da92f15e7f6898545bb170f7123610025088c7403edd2021ce8b3499713e2", + "size": 3304 } ] }, @@ -259,28 +259,6 @@ "version": 4, "version_string": "1.0.3", "version_release_date": "2026-07-21", - "files": [ - { - "path": "connector.json", - "sha256": "bce7389bfc62c9a1f633df09cdcd4630c592efc11ef064cbbf5a2a48a1b2606e", - "size": 1619 - }, - { - "path": "verify.py", - "sha256": "8e77da3ca3eca8f733296da134aaa964e5db8d01d4bfb89aa5832296e9dc45a6", - "size": 2125 - }, - { - "path": "icon_sm.png", - "sha256": "dd0a17d75ce36187f34c1fbfa459aee1665d94b2b8e1e300c2559631ffdcd1bd", - "size": 1728 - }, - { - "path": "icon_lg.png", - "sha256": "a1b698035af2cb146dccd57f992155359d55a48bc85802e2a02e8148dcec1558", - "size": 3730 - } - ], "tools": [ { "name": "web_search_exa", @@ -290,6 +268,28 @@ "name": "web_fetch_exa", "display_name": "Web Fetch" } + ], + "files": [ + { + "path": "connector.json", + "sha256": "bce7389bfc62c9a1f633df09cdcd4630c592efc11ef064cbbf5a2a48a1b2606e", + "size": 1619 + }, + { + "path": "icon_lg.png", + "sha256": "a1b698035af2cb146dccd57f992155359d55a48bc85802e2a02e8148dcec1558", + "size": 3730 + }, + { + "path": "icon_sm.png", + "sha256": "dd0a17d75ce36187f34c1fbfa459aee1665d94b2b8e1e300c2559631ffdcd1bd", + "size": 1728 + }, + { + "path": "verify.py", + "sha256": "8e77da3ca3eca8f733296da134aaa964e5db8d01d4bfb89aa5832296e9dc45a6", + "size": 2125 + } ] }, { @@ -319,23 +319,6 @@ "version": 4, "version_string": "1.0.3", "version_release_date": "2026-07-21", - "files": [ - { - "path": "connector.json", - "sha256": "6cab1a43e32741eb4f31638841e65b68fb937d2c6313fd18ace38e722bc2eb23", - "size": 5008 - }, - { - "path": "icon_sm.png", - "sha256": "3a4be30d4c16ce93a1d132e063dfdffb8bd27b6c97715c9f3b12414439aaeb01", - "size": 6858 - }, - { - "path": "icon_lg.png", - "sha256": "3a4be30d4c16ce93a1d132e063dfdffb8bd27b6c97715c9f3b12414439aaeb01", - "size": 6858 - } - ], "tools": [ { "name": "firecrawl_scrape", @@ -441,6 +424,23 @@ "name": "firecrawl_research_search_github", "display_name": "Search GitHub" } + ], + "files": [ + { + "path": "connector.json", + "sha256": "6cab1a43e32741eb4f31638841e65b68fb937d2c6313fd18ace38e722bc2eb23", + "size": 5008 + }, + { + "path": "icon_lg.png", + "sha256": "3a4be30d4c16ce93a1d132e063dfdffb8bd27b6c97715c9f3b12414439aaeb01", + "size": 6858 + }, + { + "path": "icon_sm.png", + "sha256": "3a4be30d4c16ce93a1d132e063dfdffb8bd27b6c97715c9f3b12414439aaeb01", + "size": 6858 + } ] }, { @@ -470,23 +470,6 @@ "version": 4, "version_string": "1.0.3", "version_release_date": "2026-07-21", - "files": [ - { - "path": "connector.json", - "sha256": "8087d8ed8af7c6b628c95ff74f5126023a1ed1c99c2b3fc5c0599f665ffaa6f2", - "size": 1862 - }, - { - "path": "icon_sm.svg", - "sha256": "fa32e634744d8cba369f6d8ba45746166124f7d3507cefd9a1f96180c787e1a8", - "size": 380 - }, - { - "path": "icon_lg.svg", - "sha256": "3e5496d949062678ae44cd74430b29232bbfe28a7600038deb3159c4b26adee1", - "size": 382 - } - ], "tools": [ { "name": "fetch_html", @@ -512,6 +495,23 @@ "name": "fetch_youtube_transcript", "display_name": "Get YouTube Transcript" } + ], + "files": [ + { + "path": "connector.json", + "sha256": "8087d8ed8af7c6b628c95ff74f5126023a1ed1c99c2b3fc5c0599f665ffaa6f2", + "size": 1862 + }, + { + "path": "icon_lg.svg", + "sha256": "3e5496d949062678ae44cd74430b29232bbfe28a7600038deb3159c4b26adee1", + "size": 382 + }, + { + "path": "icon_sm.svg", + "sha256": "fa32e634744d8cba369f6d8ba45746166124f7d3507cefd9a1f96180c787e1a8", + "size": 380 + } ] }, { @@ -536,6 +536,12 @@ "version": 4, "version_string": "1.0.3", "version_release_date": "2026-07-21", + "tools": [ + { + "name": "serpapi_search_flights", + "display_name": "Search Flights" + } + ], "files": [ { "path": "connector.json", @@ -543,9 +549,9 @@ "size": 1498 }, { - "path": "verify.py", - "sha256": "eca6298a01cc1c8ce2aece9170a0b228efda7cb8a5c469d1ca3b62932fb7ea51", - "size": 2003 + "path": "icon_lg.svg", + "sha256": "5a2ffa7f2502fd27dc0027395db2c863bb544c8de1eef8131a5228d87402c8e6", + "size": 574 }, { "path": "icon_sm.svg", @@ -553,15 +559,9 @@ "size": 570 }, { - "path": "icon_lg.svg", - "sha256": "5a2ffa7f2502fd27dc0027395db2c863bb544c8de1eef8131a5228d87402c8e6", - "size": 574 - } - ], - "tools": [ - { - "name": "serpapi_search_flights", - "display_name": "Search Flights" + "path": "verify.py", + "sha256": "eca6298a01cc1c8ce2aece9170a0b228efda7cb8a5c469d1ca3b62932fb7ea51", + "size": 2003 } ] }, @@ -598,14 +598,9 @@ "size": 3986 }, { - "path": "ssh_mcp_server.py", - "sha256": "68509094a35578ffaaf357e13b55e1bfcf397f16a3b993719c4c3b97ab2dc798", - "size": 50193 - }, - { - "path": "requirements.txt", - "sha256": "fa65d44e3d3219c79e5272ef7123352b5d71a35871ede721e66422c897b94e0e", - "size": 14 + "path": "icon_lg.svg", + "sha256": "84dc85685be0fff4cae1c2554b5fe958dd94455e182117c7470838b3cfca6ba1", + "size": 432 }, { "path": "icon_sm.svg", @@ -613,9 +608,14 @@ "size": 254 }, { - "path": "icon_lg.svg", - "sha256": "84dc85685be0fff4cae1c2554b5fe958dd94455e182117c7470838b3cfca6ba1", - "size": 432 + "path": "requirements.txt", + "sha256": "fa65d44e3d3219c79e5272ef7123352b5d71a35871ede721e66422c897b94e0e", + "size": 14 + }, + { + "path": "ssh_mcp_server.py", + "sha256": "68509094a35578ffaaf357e13b55e1bfcf397f16a3b993719c4c3b97ab2dc798", + "size": 50193 } ] }, @@ -639,28 +639,6 @@ "version": 5, "version_string": "1.0.4", "version_release_date": "2026-07-22", - "files": [ - { - "path": "connector.json", - "sha256": "c020a333b78778bc29f4097d56e27d6bde8c33b691f9aedb176a1887e65db730", - "size": 1577 - }, - { - "path": "icon_lg.png", - "sha256": "55a00f6108c1ba0a7d75780c446494c3272733879748e18b0377b7f816f39c5d", - "size": 3803 - }, - { - "path": "icon_sm.png", - "sha256": "7cc2d70581dc4288b43b27c9e1f3e3946c5598a8f71c2916aa5c2b64b9273dfe", - "size": 1882 - }, - { - "path": "verify.py", - "sha256": "35a4f3b518c79363893c0438b1932b68e2dc5b4b61303037984488f6967b73a4", - "size": 2057 - } - ], "tools": [ { "name": "tavily_search", @@ -682,6 +660,28 @@ "name": "tavily_research", "display_name": "Deep Research" } + ], + "files": [ + { + "path": "connector.json", + "sha256": "c020a333b78778bc29f4097d56e27d6bde8c33b691f9aedb176a1887e65db730", + "size": 1577 + }, + { + "path": "icon_lg.png", + "sha256": "55a00f6108c1ba0a7d75780c446494c3272733879748e18b0377b7f816f39c5d", + "size": 3803 + }, + { + "path": "icon_sm.png", + "sha256": "7cc2d70581dc4288b43b27c9e1f3e3946c5598a8f71c2916aa5c2b64b9273dfe", + "size": 1882 + }, + { + "path": "verify.py", + "sha256": "35a4f3b518c79363893c0438b1932b68e2dc5b4b61303037984488f6967b73a4", + "size": 2057 + } ] }, { @@ -708,20 +708,15 @@ "version_string": "3.0.4", "version_release_date": "2026-07-21", "files": [ - { - "path": "weather_mcp_server.py", - "sha256": "2b1c40f927d3095806504ae3c82ace156e6079294cf15c6c2c47df1422068185", - "size": 30001 - }, { "path": "connector.json", "sha256": "29881ad0ff5752dc546484cca6d98c22153e053d3e50c8480d02009314c9d1a8", "size": 1448 }, { - "path": "requirements.txt", - "sha256": "bff057979879bf8d16acdc64317c6f2ac3dba4f1c4cd8df5ccd2a592fa804c95", - "size": 14 + "path": "icon_lg.svg", + "sha256": "b1a16c5da95783d79e06388e5a18bc6c8291875335e8ac48665edeff5aeafca7", + "size": 372 }, { "path": "icon_sm.svg", @@ -729,9 +724,14 @@ "size": 308 }, { - "path": "icon_lg.svg", - "sha256": "b1a16c5da95783d79e06388e5a18bc6c8291875335e8ac48665edeff5aeafca7", - "size": 372 + "path": "requirements.txt", + "sha256": "bff057979879bf8d16acdc64317c6f2ac3dba4f1c4cd8df5ccd2a592fa804c95", + "size": 14 + }, + { + "path": "weather_mcp_server.py", + "sha256": "2b1c40f927d3095806504ae3c82ace156e6079294cf15c6c2c47df1422068185", + "size": 30001 } ] }, @@ -766,6 +766,16 @@ "sha256": "6ccae6fdf863bb6bd531d9ee0c4dcc65d46c18dd5a5f01ec914be7788f05aa31", "size": 1354 }, + { + "path": "icon_lg.png", + "sha256": "1128f198b2a07041f2e0c8c330fc998d29c310ec3225f866073b9e921aa59b5f", + "size": 74223 + }, + { + "path": "icon_sm.png", + "sha256": "1128f198b2a07041f2e0c8c330fc998d29c310ec3225f866073b9e921aa59b5f", + "size": 74223 + }, { "path": "index.js", "sha256": "0bfaa3c5449f22a4e2c4c99c6e9402bb24651647eca9a36dbd7a639c95a6bfd6", @@ -775,16 +785,6 @@ "path": "package.json", "sha256": "b99a9dccfd286b59e8482076129f2e40f7b339eba6c3db2a744887d65bd4964e", "size": 302 - }, - { - "path": "icon_sm.png", - "sha256": "1128f198b2a07041f2e0c8c330fc998d29c310ec3225f866073b9e921aa59b5f", - "size": 74223 - }, - { - "path": "icon_lg.png", - "sha256": "1128f198b2a07041f2e0c8c330fc998d29c310ec3225f866073b9e921aa59b5f", - "size": 74223 } ] }, @@ -812,20 +812,15 @@ "version_string": "3.0.4", "version_release_date": "2026-07-21", "files": [ - { - "path": "wikipedia_mcp_server.py", - "sha256": "ce9feed6a8b0a29ed405dbfe90743816d7f0714f1b580671bac722112bb54146", - "size": 12174 - }, { "path": "connector.json", "sha256": "f921a43e16d459c6ab6ddc375664e8ebe30c94e8dc35e07a72ca25d2303c6179", "size": 1339 }, { - "path": "requirements.txt", - "sha256": "bff057979879bf8d16acdc64317c6f2ac3dba4f1c4cd8df5ccd2a592fa804c95", - "size": 14 + "path": "icon_lg.svg", + "sha256": "f9a8dde47baf3842331534ddc4333024b195c53b5f3bda40b0b99cea3daa9a96", + "size": 285 }, { "path": "icon_sm.svg", @@ -833,9 +828,14 @@ "size": 286 }, { - "path": "icon_lg.svg", - "sha256": "f9a8dde47baf3842331534ddc4333024b195c53b5f3bda40b0b99cea3daa9a96", - "size": 285 + "path": "requirements.txt", + "sha256": "bff057979879bf8d16acdc64317c6f2ac3dba4f1c4cd8df5ccd2a592fa804c95", + "size": 14 + }, + { + "path": "wikipedia_mcp_server.py", + "sha256": "ce9feed6a8b0a29ed405dbfe90743816d7f0714f1b580671bac722112bb54146", + "size": 12174 } ] }, @@ -861,28 +861,6 @@ "version": 3, "version_string": "1.0.2", "version_release_date": "2026-07-22", - "files": [ - { - "path": "connector.json", - "sha256": "2c0a92ece0fa0bb6d5e00d4db6f858d21a94bdf08b6043b93cffe372054e0100", - "size": 1279 - }, - { - "path": "verify.py", - "sha256": "8e46d562c028c4f5370c22c7df455886836267cf4bbb8ac605c79a2b509fb5f1", - "size": 2094 - }, - { - "path": "icon_sm.svg", - "sha256": "5407c6bf958a7d1c83a76440c8bb8e6508941cae9f9f319dfbb9c9250807f5e0", - "size": 724 - }, - { - "path": "icon_lg.svg", - "sha256": "1f9b3ec611c448eff1c4fb1844a948770f4c4aadf6b7e7a73d07fec738afe209", - "size": 739 - } - ], "tools": [ { "name": "resolve-library-id", @@ -892,6 +870,28 @@ "name": "query-docs", "display_name": "Query Docs" } + ], + "files": [ + { + "path": "connector.json", + "sha256": "2c0a92ece0fa0bb6d5e00d4db6f858d21a94bdf08b6043b93cffe372054e0100", + "size": 1279 + }, + { + "path": "icon_lg.svg", + "sha256": "1f9b3ec611c448eff1c4fb1844a948770f4c4aadf6b7e7a73d07fec738afe209", + "size": 739 + }, + { + "path": "icon_sm.svg", + "sha256": "5407c6bf958a7d1c83a76440c8bb8e6508941cae9f9f319dfbb9c9250807f5e0", + "size": 724 + }, + { + "path": "verify.py", + "sha256": "8e46d562c028c4f5370c22c7df455886836267cf4bbb8ac605c79a2b509fb5f1", + "size": 2094 + } ] }, { @@ -923,33 +923,6 @@ "version": 4, "version_string": "1.0.3", "version_release_date": "2026-07-22", - "files": [ - { - "path": "connector.json", - "sha256": "ec483834a2c6d090716be0ac0c55b328f46edca26c17c24c4b289279d6a3186d", - "size": 2444 - }, - { - "path": "gmaps_mcp_server.py", - "sha256": "98db82cc3f94d237c1675dbda97ec331d9b757f018c612b934a14c88143d9dd0", - "size": 30987 - }, - { - "path": "verify.py", - "sha256": "f566e0a0d297bf636d43e89c4b0085cdbd5322f6d353ea3552f37373e8612f55", - "size": 1903 - }, - { - "path": "icon_sm.svg", - "sha256": "796656d456681ef331ea9f3fa11419f37b8bb454ad7089de32f5583b2523abc4", - "size": 766 - }, - { - "path": "icon_lg.svg", - "sha256": "796656d456681ef331ea9f3fa11419f37b8bb454ad7089de32f5583b2523abc4", - "size": 766 - } - ], "tools": [ { "name": "status", @@ -975,9 +948,35 @@ "name": "distance_matrix", "display_name": "Distance Matrix" } + ], + "files": [ + { + "path": "connector.json", + "sha256": "ec483834a2c6d090716be0ac0c55b328f46edca26c17c24c4b289279d6a3186d", + "size": 2444 + }, + { + "path": "gmaps_mcp_server.py", + "sha256": "98db82cc3f94d237c1675dbda97ec331d9b757f018c612b934a14c88143d9dd0", + "size": 30987 + }, + { + "path": "icon_lg.svg", + "sha256": "796656d456681ef331ea9f3fa11419f37b8bb454ad7089de32f5583b2523abc4", + "size": 766 + }, + { + "path": "icon_sm.svg", + "sha256": "796656d456681ef331ea9f3fa11419f37b8bb454ad7089de32f5583b2523abc4", + "size": 766 + }, + { + "path": "verify.py", + "sha256": "f566e0a0d297bf636d43e89c4b0085cdbd5322f6d353ea3552f37373e8612f55", + "size": 1903 + } ] }, - { "id": "google-trends", "name": "Google Trends", @@ -985,7 +984,7 @@ "scope": "global", "icon_small": "google-trends/icon_sm.png", "icon_large": "google-trends/icon_lg.png", - "user_description": "Current trending topics by country, keyword search interest history, related queries, and regional interest maps. Powered by trendspyg — no API key required.", + "user_description": "Current trending topics by country, keyword search interest history, related queries, and regional interest maps. Powered by trendspyg \u2014 no API key required.", "requires": [ "PYTHON" ], @@ -1004,14 +1003,6 @@ "version": 1, "version_string": "1.0.0", "version_release_date": "2026-07-22", - "files": [ - {"path": "google_trends_mcp.py", "sha256": "5404eb7c81e82180a3b9e3052a4793e80a361ae60156d598d8e62e36b21dea8a", "size": 13552}, - {"path": "connector.json", "sha256": "0f50383fa3d664e6f487983645c56a57a076353a8fea337d121826210ebd3a8a", "size": 1191}, - {"path": "verify.py", "sha256": "adbae57fc109c06c5d61ff50b67faaf62e1fa493a18cbfdacbc73f24d51ba9b8", "size": 831}, - {"path": "requirements.txt", "sha256": "8b13038b5c79cff2680a9b482491b969ac83ce4efa396f408bfca97385d00621", "size": 17}, - {"path": "icon_sm.png", "sha256": "e7b9a8ba97f824948dae572db069296bbf81bef84007d1e18c0fd598b0a05232", "size": 2304}, - {"path": "icon_lg.png", "sha256": "636d2982098c862a04099aea01d7f7ca7a9ad258dafed286baa08864480eacad", "size": 4664} - ], "tools": [ { "name": "status", @@ -1029,6 +1020,38 @@ "name": "explore", "display_name": "Explore Keyword" } + ], + "files": [ + { + "path": "connector.json", + "sha256": "0f50383fa3d664e6f487983645c56a57a076353a8fea337d121826210ebd3a8a", + "size": 1191 + }, + { + "path": "google_trends_mcp.py", + "sha256": "5404eb7c81e82180a3b9e3052a4793e80a361ae60156d598d8e62e36b21dea8a", + "size": 13552 + }, + { + "path": "icon_lg.png", + "sha256": "636d2982098c862a04099aea01d7f7ca7a9ad258dafed286baa08864480eacad", + "size": 4664 + }, + { + "path": "icon_sm.png", + "sha256": "e7b9a8ba97f824948dae572db069296bbf81bef84007d1e18c0fd598b0a05232", + "size": 2304 + }, + { + "path": "requirements.txt", + "sha256": "8b13038b5c79cff2680a9b482491b969ac83ce4efa396f408bfca97385d00621", + "size": 17 + }, + { + "path": "verify.py", + "sha256": "adbae57fc109c06c5d61ff50b67faaf62e1fa493a18cbfdacbc73f24d51ba9b8", + "size": 831 + } ] } ] diff --git a/connectors/context7/fragment.json b/connectors/context7/fragment.json new file mode 100644 index 0000000..278293e --- /dev/null +++ b/connectors/context7/fragment.json @@ -0,0 +1,33 @@ +{ + "id": "context7", + "name": "Context7", + "type": "mcp_remote", + "scope": "global", + "icon_small": "context7/icon_sm.svg", + "icon_large": "context7/icon_lg.svg", + "user_description": "Up-to-date documentation and code examples for any library, framework, SDK, API, CLI tool, or cloud service \u2014 fetched directly from the source. Free, no API key required.", + "tags": [ + "documentation", + "search", + "mcp", + "remote", + "developer-tools" + ], + "auth": { + "type": "none" + }, + "folder": "context7", + "version": 3, + "version_string": "1.0.2", + "version_release_date": "2026-07-22", + "tools": [ + { + "name": "resolve-library-id", + "display_name": "Resolve Library" + }, + { + "name": "query-docs", + "display_name": "Query Docs" + } + ] +} \ No newline at end of file diff --git a/connectors/drive/fragment.json b/connectors/drive/fragment.json new file mode 100644 index 0000000..6f59e58 --- /dev/null +++ b/connectors/drive/fragment.json @@ -0,0 +1,32 @@ +{ + "id": "drive", + "name": "Google Drive", + "type": "mcp_local", + "scope": "user", + "icon_small": "drive/icon_sm.png", + "icon_large": "drive/icon_lg.png", + "user_description": "List, search, upload, download, delete, and manage Google Drive files and folders. Full OAuth \u2014 same pattern as Gmail and Google Calendar.", + "requires": [ + "OAUTH", + "PYTHON" + ], + "tags": [ + "cloud-storage", + "files", + "mcp", + "local", + "google", + "drive" + ], + "auth": { + "type": "oauth2", + "provider": "google", + "scopes": [ + "https://www.googleapis.com/auth/drive" + ] + }, + "folder": "drive", + "version": 7, + "version_string": "1.0.6", + "version_release_date": "2026-07-22" +} \ No newline at end of file diff --git a/connectors/email/fragment.json b/connectors/email/fragment.json new file mode 100644 index 0000000..e0fc333 --- /dev/null +++ b/connectors/email/fragment.json @@ -0,0 +1,26 @@ +{ + "id": "email", + "name": "Email (IMAP/SMTP)", + "type": "mcp_local", + "scope": "user", + "icon_small": "email/icon_sm.svg", + "icon_large": "email/icon_lg.svg", + "user_description": "Read, search, organize, and send email over IMAP/SMTP \u2014 any provider, no OAuth. Real-time push notifications on new mail.", + "requires": [ + "PYTHON" + ], + "tags": [ + "email", + "mcp", + "local", + "imap", + "smtp" + ], + "auth": { + "type": "password" + }, + "folder": "email", + "version": 5, + "version_string": "1.0.4", + "version_release_date": "2026-07-21" +} \ No newline at end of file diff --git a/connectors/exa/fragment.json b/connectors/exa/fragment.json new file mode 100644 index 0000000..cb9606e --- /dev/null +++ b/connectors/exa/fragment.json @@ -0,0 +1,32 @@ +{ + "id": "exa", + "name": "Exa", + "type": "mcp_remote", + "scope": "global", + "icon_small": "exa/icon_sm.png", + "icon_large": "exa/icon_lg.png", + "user_description": "AI-powered web search, content extraction, and research via Exa's neural search engine. Works without an API key (free rate-limited tier).", + "tags": [ + "search", + "mcp", + "remote", + "ai" + ], + "auth": { + "type": "api_key" + }, + "folder": "exa", + "version": 4, + "version_string": "1.0.3", + "version_release_date": "2026-07-21", + "tools": [ + { + "name": "web_search_exa", + "display_name": "Web Search" + }, + { + "name": "web_fetch_exa", + "display_name": "Web Fetch" + } + ] +} \ No newline at end of file diff --git a/connectors/firecrawl/fragment.json b/connectors/firecrawl/fragment.json new file mode 100644 index 0000000..8bd5f60 --- /dev/null +++ b/connectors/firecrawl/fragment.json @@ -0,0 +1,134 @@ +{ + "id": "firecrawl", + "name": "Firecrawl", + "type": "mcp_local", + "scope": "global", + "icon_small": "firecrawl/icon_sm.png", + "icon_large": "firecrawl/icon_lg.png", + "user_description": "Web scraping, crawling, search, deep research, and autonomous browsing \u2014 extract content from any website.", + "requires": [ + "NODE" + ], + "tags": [ + "scraping", + "crawling", + "search", + "mcp", + "local", + "browser", + "research" + ], + "auth": { + "type": "api_key" + }, + "folder": "firecrawl", + "version": 4, + "version_string": "1.0.3", + "version_release_date": "2026-07-21", + "tools": [ + { + "name": "firecrawl_scrape", + "display_name": "Scrape URL" + }, + { + "name": "firecrawl_map", + "display_name": "Map Site" + }, + { + "name": "firecrawl_search", + "display_name": "Web Search" + }, + { + "name": "firecrawl_search_feedback", + "display_name": "Search Feedback" + }, + { + "name": "firecrawl_feedback", + "display_name": "Feedback" + }, + { + "name": "firecrawl_crawl", + "display_name": "Crawl Site" + }, + { + "name": "firecrawl_check_crawl_status", + "display_name": "Check Crawl Status" + }, + { + "name": "firecrawl_extract", + "display_name": "Extract Data" + }, + { + "name": "firecrawl_agent", + "display_name": "Research Agent" + }, + { + "name": "firecrawl_agent_status", + "display_name": "Agent Status" + }, + { + "name": "firecrawl_interact", + "display_name": "Interact with Page" + }, + { + "name": "firecrawl_interact_stop", + "display_name": "Stop Interact" + }, + { + "name": "firecrawl_parse", + "display_name": "Parse" + }, + { + "name": "firecrawl_monitor_create", + "display_name": "Create Monitor" + }, + { + "name": "firecrawl_monitor_list", + "display_name": "List Monitors" + }, + { + "name": "firecrawl_monitor_get", + "display_name": "Get Monitor" + }, + { + "name": "firecrawl_monitor_update", + "display_name": "Update Monitor" + }, + { + "name": "firecrawl_monitor_delete", + "display_name": "Delete Monitor" + }, + { + "name": "firecrawl_monitor_run", + "display_name": "Run Monitor" + }, + { + "name": "firecrawl_monitor_checks", + "display_name": "List Checks" + }, + { + "name": "firecrawl_monitor_check", + "display_name": "Get Check" + }, + { + "name": "firecrawl_research_search_papers", + "display_name": "Search Papers" + }, + { + "name": "firecrawl_research_inspect_paper", + "display_name": "Inspect Paper" + }, + { + "name": "firecrawl_research_related_papers", + "display_name": "Related Papers" + }, + { + "name": "firecrawl_research_read_paper", + "display_name": "Read Paper" + }, + { + "name": "firecrawl_research_search_github", + "display_name": "Search GitHub" + } + ] +} \ No newline at end of file diff --git a/connectors/gcal/fragment.json b/connectors/gcal/fragment.json new file mode 100644 index 0000000..989f803 --- /dev/null +++ b/connectors/gcal/fragment.json @@ -0,0 +1,30 @@ +{ + "id": "gcal", + "name": "Google Calendar", + "type": "mcp_local", + "scope": "user", + "icon_small": "gcal/icon_sm.svg", + "icon_large": "gcal/icon_lg.svg", + "user_description": "Read, create, update, delete, and respond to Google Calendar events \u2014 full CRUD with push notifications.", + "requires": [ + "OAUTH", + "PYTHON" + ], + "tags": [ + "calendar", + "mcp", + "local", + "google" + ], + "auth": { + "type": "oauth2", + "provider": "google", + "scopes": [ + "https://www.googleapis.com/auth/calendar" + ] + }, + "folder": "gcal", + "version": 5, + "version_string": "0.3.4", + "version_release_date": "2026-07-21" +} \ No newline at end of file diff --git a/connectors/gmail/fragment.json b/connectors/gmail/fragment.json new file mode 100644 index 0000000..9068e25 --- /dev/null +++ b/connectors/gmail/fragment.json @@ -0,0 +1,31 @@ +{ + "id": "gmail", + "name": "Gmail", + "type": "mcp_local", + "scope": "user", + "icon_small": "gmail/icon_sm.svg", + "icon_large": "gmail/icon_lg.svg", + "user_description": "Read, send, and manage Gmail emails via OAuth \u2014 full MCP integration with push notifications.", + "requires": [ + "OAUTH", + "PYTHON" + ], + "tags": [ + "email", + "mcp", + "local", + "google" + ], + "auth": { + "type": "oauth2", + "provider": "google", + "scopes": [ + "https://www.googleapis.com/auth/gmail.modify", + "https://www.googleapis.com/auth/gmail.labels" + ] + }, + "folder": "gmail", + "version": 6, + "version_string": "1.0.5", + "version_release_date": "2026-07-22" +} \ No newline at end of file diff --git a/connectors/gmaps/fragment.json b/connectors/gmaps/fragment.json new file mode 100644 index 0000000..f6a4bf7 --- /dev/null +++ b/connectors/gmaps/fragment.json @@ -0,0 +1,56 @@ +{ + "id": "gmaps", + "name": "Google Maps", + "type": "mcp_local", + "scope": "global", + "icon_small": "gmaps/icon_sm.svg", + "icon_large": "gmaps/icon_lg.svg", + "user_description": "Get transit, driving, walking and cycling directions, geocode addresses, search nearby places, and compute distance matrices \u2014 powered by Google Maps Platform.", + "requires": [ + "PYTHON", + "ENV" + ], + "tags": [ + "maps", + "mcp", + "local", + "google", + "navigation", + "transit" + ], + "auth": { + "type": "api_key", + "delivery": "env", + "param": "GOOGLE_MAPS_API_KEY" + }, + "folder": "gmaps", + "version": 4, + "version_string": "1.0.3", + "version_release_date": "2026-07-22", + "tools": [ + { + "name": "status", + "display_name": "Status Check" + }, + { + "name": "directions", + "display_name": "Directions" + }, + { + "name": "geocode", + "display_name": "Geocode" + }, + { + "name": "reverse_geocode", + "display_name": "Reverse Geocode" + }, + { + "name": "search_places", + "display_name": "Search Places" + }, + { + "name": "distance_matrix", + "display_name": "Distance Matrix" + } + ] +} \ No newline at end of file diff --git a/connectors/google-trends/fragment.json b/connectors/google-trends/fragment.json new file mode 100644 index 0000000..9b8c5a0 --- /dev/null +++ b/connectors/google-trends/fragment.json @@ -0,0 +1,45 @@ +{ + "id": "google-trends", + "name": "Google Trends", + "type": "mcp_local", + "scope": "global", + "icon_small": "google-trends/icon_sm.png", + "icon_large": "google-trends/icon_lg.png", + "user_description": "Current trending topics by country, keyword search interest history, related queries, and regional interest maps. Powered by trendspyg \u2014 no API key required.", + "requires": [ + "PYTHON" + ], + "tags": [ + "trends", + "mcp", + "local", + "google", + "search", + "analytics" + ], + "auth": { + "type": "none" + }, + "folder": "google-trends", + "version": 1, + "version_string": "1.0.0", + "version_release_date": "2026-07-22", + "tools": [ + { + "name": "status", + "display_name": "Status Check" + }, + { + "name": "get_trending", + "display_name": "Get Trending Topics" + }, + { + "name": "get_interest_over_time", + "display_name": "Interest Over Time" + }, + { + "name": "explore", + "display_name": "Explore Keyword" + } + ] +} \ No newline at end of file diff --git a/connectors/http-fetch/fragment.json b/connectors/http-fetch/fragment.json new file mode 100644 index 0000000..361f2c3 --- /dev/null +++ b/connectors/http-fetch/fragment.json @@ -0,0 +1,54 @@ +{ + "id": "http-fetch", + "name": "HTTP Fetch", + "type": "mcp_local", + "scope": "global", + "icon_small": "http-fetch/icon_sm.svg", + "icon_large": "http-fetch/icon_lg.svg", + "user_description": "Fetch any URL as HTML, Markdown, text, JSON, or YouTube transcripts \u2014 free, no API key, no rate limits.", + "requires": [ + "NODE" + ], + "tags": [ + "http", + "fetch", + "mcp", + "local", + "free", + "scraping", + "youtube" + ], + "auth": { + "type": "none" + }, + "folder": "http-fetch", + "version": 4, + "version_string": "1.0.3", + "version_release_date": "2026-07-21", + "tools": [ + { + "name": "fetch_html", + "display_name": "Fetch as HTML" + }, + { + "name": "fetch_markdown", + "display_name": "Fetch as Markdown" + }, + { + "name": "fetch_txt", + "display_name": "Fetch as Text" + }, + { + "name": "fetch_json", + "display_name": "Fetch as JSON" + }, + { + "name": "fetch_readable", + "display_name": "Fetch Readable Content" + }, + { + "name": "fetch_youtube_transcript", + "display_name": "Get YouTube Transcript" + } + ] +} \ No newline at end of file diff --git a/connectors/index.json b/connectors/index.json new file mode 100644 index 0000000..9f06ed2 --- /dev/null +++ b/connectors/index.json @@ -0,0 +1 @@ +["gmail", "gcal", "drive", "email", "exa", "firecrawl", "http-fetch", "serpapi-flights", "ssh", "tavily", "weather", "whatsapp", "wikipedia", "context7", "gmaps", "google-trends"] diff --git a/connectors/serpapi-flights/fragment.json b/connectors/serpapi-flights/fragment.json new file mode 100644 index 0000000..8af2790 --- /dev/null +++ b/connectors/serpapi-flights/fragment.json @@ -0,0 +1,29 @@ +{ + "id": "serpapi-flights", + "name": "SerpAPI Flights", + "type": "mcp_remote", + "scope": "global", + "icon_small": "serpapi-flights/icon_sm.svg", + "icon_large": "serpapi-flights/icon_lg.svg", + "user_description": "Search and compare flights, lookup airport codes, and explore routes via SerpAPI\u2019s Google Flights integration.", + "tags": [ + "flights", + "travel", + "mcp", + "remote", + "search" + ], + "auth": { + "type": "api_key" + }, + "folder": "serpapi-flights", + "version": 4, + "version_string": "1.0.3", + "version_release_date": "2026-07-21", + "tools": [ + { + "name": "serpapi_search_flights", + "display_name": "Search Flights" + } + ] +} \ No newline at end of file diff --git a/connectors/ssh/fragment.json b/connectors/ssh/fragment.json new file mode 100644 index 0000000..b5be722 --- /dev/null +++ b/connectors/ssh/fragment.json @@ -0,0 +1,27 @@ +{ + "id": "ssh", + "name": "SSH Remote Access", + "type": "mcp_local", + "scope": "user", + "icon_small": "ssh/icon_sm.svg", + "icon_large": "ssh/icon_lg.svg", + "user_description": "Full SSH remote server access \u2014 files, commands, systemd, upload/download. Aliases manage host config; auth via key/agent or elicited password.", + "requires": [ + "PYTHON" + ], + "tags": [ + "ssh", + "mcp", + "local", + "remote", + "server", + "sysadmin" + ], + "auth": { + "type": "none" + }, + "folder": "ssh", + "version": 5, + "version_string": "1.0.4", + "version_release_date": "2026-07-21" +} \ No newline at end of file diff --git a/connectors/tavily/fragment.json b/connectors/tavily/fragment.json new file mode 100644 index 0000000..1327907 --- /dev/null +++ b/connectors/tavily/fragment.json @@ -0,0 +1,43 @@ +{ + "id": "tavily", + "name": "Tavily", + "type": "mcp_remote", + "scope": "global", + "icon_small": "tavily/icon_sm.png", + "icon_large": "tavily/icon_lg.png", + "user_description": "Web search API for LLMs \u2014 real-time results, news, and content extraction.", + "tags": [ + "search", + "mcp", + "remote" + ], + "auth": { + "type": "api_key" + }, + "folder": "tavily", + "version": 5, + "version_string": "1.0.4", + "version_release_date": "2026-07-22", + "tools": [ + { + "name": "tavily_search", + "display_name": "Web Search" + }, + { + "name": "tavily_extract", + "display_name": "Extract Content" + }, + { + "name": "tavily_crawl", + "display_name": "Crawl Site" + }, + { + "name": "tavily_map", + "display_name": "Map Site" + }, + { + "name": "tavily_research", + "display_name": "Deep Research" + } + ] +} \ No newline at end of file diff --git a/connectors/weather/fragment.json b/connectors/weather/fragment.json new file mode 100644 index 0000000..05b1e23 --- /dev/null +++ b/connectors/weather/fragment.json @@ -0,0 +1,24 @@ +{ + "id": "weather", + "name": "Weather (Open-Meteo)", + "type": "mcp_local", + "scope": "global", + "icon_small": "weather/icon_sm.svg", + "icon_large": "weather/icon_lg.svg", + "user_description": "Global weather, forecast, and air quality via Open-Meteo \u2014 free, no API key required.", + "tags": [ + "weather", + "mcp", + "local", + "free", + "forecast", + "air-quality" + ], + "auth": { + "type": "none" + }, + "folder": "weather", + "version": 7, + "version_string": "3.0.4", + "version_release_date": "2026-07-21" +} \ No newline at end of file diff --git a/connectors/whatsapp/fragment.json b/connectors/whatsapp/fragment.json new file mode 100644 index 0000000..7ac4fe0 --- /dev/null +++ b/connectors/whatsapp/fragment.json @@ -0,0 +1,26 @@ +{ + "id": "whatsapp", + "name": "WhatsApp", + "type": "mcp_local", + "scope": "user", + "icon_small": "whatsapp/icon_sm.png", + "icon_large": "whatsapp/icon_lg.png", + "user_description": "Send and read WhatsApp messages from your own linked account. Link via QR code \u2014 no browser needed.", + "requires": [ + "NODE" + ], + "tags": [ + "messaging", + "mcp", + "local", + "whatsapp", + "qr" + ], + "auth": { + "type": "qr" + }, + "folder": "whatsapp", + "version": 6, + "version_string": "2.0.6", + "version_release_date": "2026-07-21" +} \ No newline at end of file diff --git a/connectors/wikipedia/fragment.json b/connectors/wikipedia/fragment.json new file mode 100644 index 0000000..b00a039 --- /dev/null +++ b/connectors/wikipedia/fragment.json @@ -0,0 +1,24 @@ +{ + "id": "wikipedia", + "name": "Wikipedia", + "type": "mcp_local", + "scope": "global", + "icon_small": "wikipedia/icon_sm.svg", + "icon_large": "wikipedia/icon_lg.svg", + "user_description": "Search and read Wikipedia articles \u2014 free, no API key required.", + "tags": [ + "wikipedia", + "mcp", + "local", + "free", + "reference", + "research" + ], + "auth": { + "type": "none" + }, + "folder": "wikipedia", + "version": 7, + "version_string": "3.0.4", + "version_release_date": "2026-07-21" +} \ No newline at end of file diff --git a/scripts/compile.py b/scripts/compile.py new file mode 100644 index 0000000..777251c --- /dev/null +++ b/scripts/compile.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +"""Compile connectors/index.json + fragment.json + file hash scan → connectors.json + +Usage: + python3 scripts/compile.py # scrive connectors/connectors.json + python3 scripts/compile.py --verify # verifica che l'indice esistente sia aggiornato + +Legge: + - connectors/index.json — lista ordinata di id folder + - connectors//fragment.json — entry dell'indice senza files[] + - scansione fisica dei file — SHA-256 e size di ogni file nella cartella + +Produce: + - connectors/connectors.json — indice completo con files[] e SHA-256 + +Esclusioni automatiche: fragment.json, connector.json, compile.sh, compile.py, +update_hashes.py, e l'intera directory scripts/. +""" + +from __future__ import annotations + +import hashlib +import json +import os +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +INDEX_DIR = os.path.join(ROOT, "connectors") + +EXCLUDE_FILES = { + "fragment.json", + "connectors.json", + "index.json", + "compile.sh", + "compile.py", + "update_hashes.py", + ".DS_Store", +} + +EXCLUDE_DIRS = {"scripts", "__pycache__", ".git"} + + +def scan_files(folder_path: str) -> list[dict]: + """Scan all files in folder_path, return [{path, sha256, size}, ...] sorted.""" + files = [] + for fname in sorted(os.listdir(folder_path)): + fpath = os.path.join(folder_path, fname) + if os.path.isdir(fpath): + continue + if fname in EXCLUDE_FILES: + continue + with open(fpath, "rb") as f: + data = f.read() + files.append({ + "path": fname, + "sha256": hashlib.sha256(data).hexdigest(), + "size": len(data), + }) + return files + + +def compile_index() -> list[dict]: + """Build the connectors list from index.json + fragments + file scan.""" + index_path = os.path.join(INDEX_DIR, "index.json") + if not os.path.exists(index_path): + print("❌ connectors/index.json not found. Create it first.", file=sys.stderr) + sys.exit(1) + + with open(index_path) as f: + order: list[str] = json.load(f) + + connectors = [] + for i, connector_id in enumerate(order): + frag_path = os.path.join(INDEX_DIR, connector_id, "fragment.json") + if not os.path.exists(frag_path): + print( + f"⚠️ [{i+1}/{len(order)}] {connector_id} — fragment.json not found, skipping.", + file=sys.stderr, + ) + continue + + with open(frag_path) as f: + fragment: dict = json.load(f) + + folder_path = os.path.join(INDEX_DIR, connector_id) + files = scan_files(folder_path) + fragment["files"] = files + + n_files = len(files) + print(f"✓ [{i+1}/{len(order)}] {connector_id} — {n_files} file{'s' if n_files != 1 else ''}") + connectors.append(fragment) + + return connectors + + +def write_index(connectors: list[dict]) -> None: + """Write the compiled connectors.json.""" + output = {"version": 1, "connectors": connectors} + out_path = os.path.join(INDEX_DIR, "connectors.json") + with open(out_path, "w") as f: + json.dump(output, f, indent=2) + f.write("\n") + print(f"\n✅ Scritto {out_path} ({len(connectors)} connector)") + + +def verify_index() -> bool: + """Verify existing connectors.json matches what compilation would produce.""" + with open(os.path.join(INDEX_DIR, "connectors.json")) as f: + current = json.load(f) + + fresh = compile_index() + + if current["connectors"] == fresh: + print("✅ L'indice è aggiornato — nessuna modifica.") + return True + else: + print("❌ L'indice NON è aggiornato. Esegui compile.py per rigenerarlo.") + return False + + +def main() -> None: + if "--verify" in sys.argv: + sys.exit(0 if verify_index() else 1) + + connectors = compile_index() + write_index(connectors) + + +if __name__ == "__main__": + main()