feat(mcp): align runtime home and knowledge base tooling

This commit is contained in:
Clément SAILLANT
2026-03-08 19:41:26 +01:00
parent f1cd267164
commit bd49fc628f
28 changed files with 697 additions and 363 deletions
+1 -1
View File
@@ -73,7 +73,7 @@ Les checks dependants du mirror specs ou des runtimes MCP restent des commandes
Options utiles:
- `--suite stable` pour le chemin repo-local supporte par defaut
- `--suite mcp` pour les tests MCP locaux (`notion`, `github-dispatch`, `nexar`)
- `--suite mcp` pour les tests MCP locaux (`knowledge-base`, `github-dispatch`, `nexar`)
- `--suite all` pour enchainer les deux
- `--bootstrap` pour creer le venv cible avant de lancer les tests
- `--list` pour afficher exactement les commandes couvertes
+3 -1
View File
@@ -13,9 +13,11 @@ Le fichier `constraints.yaml` est la **source de verite** des contraintes non-fo
Specs complementaires:
- `github_mcp_conversion_spec.md`: prep de conversion de `workflow_dispatch` vers une surface MCP future.
- `cad_modeling_tasks.md`: backlog canonique `FreeCAD/OpenSCAD` pour la stack CAD locale hors MCP.
- `kicad_mcp_scope_spec.md`: perimetre fonctionnel, hors scope et criteres d'acceptation du MCP KiCad supporte.
- `mcp_agentics_target_backlog.md`: backlog cible 2026 -> 2028 pour `MCP`, `agentics`, `A2A`, avec ownership par repo.
- `mcp_tasks.md`: backlog canonique des actions MCP locales, partage entre runtime, doc et gouvernance.
- `notion_mcp_conversion_spec.md`: prep de conversion du bridge Notion actuel vers une surface MCP future.
- `knowledge_base_mcp_spec.md`: spec canonique du bridge et du MCP knowledge base (`memos` / `docmost`).
- `zeroclaw_dual_hw_orchestration_spec.md`: architecture d'orchestration ZeroClaw multi-repo + double materiel.
- `zeroclaw_dual_hw_todo.md`: backlog operationnel court terme pour autonomie controlee.
@@ -0,0 +1,61 @@
# Spec MCP Knowledge Base
Last updated: 2026-03-08
## Objectif
Documenter l'implementation MCP `knowledge-base` a partir du bridge knowledge base actuel, avec uniquement `memos` et `docmost` dans la pile supportee.
## Etat actuel
- backend reel dans `mascarade/core/mascarade/integrations/knowledge_base.py`
- bridge HTTP canonique dans `mascarade/api/src/routes/knowledgeBase.ts`
- UI consommatrice dans `mascarade/web/src/pages/KnowledgeBrowser.tsx` et `crazy_life/src/pages/KnowledgeBrowser.tsx`
- providers supportes:
- `memos`
- `docmost`
## Surface MCP implemente
Serveur MCP `knowledge-base` local avec les outils:
- `search_pages`
- `read_page`
- `append_to_page`
- `create_page`
## Mapping depuis l'existant
- `GET /api/knowledge-base/search` -> `search_pages`
- `GET /api/knowledge-base/pages/:pageId` -> `read_page`
- `POST /api/knowledge-base/pages/:pageId/append` -> `append_to_page`
- `POST /api/knowledge-base/pages` -> `create_page`
## Contraintes
- garder `stdio` comme transport par defaut
- ne pas exposer un MCP reseau en v1
- garder le bridge HTTP canonique tant que les clients UI le consomment
- launcher operateur: `tools/run_knowledge_base_mcp.sh`
- erreurs explicites si le provider actif n'est pas configure
## Providers supportes
- `memos`
- prerequis: `MEMOS_BASE_URL`, `MEMOS_ACCESS_TOKEN`
- `docmost`
- prerequis: `DOCMOST_BASE_URL`, `DOCMOST_EMAIL`, `DOCMOST_PASSWORD`
## Hors scope v1
- ajout d'un troisieme provider non qualifie
- suppression du bridge HTTP canonique
- edition riche avancee ou blocs proprietaires
- sync bidirectionnelle UI <-> MCP hors actions explicites
## Validation minimale
- handshake `initialize -> tools/list` vert
- `search_pages` et `read_page` smokees sur le provider actif
- erreur structuree et non ambigue si le provider actif n'est pas configure
- documentation operateur et matrice de support mises a jour
+32 -5
View File
@@ -1,6 +1,6 @@
# Tasks MCP local
Last updated: 2026-03-07
Last updated: 2026-03-08
Backlog MCP canonique pour `Kill_LIFE`.
@@ -17,6 +17,14 @@ Format:
## État courant
- Etat agrege courant:
- `kicad`, `validate-specs` et `huggingface` sont `ready`
- `knowledge-base` est `ready` sur le provider actif `memos`, avec smoke live valide
- `github-dispatch` est `ready`, avec smoke live valide via token GitHub persiste
- le backlog MCP restant est limite a deux blocages specialises constates sur cette machine:
- `K-012`: `pcbnew` absent sur l'hote, donc validation host-native impossible ici
- `K-014`: `NEXAR_TOKEN` absent, donc `nexar_api` reste en mode demo
- [x] K-001 — Rendre `validate-specs` réel
- AC: `mcp.json` ne référence plus de chemin absent.
@@ -55,6 +63,9 @@ Format:
- [ ] K-012 — Rejouer la validation host-native sur une machine avec `pcbnew`
- AC: le smoke passe aussi sur le chemin hote, pas seulement via le fallback conteneur.
- Helper pret: `python3 tools/hw/kicad_host_mcp_smoke.py --json --quick` degrade proprement si `pcbnew` est absent.
- Derniere verification: `2026-03-08` sur cette machine -> `blocked by host environment`
- Evidence: `python3 tools/hw/kicad_host_mcp_smoke.py --json --quick`
- Resultat: `{"status":"degraded","host_pcbnew_import":"missing","error":"pcbnew not importable on host runtime"}`
- [x] K-013 — Décider du statut final des micro-serveurs `kicad_kic_ai`
- AC: `component_database`, `kicad_tools` et `nexar_api` sont explicitement promus en surfaces auxiliaires supportées.
@@ -62,18 +73,22 @@ Format:
- [ ] K-014 — Valider le mode live de `nexar_api`
- AC: un run avec `NEXAR_TOKEN` confirme le comportement reel et le distingue du mode demo.
- Helper pret: `python3 tools/nexar_mcp_smoke.py --json --live` degrade ou echoue proprement tant que le token ou le mode live manquent.
- Derniere verification: `2026-03-08` sur cette machine -> `blocked by secret/env`
- Evidence: `python3 tools/nexar_mcp_smoke.py --json --live`
- Resultat: `{"status":"degraded","token_configured":false,"demo_mode":true,"error":"NEXAR token missing or server running in demo mode"}`
- [x] K-015 — Implémenter le MCP `Notion`
- AC: `tools/run_notion_mcp.sh` expose `search_pages`, `read_page`, `append_to_page`, `create_page` sans retirer le bridge HTTP en V1.
- [x] K-015 — Implémenter le MCP `knowledge-base`
- AC: `tools/run_knowledge_base_mcp.sh` expose `search_pages`, `read_page`, `append_to_page`, `create_page` sans retirer le bridge HTTP en V1.
- Resultat: le serveur `knowledge-base` est maintenant un MCP de compat vers `KNOWLEDGE_BASE_PROVIDER=memos|docmost`.
- [x] K-016 — Implémenter le MCP `GitHub dispatch`
- AC: `tools/run_github_dispatch_mcp.sh` expose `list_allowlisted_workflows`, `dispatch_workflow` et `get_dispatch_status` sans retirer la voie API actuelle en V1.
- [x] K-017 — Ajouter des smokes MCP dedies hors KiCad
- AC: `validate-specs`, `notion` et `github-dispatch` ont chacun un smoke versionne avec sortie JSON.
- AC: `validate-specs`, `knowledge-base` et `github-dispatch` ont chacun un smoke versionne avec sortie JSON.
- [x] K-018 — Etendre l'observabilite MCP a plusieurs serveurs
- AC: `/api/ops/summary` expose un etat agrege et le detail par serveur pour `kicad`, `validate-specs`, `notion` et `github-dispatch`.
- AC: `/api/ops/summary` expose un etat agrege et le detail par serveur pour `kicad`, `validate-specs`, `knowledge-base`, `github-dispatch`, `freecad` et `openscad`.
- [x] K-019 — Ajouter un helper de readiness host-native KiCad
- AC: `python3 tools/hw/kicad_host_mcp_smoke.py --json --quick` retourne `ready` ou `degraded` sans ambiguite.
@@ -83,3 +98,15 @@ Format:
- [x] K-021 — Ajouter un rapport MCP local synthetique
- AC: `python3 tools/mcp_runtime_status.py --json` agrege les smokes supportes et rend visibles les blocages K-012/K-014.
- [x] K-022 — Valider la knowledge base active en live via le MCP `knowledge-base`
- AC: un run avec le provider actif et sa cible de smoke confirme `search_pages` et `read_page`.
- Resultat: validation live fermee sur le provider actif `memos` auto-heberge, avec `python3 tools/knowledge_base_mcp_smoke.py --json` en `ready`.
- Variantes supportees:
- `memos`: `MEMOS_BASE_URL` + `MEMOS_ACCESS_TOKEN` + `KNOWLEDGE_BASE_SMOKE_PAGE_ID` optionnel
- `docmost`: `DOCMOST_BASE_URL` + `DOCMOST_EMAIL` + `DOCMOST_PASSWORD` + `KNOWLEDGE_BASE_SMOKE_PAGE_ID`
- [x] K-023 — Valider `GitHub dispatch MCP` en live
- AC: un run avec `KILL_LIFE_GITHUB_TOKEN` ou un `GitHub App` valide confirme `list_allowlisted_workflows` et `dispatch_workflow` sur une cible autorisee.
- Resultat: validation live fermee via token GitHub persiste dans `runtime-secrets`; le smoke versionne confirme `list_allowlisted_workflows`, `dispatch_workflow` et `get_dispatch_status`.
- Evidence: `python3 tools/github_dispatch_mcp_smoke.py --json --live`
@@ -1,51 +0,0 @@
# Spec conversion MCP Notion
Last updated: 2026-03-07
## Objectif
Documenter l'implémentation MCP `notion` à partir de l'intégration `Notion` existante, sans remplacer la voie HTTP existante en V1.
## État actuel
- backend réel dans `mascarade/core/mascarade/integrations/notion.py`
- bridge HTTP existant dans `mascarade/api/src/routes/notion.ts`
- UI consommatrice existante dans `crazy_life/src/pages/NotionBrowser.tsx`
- dépendance secrète: `NOTION_API_KEY`
## Surface MCP implémentée
Serveur MCP `notion` local avec les outils:
- `search_pages`
- `read_page`
- `append_to_page`
- `create_page`
## Mapping depuis l'existant
- `GET /api/notion/search` -> `search_pages`
- `GET /api/notion/pages/:pageId` -> `read_page`
- `POST /api/notion/pages/:pageId/append` -> `append_to_page`
- `POST /api/notion/pages` -> `create_page`
## Contraintes
- garder `stdio` comme transport par défaut
- ne pas exposer un MCP réseau en V1
- erreurs explicites si `NOTION_API_KEY` absent
- conserver le bridge HTTP existant tant que la migration client n'est pas faite
- launcher opérateur: `tools/run_notion_mcp.sh`
## Hors scope V1
- suppression du bridge HTTP existant
- édition riche avancée ou gestion fine des blocs Notion
- sync bidirectionnelle UI <-> MCP
## Validation minimale
- handshake `initialize -> tools/list` vert
- `search_pages` et `read_page` smokés
- erreur structurée et non ambiguë si `NOTION_API_KEY` absent
- documentation opérateur et matrice de support mises à jour
@@ -64,6 +64,7 @@ Last updated: 2026-02-21
- [x] I-203 - Add local docker compose stack for n8n (`5678`).
- [x] I-204 - Add runtime scripts (`integrations_up/down/status`, `import_n8n`).
- [ ] I-205 - Validate end-to-end import + activation on local Docker runtime.
- status: Deferred (post-stabilization)
- command: `tools/ai/zeroclaw_integrations_up.sh`
- command: `tools/ai/zeroclaw_integrations_status.sh`
- command: `tools/ai/zeroclaw_integrations_import_n8n.sh`
+112 -56
View File
@@ -1,15 +1,19 @@
# Local Change Bundles — 2026-03-08
But: reduire la derive locale de `Kill_LIFE` en regroupant le worktree en lots revus/publies par sujet.
But: sortir le worktree `Kill_LIFE` en lots publiables reellement alignes sur
le delta courant, et non plus seulement "reviewables par sujet".
## Etat courant
Le worktree local n'est plus un melange de dizaines de sujets heterogenes. Il se lit maintenant en `2` lots principaux:
Le delta `Kill_LIFE` se lit maintenant en `3` lots publiables plus un reliquat
runtime local non versionnable:
1. `mcp-runtime`
2. `python-local`
2. `cad-mcp`
3. `python-local`
4. `.mascarade/` = runtime local genere, a exclure des commits
Le helper de revue associe est:
Le helper de revue associe reste:
```bash
bash tools/review_local_change_bundle.sh <bundle> [status|diff|paths]
@@ -19,74 +23,126 @@ bash tools/review_local_change_bundle.sh <bundle> [status|diff|paths]
Objet:
- `runtime home` local explicite pour les launchers MCP et CAD
- smokes MCP alignes sur les modes d'auth reels
- doc operateur associee
Fichiers:
- `.gitignore`
- `ai-agentic-embedded-base/specs/mcp_tasks.md`
- `docs/QUICKSTART.md`
- `docs/index.md`
- `docs/RUNTIME_HOME.md`
- `tools/github_dispatch_mcp_smoke.py`
- `tools/hw/kicad_cli.sh`
- `tools/hw/run_kicad_mcp.sh`
- `tools/lib/runtime_home.sh`
- `tools/notion_mcp.py`
- `tools/notion_mcp_smoke.py`
- `tools/run_github_dispatch_mcp.sh`
- `tools/run_nexar_mcp.sh`
- `tools/run_notion_mcp.sh`
Revue:
```bash
bash tools/review_local_change_bundle.sh mcp-runtime status
bash tools/review_local_change_bundle.sh mcp-runtime diff
```
## Lot 2 — `python-local`
Objet:
- bootstrap Python repo-local stable
- commande de tests repo-locale stable
- harness de tests ajustes pour ce chemin supporte
- remplacer les anciennes surfaces `notion` par `knowledge-base`
- figer le `runtime home` local et le statut MCP courant
- aligner GitHub dispatch et la doc MCP sur le contrat reel
Fichiers:
- `README.md`
- `test/test_openclaw_sanitizer.py`
- `tools/bootstrap_python_env.sh`
- `tools/hw/schops/tests/test_rules_engine.py`
- `tools/test_python.sh`
- `ai-agentic-embedded-base/specs/README.md`
- `ai-agentic-embedded-base/specs/knowledge_base_mcp_spec.md`
- `ai-agentic-embedded-base/specs/mcp_tasks.md`
- `ai-agentic-embedded-base/specs/notion_mcp_conversion_spec.md`
- `ai-agentic-embedded-base/specs/zeroclaw_dual_hw_todo.md`
- `docs/LOCAL_CHANGE_BUNDLES_2026-03-08.md`
- `docs/MCP_ECOSYSTEM_MATRIX.md`
- `docs/MCP_SETUP.md`
- `docs/MCP_SUPPORT_MATRIX.md`
- `docs/RUNTIME_HOME.md`
- `docs/plans/15_plan_mcp_runtime_alignment.md`
- `docs/plans/README.md`
- `mcp.json`
- `specs/README.md`
- `specs/knowledge_base_mcp_spec.md`
- `specs/mcp_tasks.md`
- `specs/notion_mcp_conversion_spec.md`
- `test/test_knowledge_base_mcp.py`
- `test/test_notion_mcp.py`
- `tools/github_dispatch_mcp_smoke.py`
- `tools/knowledge_base_mcp.py`
- `tools/knowledge_base_mcp_smoke.py`
- `tools/lib/runtime_home.sh`
- `tools/mcp_runtime_status.py`
- `tools/mcp_smoke_common.py`
- `tools/notion_mcp.py`
- `tools/notion_mcp_smoke.py`
- `tools/review_local_change_bundle.sh`
- `tools/run_github_dispatch_mcp.sh`
- `tools/run_knowledge_base_mcp.sh`
- `tools/run_notion_mcp.sh`
Revue:
Validation minimale:
```bash
bash tools/review_local_change_bundle.sh python-local status
bash tools/review_local_change_bundle.sh python-local diff
cd /home/clems/Kill_LIFE && bash tools/test_python.sh --suite stable
cd /home/clems/Kill_LIFE && python3 tools/validate_specs.py --json
```
## Lot 2 — `cad-mcp`
Objet:
- pile CAD/MCP locale (`FreeCAD`, `OpenSCAD`, compose CAD, runtime status)
- specs, plans et docs operateur associes
- smokes et launchers dedies a cette pile
Fichiers:
- `Makefile`
- `ai-agentic-embedded-base/specs/cad_modeling_tasks.md`
- `ai-agentic-embedded-base/specs/mcp_agentics_target_backlog.md`
- `deploy/cad/README.md`
- `deploy/cad/Dockerfile.openscad-headless`
- `deploy/cad/docker-compose.yml`
- `docs/plans/16_plan_cad_modeling_stack.md`
- `docs/plans/17_plan_target_architecture_mcp_agentics_2028.md`
- `specs/cad_modeling_tasks.md`
- `specs/mcp_agentics_target_backlog.md`
- `test/test_freecad_mcp.py`
- `test/test_openscad_mcp.py`
- `tools/cad_runtime.py`
- `tools/freecad_mcp.py`
- `tools/freecad_mcp_smoke.py`
- `tools/hw/cad_stack.sh`
- `tools/hw/freecad_smoke.py`
- `tools/hw/openscad_smoke.py`
- `tools/mcp_telemetry.py`
- `tools/openscad_mcp.py`
- `tools/openscad_mcp_smoke.py`
- `tools/run_freecad_mcp.sh`
- `tools/run_openscad_mcp.sh`
Validation minimale:
```bash
cd /home/clems/Kill_LIFE && bash tools/hw/cad_stack.sh doctor
cd /home/clems/Kill_LIFE && bash tools/hw/cad_stack.sh doctor-mcp
```
## Lot 3 — `python-local`
Objet:
- garder un chemin de test repo-local stable et publiable
- maintenir la commande Python minimale supportee dans le delta courant
Fichiers:
- `tools/test_python.sh`
Validation repo-locale:
```bash
bash tools/bootstrap_python_env.sh
bash tools/test_python.sh --suite stable
cd /home/clems/Kill_LIFE && bash tools/test_python.sh --suite stable
```
## Exclusion explicite
Ne pas versionner le runtime local genere:
- `.mascarade/mcp/github-dispatch/*.json`
Ces fichiers servent d'evidence locale runtime, pas de source de verite repo.
## Ordre recommande
1. publier ou reviewer `mcp-runtime`
2. publier ou reviewer `python-local`
1. publier `mcp-runtime`
2. publier `cad-mcp`
3. publier `python-local`
Ce decoupage evite de melanger:
- la hygiene runtime des launchers MCP
- le contrat operateur Python repo-local
## Note
Les tests MCP d'integration (`--suite mcp`) restent un lot de verification distinct du chemin repo-local stable. Ils dependent encore des launchers et des runtimes compagnons, donc ils ne servent pas de gate minimale pour le lot `python-local`.
- la migration `notion -> knowledge-base` et la hygiene runtime MCP
- la pile CAD/MCP et ses smokes associes
- le contrat Python repo-local minimal
+18 -19
View File
@@ -1,6 +1,6 @@
# MCP ecosystem matrix
Last updated: 2026-03-07
Last updated: 2026-03-08
Matrice transverse des surfaces MCP et non-MCP observees dans `Kill_LIFE`, `mascarade` et `crazy_life`.
@@ -18,44 +18,43 @@ Matrice transverse des surfaces MCP et non-MCP observees dans `Kill_LIFE`, `masc
| --- | --- | --- | --- | --- | --- |
| `kicad` | `Kill_LIFE` + `mascarade` | serveur MCP | `tools/hw/run_kicad_mcp.sh` | supporte | runtime KiCad canonique; implementation dans `mascarade/finetune/kicad_mcp_server` |
| `validate-specs` | `Kill_LIFE` | serveur MCP | `python3 tools/validate_specs.py --mcp` | supporte | validation repo/specs; pas un runtime CAD |
| `notion` | `Kill_LIFE` + `mascarade` | serveur MCP | `tools/run_notion_mcp.sh` | supporte avec dependance externe | MCP local branche sur `mascarade/core/mascarade/integrations/notion.py`; garde le bridge HTTP existant |
| `github-dispatch` | `Kill_LIFE` + `mascarade` | serveur MCP | `tools/run_github_dispatch_mcp.sh` | supporte avec dependance externe | MCP local branche sur `mascarade/core/mascarade/integrations/github_dispatch.py`; garde l'API directe existante |
| `knowledge-base` | `Kill_LIFE` + `mascarade` | serveur MCP | `tools/run_knowledge_base_mcp.sh` | supporte avec dependance externe | serveur MCP de compat sur la knowledge base configuree (`memos` ou `docmost`); validation live fermee sur le provider actif `memos` auto-heberge |
| `github-dispatch` | `Kill_LIFE` + `mascarade` | serveur MCP | `tools/run_github_dispatch_mcp.sh` | supporte avec dependance externe | serveur stable, validation live fermee via token GitHub persiste dans `runtime-secrets` |
| `freecad` | `Kill_LIFE` + `mascarade` | serveur MCP | `tools/run_freecad_mcp.sh` | supporte | serveur MCP headless local base sur `FreeCADCmd` |
| `openscad` | `Kill_LIFE` + `mascarade` | serveur MCP | `tools/run_openscad_mcp.sh` | supporte | serveur MCP headless local stateless base sur `openscad` |
| `component_database` | `mascarade` | micro-serveur MCP | `python3 -m mcp_servers.component_db` | supporte avec dependance externe | serveur auxiliaire; depend du cache KiCad v10 et du repo compagnon |
| `kicad_tools` | `mascarade` | micro-serveur MCP | `python3 -m mcp_servers.kicad_tools` | supporte avec dependance externe | serveur auxiliaire; depend des fichiers KiCad reels et du repo compagnon |
| `nexar_api` | `Kill_LIFE` + `mascarade` | micro-serveur MCP | `tools/run_nexar_mcp.sh` | experimental | wrapper `Kill_LIFE` sur le serveur auxiliaire `mascarade`; mode demo sans token, validation live encore ouverte |
| `nexar_api` | `Kill_LIFE` + `mascarade` | micro-serveur MCP | `tools/run_nexar_mcp.sh` | experimental | mode demo sans token; validation live encore ouverte |
## 2. Consommateurs et configs MCP
| Surface | Repo principal | Type | Point d'entree | Statut | Notes |
| --- | --- | --- | --- | --- | --- |
| `mcp.json` | `Kill_LIFE` | config consommateur MCP | `mcp.json` | supporte | reference `kicad`, `validate-specs`, `notion` et `github-dispatch` |
| `mcp.json` | `Kill_LIFE` | config consommateur MCP | `mcp.json` | supporte | reference `kicad`, `validate-specs`, `knowledge-base`, `github-dispatch`, `freecad`, `openscad` |
| `MCP setup` | `Kill_LIFE` | doc operateur MCP | `docs/MCP_SETUP.md` | supporte | source de verite d'usage local |
| `KiCad plugin MCP config` | `mascarade` | config plugin MCP | `finetune/kicad_kic_ai/plugins/mcp_config.json` | supporte avec dependance externe | concerne les micro-serveurs auxiliaires, pas le runtime canonique |
| `ops MCP probe` | `mascarade` | observabilite synthetique | `/api/ops/summary` via `api/src/routes/ops.ts` | supporte avec dependance externe | expose l'etat agrege de `kicad`, `validate-specs`, `notion` et `github-dispatch`, plus le detail par serveur |
| `crazy_life MCP positionnement` | `crazy_life` | doc de non-ownership | `docs/MCP_PLAN_2026-03-07.md` | supporte | `crazy_life` ne porte pas de serveur MCP |
| `ops MCP probe` | `mascarade` | observabilite synthetique | `/api/ops/summary` via `api/src/routes/ops.ts` | supporte avec dependance externe | expose l'etat agrege de `kicad`, `validate-specs`, `knowledge-base`, `github-dispatch`, `freecad`, `openscad` et des surfaces distantes suivies par le cockpit |
| `crazy_life MCP positionnement` | `crazy_life` | doc de non-ownership / cockpit | `docs/MCP_PLAN_2026-03-07.md` | supporte | `crazy_life` consomme l'etat MCP et les probes, sans porter de serveur |
## 3. Integrations tierces non-MCP
| Surface | Repo principal | Type | Point d'entree | Dependance | Statut | Notes |
| --- | --- | --- | --- | --- | --- | --- |
| `Notion bridge` | `mascarade` | API HTTP interne | `/api/notion/*` via `api/src/routes/notion.ts` | `NOTION_API_KEY` | supporte | bridge backend vers le client Notion, conserve en parallele du MCP `notion` |
| `Notion client core` | `mascarade` | integration SDK | `core/mascarade/integrations/notion.py` | `NOTION_API_KEY` | supporte | source de verite backend Notion |
| `NotionBrowser UI` | `crazy_life` | UI consommatrice | `src/pages/NotionBrowser.tsx` | backend `mascarade` | supporte | consomme encore le bridge HTTP Notion; migration MCP possible ensuite |
| `Knowledge base bridge` | `mascarade` | API HTTP interne | `/api/knowledge-base/*` via `api/src/routes/knowledgeBase.ts` | provider actif + credentials associes | supporte | bridge HTTP de compat vers la knowledge base configuree |
| `Knowledge base core` | `mascarade` | integration provider-aware | `core/mascarade/integrations/knowledge_base.py` | provider actif + credentials associes | supporte | source de verite backend pour `memos` et `docmost` |
| `GitHub dispatch` | `mascarade` | API GitHub directe | `api/src/lib/killlife.ts` | `KILL_LIFE_GITHUB_TOKEN` ou `GITHUB_TOKEN` | supporte | lance `workflow_dispatch`, conserve en parallele du MCP `github-dispatch` |
| `GitHub dispatch` | `crazy_life` | API GitHub directe | `api/src/lib/killlife.ts` | `KILL_LIFE_GITHUB_TOKEN` ou `GITHUB_TOKEN` | supporte | miroir cote repo canonique frontend/API; migration MCP possible ensuite |
| `KillLife workflow editors` | `mascarade` + `crazy_life` | UI orchestration | `web/src/pages/KillLifeWorkflowEditor.tsx`, `src/pages/KillLifeWorkflowEditor.tsx`, `src/pages/CrazyLaneEditor.tsx` | backend API | supporte | exposent `github-dispatch` comme type de noeud, pas comme MCP |
| `FreeCAD agent` | `mascarade` | agent metier | `core/mascarade/agents/freecad_agent.py` | backend LLM | supporte | reste un agent de guidance; l'execution outillee passe par le MCP `freecad` pour la suite cible |
| `Workflow editors` | `mascarade` + `crazy_life` | UI orchestration | `web/src/pages/KillLifeWorkflowEditor.tsx`, `src/pages/KillLifeWorkflowEditor.tsx`, `src/pages/CrazyLaneEditor.tsx` | backend API | supporte | exposent `github-dispatch` comme type de noeud, pas comme serveur MCP |
## 4. Surfaces infra-only ou migration
| Surface | Repo principal | Type | Point d'entree | Statut | Notes |
| --- | --- | --- | --- | --- | --- |
| `openmemory-mcp / mem0` | `mascarade` | conteneur MCP tiers | `deploy/migration/compose.tools.ai.yml` | infra-only | profil `heavy`, non documente comme point d'entree canonique, non observe en execution sur cette machine |
| `openmemory-mcp / mem0` | `mascarade` | conteneur MCP tiers | `deploy/migration/compose.tools.ai.yml` | infra-only | profil `heavy`, non documente comme point d'entree canonique |
| `kicad-sch-mcp` | docs historiques | ancien serveur MCP externe | documentation seulement | non supporte | pas package ni retenu dans le workspace actuel |
## 5. Conclusion
- le point d'entree operateur MCP de `Kill_LIFE` reste la surface `kicad` lancee par `tools/hw/run_kicad_mcp.sh`
- `Notion` et `GitHub dispatch` disposent aussi d'un serveur MCP local, mais leur logique applicative reste fournie par `mascarade`
- `crazy_life` consomme des surfaces applicatives, mais n'own pas de serveur MCP
- `mem0/openmemory-mcp` reste une brique d'infra optionnelle, hors chaine operateur canonique
- les surfaces auxiliaires `kicad_kic_ai` ne doivent pas etre lues comme equivalentes au point d'entree operateur `kicad`
- `Kill_LIFE` porte maintenant des MCP locaux supportes pour `kicad`, `validate-specs`, `knowledge-base`, `github-dispatch`, `freecad` et `openscad`
- `mascarade` porte l'agregation ops et les integrations applicatives encore existantes en parallele
- `crazy_life` consomme et supervise, mais n'own pas de serveur MCP
- `A2A` reste ferme tant que l'orchestrateur n'est pas branche sur les MCP specialises et que l'observabilite MCP n'est pas completement homogene
+71 -82
View File
@@ -1,54 +1,56 @@
# MCP setup
Last updated: 2026-03-08
Source canonique pour l'usage MCP local de `Kill_LIFE`.
References canoniques:
- spec de perimetre: `specs/kicad_mcp_scope_spec.md`
- spec de perimetre KiCad: `specs/kicad_mcp_scope_spec.md`
- matrice de support: `docs/MCP_SUPPORT_MATRIX.md`
- matrice ecosysteme: `docs/MCP_ECOSYSTEM_MATRIX.md`
- backlog MCP: `specs/mcp_tasks.md`
- backlog MCP KiCad: `specs/mcp_tasks.md`
- backlog cible MCP/agentics: `specs/mcp_agentics_target_backlog.md`
## Source de verite et ownership
- `Kill_LIFE` own le lancement, la consommation et la gouvernance documentaire MCP locale
- `mascarade` own l'implementation du serveur KiCad principal et l'observabilite compagnon
- `Kill_LIFE` own le lancement, les smokes et la gouvernance documentaire MCP locale
- `mascarade` own l'agregation ops et l'observabilite compagnon
- `specs/` a la racine de `Kill_LIFE` est la source de verite canonique
- `ai-agentic-embedded-base/specs/` n'est qu'un miroir exporte
## Chemins supportes
- serveur MCP KiCad supporte: `../mascarade/finetune/kicad_mcp_server`
- launcher supporte cote `Kill_LIFE`: `tools/hw/run_kicad_mcp.sh`
- alias operateur supporte: `tools/hw/cad_stack.sh mcp`
- serveur auxiliaire supporte: `python3 tools/validate_specs.py --mcp`
- serveur MCP Notion supporte: `tools/run_notion_mcp.sh`
- serveur MCP GitHub dispatch supporte: `tools/run_github_dispatch_mcp.sh`
- transport supporte: `stdio` local uniquement
`kicad-sch-mcp` n'est plus un chemin supporte dans ce repo. Il reste un ancien axe documentaire, pas un runtime principal.
- `kicad`: `tools/hw/run_kicad_mcp.sh`
- `validate-specs`: `python3 tools/validate_specs.py --mcp`
- `knowledge-base`: `tools/run_knowledge_base_mcp.sh`
- `github-dispatch`: `tools/run_github_dispatch_mcp.sh`
- `freecad`: `tools/run_freecad_mcp.sh`
- `openscad`: `tools/run_openscad_mcp.sh`
- transport supporte: `stdio` local uniquement, sauf surface distante explicitement declaree par le cockpit compagnon
## Ce qui est reellement supporte
- `kicad`: runtime MCP KiCad canonique, avec `tools`, `resources` et `prompts`
- `validate-specs`: validation repo/specs cote `Kill_LIFE`, sans role CAD
- `notion`: MCP local sur le backend Notion existant de `mascarade`
- `kicad`: runtime MCP CAD canonique, avec `tools`, `resources` et `prompts`
- `validate-specs`: validation repo/specs cote `Kill_LIFE`
- `knowledge-base`: MCP local de compat sur la knowledge base configuree dans `mascarade` (`memos` ou `docmost`)
- `github-dispatch`: MCP local pour workflows GitHub allowlistes
- `freecad`: MCP local headless pour infos runtime, document minimal, export et script Python controle
- `openscad`: MCP local headless pour infos runtime, validation, rendu et export
Les micro-serveurs `kicad_kic_ai` de `mascarade` sont suivis comme surfaces auxiliaires. Ils ne sont pas des points d'entree operateur `Kill_LIFE`, et leur statut doit etre lu avec leurs dependances externes dans `docs/MCP_SUPPORT_MATRIX.md`.
Les micro-serveurs `kicad_kic_ai` de `mascarade` restent suivis comme surfaces auxiliaires dans `docs/MCP_SUPPORT_MATRIX.md`.
## Prerequis
- le repo compagnon `mascarade` existe en voisin (`../mascarade`) ou via `MASCARADE_DIR`
- `node` est disponible sur la machine
- le serveur est builde dans `mascarade/finetune/kicad_mcp_server/dist/index.js`
- le venv `mascarade/core/.venv` existe, ou `MASCARADE_CORE_PYTHON` pointe vers un Python avec `notion-client` et `httpx`
- Docker est disponible pour le fallback conteneur KiCad v10
- `pcbnew` cote hote est optionnel: s'il est absent, le launcher bascule vers le conteneur supporte
- `NOTION_API_KEY` est requis pour les outils `notion`
- `KILL_LIFE_GITHUB_TOKEN` ou `GITHUB_TOKEN` est requis pour `dispatch_workflow`
Le runtime prepare un environnement writable sous `.cad-home/kicad-mcp/` et exporte `KICAD_MCP_DATA_DIR` pour eviter les ecritures dans un prefixe immuable.
- Docker est disponible pour `kicad`, `freecad` et `openscad`
- `node` est disponible pour le build/API compagnon
- le venv `mascarade/core/.venv` existe, ou `MASCARADE_CORE_PYTHON` pointe vers un Python avec les dependances knowledge base (`httpx`)
- `KNOWLEDGE_BASE_PROVIDER` selectionne `memos` ou `docmost`
- selon le provider:
- `memos`: `MEMOS_BASE_URL` et `MEMOS_ACCESS_TOKEN`
- `docmost`: `DOCMOST_BASE_URL`, `DOCMOST_EMAIL` et `DOCMOST_PASSWORD`
- `KILL_LIFE_GITHUB_TOKEN`, `GITHUB_TOKEN` ou une configuration `GitHub App` est requise pour la validation live de `github-dispatch`
## Diagnostic rapide
@@ -56,31 +58,25 @@ Depuis `Kill_LIFE`:
```bash
tools/hw/run_kicad_mcp.sh --doctor
tools/hw/cad_stack.sh mcp --doctor
tools/run_notion_mcp.sh --doctor
tools/run_knowledge_base_mcp.sh --doctor
tools/run_github_dispatch_mcp.sh --doctor
tools/run_nexar_mcp.sh --doctor
python3 tools/mcp_runtime_status.py --json
tools/run_freecad_mcp.sh --doctor
tools/run_openscad_mcp.sh --doctor
python3 tools/validate_specs_mcp_smoke.py --json --quick
python3 tools/notion_mcp_smoke.py --json --quick
python3 tools/knowledge_base_mcp_smoke.py --json --quick
python3 tools/github_dispatch_mcp_smoke.py --json --quick
python3 tools/nexar_mcp_smoke.py --json
python3 tools/hw/kicad_host_mcp_smoke.py --json --quick
python3 tools/hw/mcp_smoke.py --json --quick --timeout 30
python3 tools/hw/mcp_smoke.py --timeout 30
python3 tools/validate_specs.py --json
python3 tools/freecad_mcp_smoke.py --json
python3 tools/openscad_mcp_smoke.py --json
python3 tools/hw/freecad_smoke.py --json
python3 tools/hw/openscad_smoke.py --json
python3 tools/mcp_runtime_status.py --json
```
Sur cette machine auditee, le smoke KiCad passe via le fallback conteneur:
Sur la machine de reference:
- `HOST_PCBNEW_IMPORT=missing`
- `CONTAINER_STATUS=available`
- `python3 tools/hw/mcp_smoke.py --timeout 30` passe
- `python3 tools/notion_mcp_smoke.py --json --quick` retourne `degraded` tant que `NOTION_API_KEY` est absent
- `python3 tools/github_dispatch_mcp_smoke.py --json --quick` retourne `degraded` tant que le token GitHub est absent
- `python3 tools/mcp_runtime_status.py --json` agrege les smokes MCP locaux et remonte les blocages K-012/K-014
- `python3 tools/nexar_mcp_smoke.py --json` retourne `degraded` tant que `NEXAR_TOKEN` ou `NEXAR_API_KEY` est absent
- `python3 tools/hw/kicad_host_mcp_smoke.py --json --quick` retourne `degraded` tant que `pcbnew` n'est pas importable cote hote
- `kicad`, `validate-specs`, `freecad` et `openscad` sont `ready`
- `knowledge-base` est `ready` sur le provider actif `memos` auto-heberge
- `github-dispatch` est `ready`, avec validation live fermee via token GitHub persiste
## Configuration locale
@@ -101,10 +97,10 @@ Le fichier versionne [mcp.json](../mcp.json) pointe vers les serveurs MCP reelle
"args": ["tools/validate_specs.py", "--mcp"],
"tools": ["*"]
},
"notion": {
"knowledge-base": {
"type": "local",
"command": "bash",
"args": ["tools/run_notion_mcp.sh"],
"args": ["tools/run_knowledge_base_mcp.sh"],
"tools": ["*"]
},
"github-dispatch": {
@@ -112,6 +108,18 @@ Le fichier versionne [mcp.json](../mcp.json) pointe vers les serveurs MCP reelle
"command": "bash",
"args": ["tools/run_github_dispatch_mcp.sh"],
"tools": ["*"]
},
"freecad": {
"type": "local",
"command": "bash",
"args": ["tools/run_freecad_mcp.sh"],
"tools": ["*"]
},
"openscad": {
"type": "local",
"command": "bash",
"args": ["tools/run_openscad_mcp.sh"],
"tools": ["*"]
}
}
}
@@ -123,52 +131,33 @@ Depuis `Kill_LIFE`:
```bash
tools/hw/run_kicad_mcp.sh
tools/hw/cad_stack.sh mcp
python3 tools/validate_specs.py --mcp
tools/run_notion_mcp.sh
tools/run_knowledge_base_mcp.sh
tools/run_github_dispatch_mcp.sh
tools/run_freecad_mcp.sh
tools/run_openscad_mcp.sh
```
Le smoke `tools/hw/mcp_smoke.py` valide actuellement la surface cible suivante:
- `initialize`
- `tools/list`
- `resources/list`
- `prompts/list`
- creation de projet
- lecture de resources stables
- lecture d'un prompt stable
Les smokes dedies supplementaires sont:
- `tools/validate_specs_mcp_smoke.py`: handshake MCP de `validate-specs`
- `tools/notion_mcp_smoke.py`: handshake MCP de `notion`, puis validation live si le secret est disponible
- `tools/github_dispatch_mcp_smoke.py`: handshake MCP de `github-dispatch`, puis validation allowlist et live optionnelle
- `tools/validate_specs_mcp_smoke.py`
- `tools/knowledge_base_mcp_smoke.py`
- `tools/github_dispatch_mcp_smoke.py`
- `tools/freecad_mcp_smoke.py`
- `tools/openscad_mcp_smoke.py`
Le chemin d'observabilite synthetique n'est pas fourni par `Kill_LIFE` seul. Si la stack compagnon `mascarade` tourne, `/api/ops/summary` expose un bloc `mcp` qui remonte le statut, le runtime reellement choisi, la version de protocole et les compteurs de surface.
## Outils auxiliaires
- `python3 tools/mcp_runtime_status.py --json` est le rapport MCP local synthetique de premier niveau pour les smokes supportes
- `tools/run_nexar_mcp.sh` et `python3 tools/nexar_mcp_smoke.py` sont des helpers experimentaux pour qualifier `nexar_api` sans le promouvoir en point d'entree operateur
- `tools/hw/kicad_host_mcp_smoke.py` est un helper de readiness pour verifier explicitement le chemin host-native
- `tools/hw/sync_kicad_v10_libs.sh` est un helper auxiliaire optionnel, hors chemin operateur principal, pour prechauffer les libs/cache KiCad v10 des micro-serveurs auxiliaires
- ce helper depend:
- d'une image Docker locale `kill_life_cad-kicad-mcp:latest`
- du repo compagnon `mascarade`
- ce helper n'est pas requis pour lancer le runtime `kicad` canonique
Le chemin d'observabilite synthetique n'est pas fourni par `Kill_LIFE` seul. Si la stack compagnon `mascarade` tourne, `/api/ops/summary` expose un bloc `mcp` agrege qui remonte `kicad`, `validate-specs`, `knowledge-base`, `github-dispatch`, `freecad`, `openscad` et les surfaces distantes suivies par le cockpit.
## Politique de support
- `stdio` reste le seul transport supporte par defaut
- aucun serveur MCP reseau n'est expose par defaut
- `tools/hw/cad_stack.sh mcp` est un alias supporte du launcher canonique
- le runtime KiCad canonique est celui de `mascarade/finetune/kicad_mcp_server`
- `validate-specs` reste un MCP auxiliaire repo/specs, pas un runtime CAD
- `notion` et `github-dispatch` restent en `stdio` local et reutilisent les backends existants
- les micro-serveurs `kicad_kic_ai` sont des surfaces auxiliaires suivies, mais restent hors chemin operateur `Kill_LIFE`
- aucun serveur MCP reseau n'est expose par defaut pour ces surfaces locales
- `knowledge-base` et `github-dispatch` sont valides en live sur la machine de reference
- `freecad` et `openscad` sont supportes comme serveurs MCP headless locaux
- `kicad` reste le runtime MCP CAD principal
## Points encore ouverts
- le chemin host-native avec `pcbnew` doit encore etre revalide sur une machine qui expose reellement KiCad Python
- `nexar_api` doit encore etre valide en mode live avec `NEXAR_TOKEN`
- finir l'observabilite MCP homogene
- requalifier l'ouverture future de `A2A` une fois l'observabilite MCP homogene fermee
- fermer `K-012` sur une machine avec `pcbnew` host-native et `K-014` en mode `nexar_api` live
+13 -14
View File
@@ -1,6 +1,6 @@
# MCP support matrix
Last updated: 2026-03-07
Last updated: 2026-03-08
Matrice canonique du statut MCP pour `Kill_LIFE`, `mascarade` et les surfaces associees.
@@ -19,11 +19,13 @@ Vue plus large de l'ecosysteme:
| Surface | Point d'entree | Ownership | Protocole observe / declare | Statut | Notes |
| --- | --- | --- | --- | --- | --- |
| `kicad` | `tools/hw/run_kicad_mcp.sh` | launcher `Kill_LIFE`, serveur `mascarade/finetune/kicad_mcp_server` | `2025-03-26` observe au smoke | supporte | runtime KiCad canonique; `tools/hw/cad_stack.sh mcp` est un alias supporte |
| `kicad` | `tools/hw/run_kicad_mcp.sh` | launcher `Kill_LIFE`, implementation `mascarade/finetune/kicad_mcp_server` | `2025-03-26` observe au smoke | supporte | runtime KiCad canonique; `tools/hw/cad_stack.sh mcp` est un alias supporte |
| `validate-specs` | `python3 tools/validate_specs.py --mcp` | `Kill_LIFE` | `2025-03-26` observe en test | supporte | validation repo/specs; ne remplace pas le runtime KiCad |
| `notion` | `tools/run_notion_mcp.sh` | launcher `Kill_LIFE`, backend `mascarade/core/mascarade/integrations/notion.py` | `2025-03-26` observe en test | supporte avec dependance externe | MCP local branche sur le backend Notion de `mascarade`; requiert `NOTION_API_KEY` et le repo compagnon |
| `github-dispatch` | `tools/run_github_dispatch_mcp.sh` | launcher `Kill_LIFE`, backend `mascarade/core/mascarade/integrations/github_dispatch.py` | `2025-03-26` observe en test | supporte avec dependance externe | MCP local pour workflows allowlistes; requiert `KILL_LIFE_GITHUB_TOKEN` ou `GITHUB_TOKEN` et le repo compagnon |
| `component_database` | `python3 -m mcp_servers.component_db` | `mascarade/finetune/kicad_kic_ai` | `2025-03-26` observe au handshake | supporte avec dependance externe | micro-serveur auxiliaire; depend du repo compagnon `mascarade`, du cache KiCad v10 et d'un index local prechauffe |
| `knowledge-base` | `tools/run_knowledge_base_mcp.sh` | launcher `Kill_LIFE`, backend `mascarade/core/mascarade/integrations/knowledge_base.py` | `2025-03-26` observe en test | supporte avec dependance externe | serveur MCP de compat vers la knowledge base configuree (`memos` ou `docmost`); validation live fermee sur le provider actif `memos` auto-heberge |
| `github-dispatch` | `tools/run_github_dispatch_mcp.sh` | launcher `Kill_LIFE`, backend `mascarade/core/mascarade/integrations/github_dispatch.py` | `2025-03-26` observe en test | supporte avec dependance externe | serveur local stable; validation live fermee via token GitHub persiste dans `runtime-secrets` |
| `freecad` | `tools/run_freecad_mcp.sh` | runtime `Kill_LIFE`, ops `mascarade` | `2025-03-26` observe au smoke | supporte | MCP local headless pour infos runtime, creation minimale, export et script controle |
| `openscad` | `tools/run_openscad_mcp.sh` | runtime `Kill_LIFE`, ops `mascarade` | `2025-03-26` observe au smoke | supporte | MCP local headless stateless pour validation, rendu et export |
| `component_database` | `python3 -m mcp_servers.component_db` | `mascarade/finetune/kicad_kic_ai` | `2025-03-26` observe au handshake | supporte avec dependance externe | micro-serveur auxiliaire; depend du cache KiCad v10 et du repo compagnon |
| `kicad_tools` | `python3 -m mcp_servers.kicad_tools` | `mascarade/finetune/kicad_kic_ai` | `2025-03-26` observe au handshake | supporte avec dependance externe | micro-serveur auxiliaire; analyses reelles si les fichiers KiCad et dependances associees sont disponibles |
| `nexar_api` | `tools/run_nexar_mcp.sh` | launcher `Kill_LIFE`, serveur `mascarade/finetune/kicad_kic_ai/mcp_servers/nexar.py` | `2025-03-26` observe au handshake | experimental | micro-serveur auxiliaire; sans `NEXAR_TOKEN`, reste en mode demo; validation live encore ouverte |
@@ -35,15 +37,12 @@ Vue plus large de l'ecosysteme:
## Decisions importantes
- `Kill_LIFE` n'own pas de second serveur KiCad concurrent
- `stdio` reste le seul transport supporte par defaut
- le runtime KiCad supporte passe par `Kill_LIFE` pour le lancement et par `mascarade` pour l'implementation
- `notion` et `github-dispatch` sont supportes comme serveurs MCP locaux, mais leur logique applicative reste fournie par `mascarade`
- les micro-serveurs `kicad_kic_ai` sont suivis comme surfaces auxiliaires, pas comme point d'entree operateur `Kill_LIFE`
- le probe synthetique MCP expose cote ops appartient a `mascarade/api/src/routes/ops.ts`; il n'est disponible que si la stack compagnon tourne
- `stdio` reste le seul transport supporte par defaut pour les serveurs locaux
- `knowledge-base` et `github-dispatch` sont supportes comme serveurs MCP locaux, avec validation live fermee sur la machine de reference
- `freecad` et `openscad` sont des serveurs MCP supportes et sondes par le cockpit ops
- le probe synthetique MCP expose cote ops appartient a `mascarade/api/src/routes/ops.ts`
## Dettes encore ouvertes
- le chemin host-native avec `pcbnew` n'est pas encore revalide sur une machine qui l'expose reellement
- `nexar_api` doit encore etre valide en mode live avec credentials
- le statut des micro-serveurs auxiliaires doit rester distinct de la surface operateur `kicad`
- fermer `K-012` sur une machine avec `pcbnew` host-native
- fermer `K-014` en mode `nexar_api` live avec credentials
+1 -1
View File
@@ -82,7 +82,7 @@ docker run --rm \
- [tools/hw/kicad_cli.sh](../tools/hw/kicad_cli.sh)
- [tools/hw/run_kicad_mcp.sh](../tools/hw/run_kicad_mcp.sh)
- [tools/run_notion_mcp.sh](../tools/run_notion_mcp.sh)
- [tools/run_knowledge_base_mcp.sh](../tools/run_knowledge_base_mcp.sh)
- [tools/run_github_dispatch_mcp.sh](../tools/run_github_dispatch_mcp.sh)
- [tools/run_nexar_mcp.sh](../tools/run_nexar_mcp.sh)
+1 -1
View File
@@ -17,7 +17,7 @@ Faire de `Kill_LIFE` le repo de consommation et de gouvernance MCP, sans mainten
## Etat actuel
- `mcp.json` pointe vers des launchers MCP reels pour `kicad`, `validate-specs`, `notion` et `github-dispatch`
- `mcp.json` pointe vers des launchers MCP reels pour `kicad`, `validate-specs`, `knowledge-base` et `github-dispatch`
- `tools/hw/run_kicad_mcp.sh` est le point d'entree canonique pour le runtime KiCad
- `tools/hw/cad_stack.sh mcp` est deja aligne sur ce launcher
- `python3 tools/hw/mcp_smoke.py --timeout 30` passe sur la machine auditee via fallback conteneur
+2
View File
@@ -23,6 +23,8 @@ Ces plans sont des **runbooks** : tu peux les suivre tels quels, ou les transfor
13. [Plan de troubleshooting](13_plan_troubleshooting.md)
14. [Plan de release & versioning](14_plan_release_versioning.md)
15. [Plan d'alignement MCP local](15_plan_mcp_runtime_alignment.md)
16. [Plan de stack CAD modelling locale](16_plan_cad_modeling_stack.md)
17. [Plan cible MCP + agentics + A2A](17_plan_target_architecture_mcp_agentics_2028.md)
---
+14 -2
View File
@@ -12,10 +12,10 @@
"args": ["tools/validate_specs.py", "--mcp"],
"tools": ["*"]
},
"notion": {
"knowledge-base": {
"type": "local",
"command": "bash",
"args": ["tools/run_notion_mcp.sh"],
"args": ["tools/run_knowledge_base_mcp.sh"],
"tools": ["*"]
},
"github-dispatch": {
@@ -24,6 +24,18 @@
"args": ["tools/run_github_dispatch_mcp.sh"],
"tools": ["*"]
},
"freecad": {
"type": "local",
"command": "bash",
"args": ["tools/run_freecad_mcp.sh"],
"tools": ["*"]
},
"openscad": {
"type": "local",
"command": "bash",
"args": ["tools/run_openscad_mcp.sh"],
"tools": ["*"]
},
"huggingface": {
"type": "url",
"url": "https://huggingface.co/mcp",
+3 -1
View File
@@ -13,9 +13,11 @@ Le fichier `constraints.yaml` est la **source de verite** des contraintes non-fo
Specs complementaires:
- `github_mcp_conversion_spec.md`: prep de conversion de `workflow_dispatch` vers une surface MCP future.
- `cad_modeling_tasks.md`: backlog canonique `FreeCAD/OpenSCAD` pour la stack CAD locale hors MCP.
- `kicad_mcp_scope_spec.md`: perimetre fonctionnel, hors scope et criteres d'acceptation du MCP KiCad supporte.
- `mcp_agentics_target_backlog.md`: backlog cible 2026 -> 2028 pour `MCP`, `agentics`, `A2A`, avec ownership par repo.
- `mcp_tasks.md`: backlog canonique des actions MCP locales, partage entre runtime, doc et gouvernance.
- `notion_mcp_conversion_spec.md`: prep de conversion du bridge Notion actuel vers une surface MCP future.
- `knowledge_base_mcp_spec.md`: spec canonique du bridge et du MCP knowledge base (`memos` / `docmost`).
- `zeroclaw_dual_hw_orchestration_spec.md`: architecture d'orchestration ZeroClaw multi-repo + double materiel.
- `zeroclaw_dual_hw_todo.md`: backlog operationnel court terme pour autonomie controlee.
+61
View File
@@ -0,0 +1,61 @@
# Spec MCP Knowledge Base
Last updated: 2026-03-08
## Objectif
Documenter l'implementation MCP `knowledge-base` a partir du bridge knowledge base actuel, avec uniquement `memos` et `docmost` dans la pile supportee.
## Etat actuel
- backend reel dans `mascarade/core/mascarade/integrations/knowledge_base.py`
- bridge HTTP canonique dans `mascarade/api/src/routes/knowledgeBase.ts`
- UI consommatrice dans `mascarade/web/src/pages/KnowledgeBrowser.tsx` et `crazy_life/src/pages/KnowledgeBrowser.tsx`
- providers supportes:
- `memos`
- `docmost`
## Surface MCP implemente
Serveur MCP `knowledge-base` local avec les outils:
- `search_pages`
- `read_page`
- `append_to_page`
- `create_page`
## Mapping depuis l'existant
- `GET /api/knowledge-base/search` -> `search_pages`
- `GET /api/knowledge-base/pages/:pageId` -> `read_page`
- `POST /api/knowledge-base/pages/:pageId/append` -> `append_to_page`
- `POST /api/knowledge-base/pages` -> `create_page`
## Contraintes
- garder `stdio` comme transport par defaut
- ne pas exposer un MCP reseau en v1
- garder le bridge HTTP canonique tant que les clients UI le consomment
- launcher operateur: `tools/run_knowledge_base_mcp.sh`
- erreurs explicites si le provider actif n'est pas configure
## Providers supportes
- `memos`
- prerequis: `MEMOS_BASE_URL`, `MEMOS_ACCESS_TOKEN`
- `docmost`
- prerequis: `DOCMOST_BASE_URL`, `DOCMOST_EMAIL`, `DOCMOST_PASSWORD`
## Hors scope v1
- ajout d'un troisieme provider non qualifie
- suppression du bridge HTTP canonique
- edition riche avancee ou blocs proprietaires
- sync bidirectionnelle UI <-> MCP hors actions explicites
## Validation minimale
- handshake `initialize -> tools/list` vert
- `search_pages` et `read_page` smokees sur le provider actif
- erreur structuree et non ambigue si le provider actif n'est pas configure
- documentation operateur et matrice de support mises a jour
+32 -5
View File
@@ -1,6 +1,6 @@
# Tasks MCP local
Last updated: 2026-03-07
Last updated: 2026-03-08
Backlog MCP canonique pour `Kill_LIFE`.
@@ -17,6 +17,14 @@ Format:
## État courant
- Etat agrege courant:
- `kicad`, `validate-specs` et `huggingface` sont `ready`
- `knowledge-base` est `ready` sur le provider actif `memos`, avec smoke live valide
- `github-dispatch` est `ready`, avec smoke live valide via token GitHub persiste
- le backlog MCP restant est limite a deux blocages specialises constates sur cette machine:
- `K-012`: `pcbnew` absent sur l'hote, donc validation host-native impossible ici
- `K-014`: `NEXAR_TOKEN` absent, donc `nexar_api` reste en mode demo
- [x] K-001 — Rendre `validate-specs` réel
- AC: `mcp.json` ne référence plus de chemin absent.
@@ -55,6 +63,9 @@ Format:
- [ ] K-012 — Rejouer la validation host-native sur une machine avec `pcbnew`
- AC: le smoke passe aussi sur le chemin hote, pas seulement via le fallback conteneur.
- Helper pret: `python3 tools/hw/kicad_host_mcp_smoke.py --json --quick` degrade proprement si `pcbnew` est absent.
- Derniere verification: `2026-03-08` sur cette machine -> `blocked by host environment`
- Evidence: `python3 tools/hw/kicad_host_mcp_smoke.py --json --quick`
- Resultat: `{"status":"degraded","host_pcbnew_import":"missing","error":"pcbnew not importable on host runtime"}`
- [x] K-013 — Décider du statut final des micro-serveurs `kicad_kic_ai`
- AC: `component_database`, `kicad_tools` et `nexar_api` sont explicitement promus en surfaces auxiliaires supportées.
@@ -62,18 +73,22 @@ Format:
- [ ] K-014 — Valider le mode live de `nexar_api`
- AC: un run avec `NEXAR_TOKEN` confirme le comportement reel et le distingue du mode demo.
- Helper pret: `python3 tools/nexar_mcp_smoke.py --json --live` degrade ou echoue proprement tant que le token ou le mode live manquent.
- Derniere verification: `2026-03-08` sur cette machine -> `blocked by secret/env`
- Evidence: `python3 tools/nexar_mcp_smoke.py --json --live`
- Resultat: `{"status":"degraded","token_configured":false,"demo_mode":true,"error":"NEXAR token missing or server running in demo mode"}`
- [x] K-015 — Implémenter le MCP `Notion`
- AC: `tools/run_notion_mcp.sh` expose `search_pages`, `read_page`, `append_to_page`, `create_page` sans retirer le bridge HTTP en V1.
- [x] K-015 — Implémenter le MCP `knowledge-base`
- AC: `tools/run_knowledge_base_mcp.sh` expose `search_pages`, `read_page`, `append_to_page`, `create_page` sans retirer le bridge HTTP en V1.
- Resultat: le serveur `knowledge-base` est maintenant un MCP de compat vers `KNOWLEDGE_BASE_PROVIDER=memos|docmost`.
- [x] K-016 — Implémenter le MCP `GitHub dispatch`
- AC: `tools/run_github_dispatch_mcp.sh` expose `list_allowlisted_workflows`, `dispatch_workflow` et `get_dispatch_status` sans retirer la voie API actuelle en V1.
- [x] K-017 — Ajouter des smokes MCP dedies hors KiCad
- AC: `validate-specs`, `notion` et `github-dispatch` ont chacun un smoke versionne avec sortie JSON.
- AC: `validate-specs`, `knowledge-base` et `github-dispatch` ont chacun un smoke versionne avec sortie JSON.
- [x] K-018 — Etendre l'observabilite MCP a plusieurs serveurs
- AC: `/api/ops/summary` expose un etat agrege et le detail par serveur pour `kicad`, `validate-specs`, `notion` et `github-dispatch`.
- AC: `/api/ops/summary` expose un etat agrege et le detail par serveur pour `kicad`, `validate-specs`, `knowledge-base`, `github-dispatch`, `freecad` et `openscad`.
- [x] K-019 — Ajouter un helper de readiness host-native KiCad
- AC: `python3 tools/hw/kicad_host_mcp_smoke.py --json --quick` retourne `ready` ou `degraded` sans ambiguite.
@@ -83,3 +98,15 @@ Format:
- [x] K-021 — Ajouter un rapport MCP local synthetique
- AC: `python3 tools/mcp_runtime_status.py --json` agrege les smokes supportes et rend visibles les blocages K-012/K-014.
- [x] K-022 — Valider la knowledge base active en live via le MCP `knowledge-base`
- AC: un run avec le provider actif et sa cible de smoke confirme `search_pages` et `read_page`.
- Resultat: validation live fermee sur le provider actif `memos` auto-heberge, avec `python3 tools/knowledge_base_mcp_smoke.py --json` en `ready`.
- Variantes supportees:
- `memos`: `MEMOS_BASE_URL` + `MEMOS_ACCESS_TOKEN` + `KNOWLEDGE_BASE_SMOKE_PAGE_ID` optionnel
- `docmost`: `DOCMOST_BASE_URL` + `DOCMOST_EMAIL` + `DOCMOST_PASSWORD` + `KNOWLEDGE_BASE_SMOKE_PAGE_ID`
- [x] K-023 — Valider `GitHub dispatch MCP` en live
- AC: un run avec `KILL_LIFE_GITHUB_TOKEN` ou un `GitHub App` valide confirme `list_allowlisted_workflows` et `dispatch_workflow` sur une cible autorisee.
- Resultat: validation live fermee via token GitHub persiste dans `runtime-secrets`; le smoke versionne confirme `list_allowlisted_workflows`, `dispatch_workflow` et `get_dispatch_status`.
- Evidence: `python3 tools/github_dispatch_mcp_smoke.py --json --live`
-51
View File
@@ -1,51 +0,0 @@
# Spec conversion MCP Notion
Last updated: 2026-03-07
## Objectif
Documenter l'implémentation MCP `notion` à partir de l'intégration `Notion` existante, sans remplacer la voie HTTP existante en V1.
## État actuel
- backend réel dans `mascarade/core/mascarade/integrations/notion.py`
- bridge HTTP existant dans `mascarade/api/src/routes/notion.ts`
- UI consommatrice existante dans `crazy_life/src/pages/NotionBrowser.tsx`
- dépendance secrète: `NOTION_API_KEY`
## Surface MCP implémentée
Serveur MCP `notion` local avec les outils:
- `search_pages`
- `read_page`
- `append_to_page`
- `create_page`
## Mapping depuis l'existant
- `GET /api/notion/search` -> `search_pages`
- `GET /api/notion/pages/:pageId` -> `read_page`
- `POST /api/notion/pages/:pageId/append` -> `append_to_page`
- `POST /api/notion/pages` -> `create_page`
## Contraintes
- garder `stdio` comme transport par défaut
- ne pas exposer un MCP réseau en V1
- erreurs explicites si `NOTION_API_KEY` absent
- conserver le bridge HTTP existant tant que la migration client n'est pas faite
- launcher opérateur: `tools/run_notion_mcp.sh`
## Hors scope V1
- suppression du bridge HTTP existant
- édition riche avancée ou gestion fine des blocs Notion
- sync bidirectionnelle UI <-> MCP
## Validation minimale
- handshake `initialize -> tools/list` vert
- `search_pages` et `read_page` smokés
- erreur structurée et non ambiguë si `NOTION_API_KEY` absent
- documentation opérateur et matrice de support mises à jour
@@ -9,7 +9,7 @@ from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
SCRIPT = REPO_ROOT / "tools" / "run_notion_mcp.sh"
SCRIPT = REPO_ROOT / "tools" / "run_knowledge_base_mcp.sh"
def write_message(proc: subprocess.Popen[str], payload: dict) -> None:
@@ -34,10 +34,11 @@ def read_message(proc: subprocess.Popen[str]) -> dict:
return json.loads(body)
class NotionMcpTests(unittest.TestCase):
class KnowledgeBaseMcpTests(unittest.TestCase):
def test_server_supports_initialize_and_tools_list(self):
env = os.environ.copy()
env.pop("NOTION_API_KEY", None)
env["KNOWLEDGE_BASE_PROVIDER"] = "memos"
env.pop("MEMOS_ACCESS_TOKEN", None)
proc = subprocess.Popen(
["bash", str(SCRIPT)],
cwd=REPO_ROOT,
@@ -59,7 +60,9 @@ class NotionMcpTests(unittest.TestCase):
},
)
initialize = read_message(proc)
self.assertEqual(initialize["result"]["serverInfo"]["name"], "notion")
self.assertEqual(
initialize["result"]["serverInfo"]["name"], "knowledge-base"
)
self.assertEqual(initialize["result"]["protocolVersion"], "2025-03-26")
write_message(
@@ -89,7 +92,8 @@ class NotionMcpTests(unittest.TestCase):
def test_search_pages_returns_structured_missing_secret_error(self):
env = os.environ.copy()
env.pop("NOTION_API_KEY", None)
env["KNOWLEDGE_BASE_PROVIDER"] = "memos"
env.pop("MEMOS_ACCESS_TOKEN", None)
proc = subprocess.Popen(
["bash", str(SCRIPT)],
cwd=REPO_ROOT,
+2
View File
@@ -14,6 +14,7 @@ from mcp_smoke_common import (
emit_payload,
initialize,
list_tools,
load_runtime_env,
spawn_server,
terminate_server,
)
@@ -54,6 +55,7 @@ def parse_args() -> argparse.Namespace:
def main() -> int:
load_runtime_env()
args = parse_args()
token_configured = github_dispatch_auth_configured()
proc = spawn_server(["bash", str(SERVER)], ROOT)
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Local MCP server for the existing Mascarade Notion integration."""
"""Local MCP server for the configured Mascarade knowledge-base integration."""
from __future__ import annotations
@@ -26,16 +26,19 @@ MASCARADE_CORE_DIR = MASCARADE_DIR / "core"
if str(MASCARADE_CORE_DIR) not in sys.path:
sys.path.insert(0, str(MASCARADE_CORE_DIR))
from mascarade.integrations.notion import ( # noqa: E402
NotionClient,
notion_auth_configured,
from mascarade.integrations.knowledge_base import ( # noqa: E402
KnowledgeBaseClient,
knowledge_base_auth_configured,
knowledge_base_provider_label,
knowledge_base_status_detail,
normalized_knowledge_base_provider,
)
TOOLS = [
{
"name": "search_pages",
"description": "Search pages through the existing Mascarade Notion integration.",
"description": "Search pages through the configured Mascarade knowledge-base integration.",
"inputSchema": {
"type": "object",
"properties": {
@@ -51,22 +54,22 @@ TOOLS = [
},
{
"name": "read_page",
"description": "Read a Notion page and return its plain-text content.",
"description": "Read a knowledge-base page and return its plain-text content.",
"inputSchema": {
"type": "object",
"properties": {
"page_id": {"type": "string", "description": "Notion page identifier"}
"page_id": {"type": "string", "description": "Knowledge-base page identifier"}
},
"required": ["page_id"],
},
},
{
"name": "append_to_page",
"description": "Append a paragraph block to an existing Notion page.",
"description": "Append content to an existing knowledge-base page.",
"inputSchema": {
"type": "object",
"properties": {
"page_id": {"type": "string", "description": "Notion page identifier"},
"page_id": {"type": "string", "description": "Knowledge-base page identifier"},
"content": {"type": "string", "description": "Paragraph content to append"},
},
"required": ["page_id", "content"],
@@ -74,7 +77,7 @@ TOOLS = [
},
{
"name": "create_page",
"description": "Create a page under a parent page using the existing Notion integration.",
"description": "Create a page under a parent page using the configured knowledge-base integration.",
"inputSchema": {
"type": "object",
"properties": {
@@ -93,26 +96,26 @@ TOOLS = [
def _missing_secret_payload() -> dict[str, Any]:
label = knowledge_base_provider_label()
return {
"ok": False,
"provider": normalized_knowledge_base_provider(),
"error": {
"code": "missing_secret",
"message": (
"Notion non configure "
"(NOTION_API_KEY ou credentials OAuth Notion manquants)"
),
"message": knowledge_base_status_detail(),
},
"provider_label": label,
}
async def _with_client(callback):
if not notion_auth_configured():
if not knowledge_base_auth_configured():
return error_tool_result(
"Notion non configure (NOTION_API_KEY ou credentials OAuth Notion manquants)",
knowledge_base_status_detail(),
_missing_secret_payload(),
)
client = NotionClient()
client = KnowledgeBaseClient()
try:
return await callback(client)
finally:
@@ -129,11 +132,17 @@ async def tool_search_pages(arguments: dict[str, Any]) -> dict[str, Any]:
{"ok": False, "error": {"code": "invalid_arguments", "message": "query is required"}},
)
async def _run(client: NotionClient) -> dict[str, Any]:
results = await client.search(query)
payload = {"ok": True, "query": query, "results": results[:limit]}
async def _run(client: KnowledgeBaseClient) -> dict[str, Any]:
results = await client.search(query, limit=limit)
payload = {
"ok": True,
"provider": client.provider,
"provider_label": client.label,
"query": query,
"results": results[:limit],
}
return ok_tool_result(
f"Found {len(payload['results'])} Notion page(s) for '{query}'",
f"Found {len(payload['results'])} {client.label} page(s) for '{query}'",
payload,
)
@@ -151,11 +160,17 @@ async def tool_read_page(arguments: dict[str, Any]) -> dict[str, Any]:
},
)
async def _run(client: NotionClient) -> dict[str, Any]:
async def _run(client: KnowledgeBaseClient) -> dict[str, Any]:
content = await client.read_page(page_id)
payload = {"ok": True, "page_id": page_id, "content": content}
payload = {
"ok": True,
"provider": client.provider,
"provider_label": client.label,
"page_id": page_id,
"content": content,
}
return ok_tool_result(
f"Read Notion page {page_id}",
f"Read {client.label} page {page_id}",
payload,
)
@@ -177,11 +192,17 @@ async def tool_append_to_page(arguments: dict[str, Any]) -> dict[str, Any]:
},
)
async def _run(client: NotionClient) -> dict[str, Any]:
async def _run(client: KnowledgeBaseClient) -> dict[str, Any]:
await client.append_to_page(page_id, content)
payload = {"ok": True, "page_id": page_id, "content_length": len(content)}
payload = {
"ok": True,
"provider": client.provider,
"provider_label": client.label,
"page_id": page_id,
"content_length": len(content),
}
return ok_tool_result(
f"Appended content to Notion page {page_id}",
f"Appended content to {client.label} page {page_id}",
payload,
)
@@ -204,11 +225,18 @@ async def tool_create_page(arguments: dict[str, Any]) -> dict[str, Any]:
},
)
async def _run(client: NotionClient) -> dict[str, Any]:
async def _run(client: KnowledgeBaseClient) -> dict[str, Any]:
page_id = await client.create_page(parent_id, title, content)
payload = {"ok": True, "page_id": page_id, "parent_id": parent_id, "title": title}
payload = {
"ok": True,
"provider": client.provider,
"provider_label": client.label,
"page_id": page_id,
"parent_id": parent_id,
"title": title,
}
return ok_tool_result(
f"Created Notion page '{title}'",
f"Created {client.label} page '{title}'",
payload,
)
@@ -232,7 +260,7 @@ def serve_mcp() -> int:
{
"protocolVersion": PROTOCOL_VERSION,
"capabilities": {"tools": {"listChanged": False}},
"serverInfo": {"name": "notion", "version": "1.0.0"},
"serverInfo": {"name": "knowledge-base", "version": "1.0.0"},
},
)
)
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Smoke checks for the local Notion MCP server."""
"""Smoke checks for the local knowledge-base MCP server."""
from __future__ import annotations
@@ -14,27 +14,30 @@ from mcp_smoke_common import (
emit_payload,
initialize,
list_tools,
load_runtime_env,
spawn_server,
terminate_server,
)
ROOT = Path(__file__).resolve().parents[1]
SERVER = ROOT / "tools" / "run_notion_mcp.sh"
PAGE_ID_ENV = "NOTION_MCP_SMOKE_PAGE_ID"
SERVER = ROOT / "tools" / "run_knowledge_base_mcp.sh"
PAGE_ID_ENV = "KNOWLEDGE_BASE_SMOKE_PAGE_ID"
def notion_auth_configured() -> bool:
auth_mode = os.getenv("NOTION_AUTH_MODE", "api_key").strip().lower()
if auth_mode == "oauth_oidc":
def knowledge_base_auth_configured() -> bool:
provider = os.getenv("KNOWLEDGE_BASE_PROVIDER", "memos").strip().lower() or "memos"
if provider == "memos":
return bool(
os.getenv("NOTION_OAUTH_CLIENT_ID", "").strip()
and os.getenv("NOTION_OAUTH_CLIENT_SECRET", "").strip()
and (
os.getenv("NOTION_OAUTH_ACCESS_TOKEN", "").strip()
or os.getenv("NOTION_OAUTH_REFRESH_TOKEN", "").strip()
)
os.getenv("MEMOS_BASE_URL", "").strip()
and os.getenv("MEMOS_ACCESS_TOKEN", "").strip()
)
return bool(os.getenv("NOTION_API_KEY"))
if provider == "docmost":
return bool(
os.getenv("DOCMOST_BASE_URL", "").strip()
and os.getenv("DOCMOST_EMAIL", "").strip()
and os.getenv("DOCMOST_PASSWORD", "").strip()
)
return False
def parse_args() -> argparse.Namespace:
@@ -42,18 +45,24 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("--timeout", type=float, default=15.0)
parser.add_argument("--json", action="store_true")
parser.add_argument("--quick", action="store_true")
parser.add_argument("--page-id", default=os.getenv(PAGE_ID_ENV, ""))
parser.add_argument(
"--page-id",
default=os.getenv(PAGE_ID_ENV, "").strip(),
)
return parser.parse_args()
def main() -> int:
load_runtime_env()
args = parse_args()
secret_configured = notion_auth_configured()
secret_configured = knowledge_base_auth_configured()
proc = spawn_server(["bash", str(SERVER)], ROOT)
provider = os.getenv("KNOWLEDGE_BASE_PROVIDER", "memos").strip().lower() or "memos"
payload = {
"status": "failed",
"protocol_version": None,
"server_name": "notion",
"server_name": "knowledge-base",
"provider": provider,
"tool_count": 0,
"checks": [],
"secret_configured": secret_configured,
@@ -62,15 +71,19 @@ def main() -> int:
}
try:
init = initialize(proc, args.timeout, "kill-life-notion-mcp-smoke")
init = initialize(proc, args.timeout, "kill-life-knowledge-base-mcp-smoke")
tools = list_tools(proc, args.timeout)
tool_names = {tool.get("name") for tool in tools}
expected = {"search_pages", "read_page", "append_to_page", "create_page"}
if expected - tool_names:
raise SmokeError(f"notion tools missing: {sorted(expected - tool_names)}")
raise SmokeError(
f"knowledge-base tools missing: {sorted(expected - tool_names)}"
)
payload["protocol_version"] = init.get("protocolVersion", PROTOCOL_VERSION)
payload["server_name"] = (init.get("serverInfo") or {}).get("name", "notion")
payload["server_name"] = (
init.get("serverInfo") or {}
).get("name", "knowledge-base")
payload["tool_count"] = len(tools)
payload["checks"] = ["initialize", "tools/list"]
@@ -81,7 +94,7 @@ def main() -> int:
else:
payload["status"] = "degraded"
payload["live_validation"] = "missing_secret"
payload["error"] = "NOTION auth missing"
payload["error"] = f"{provider} auth missing"
return emit_payload(payload, json_output=args.json)
search_result = call_tool(
+24 -1
View File
@@ -2,12 +2,35 @@
# shellcheck shell=bash
kill_life_runtime_home_is_writable() {
local target_dir="$1"
local probe_dir="$target_dir"
while [ ! -e "$probe_dir" ]; do
probe_dir="$(dirname "$probe_dir")"
if [ "$probe_dir" = "/" ]; then
break
fi
done
[ -w "$probe_dir" ]
}
kill_life_runtime_home_init() {
local root_dir="$1"
local runtime_name="$2"
local base_dir="${3:-$root_dir/.runtime-home}"
local fallback_base_dir="${KILL_LIFE_RUNTIME_BASE_DIR:-$root_dir/.cad-home/runtime-home}"
local selected_base_dir="$base_dir"
RUNTIME_HOME="${KILL_LIFE_RUNTIME_HOME:-$base_dir/$runtime_name}"
if [ -z "${KILL_LIFE_RUNTIME_HOME:-}" ] && ! kill_life_runtime_home_is_writable "$base_dir"; then
selected_base_dir="$fallback_base_dir"
if ! kill_life_runtime_home_is_writable "$selected_base_dir"; then
selected_base_dir="${XDG_RUNTIME_DIR:-/tmp}/kill-life-runtime-home"
fi
fi
RUNTIME_HOME="${KILL_LIFE_RUNTIME_HOME:-$selected_base_dir/$runtime_name}"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$RUNTIME_HOME/.config}"
XDG_CACHE_HOME="${XDG_CACHE_HOME:-$RUNTIME_HOME/.cache}"
HOME="$RUNTIME_HOME"
+20 -2
View File
@@ -10,6 +10,11 @@ import sys
from pathlib import Path
from typing import Any
try:
from .mcp_smoke_common import load_runtime_env
except ImportError: # pragma: no cover - script entrypoint fallback
from mcp_smoke_common import load_runtime_env
ROOT = Path(__file__).resolve().parents[1]
CHECKS: tuple[dict[str, Any], ...] = (
@@ -31,8 +36,8 @@ CHECKS: tuple[dict[str, Any], ...] = (
"blocked_when": "host_pcbnew_import != ok",
},
{
"name": "notion",
"cmd": ["python3", "tools/notion_mcp_smoke.py", "--json", "--quick"],
"name": "knowledge-base",
"cmd": ["python3", "tools/knowledge_base_mcp_smoke.py", "--json", "--quick"],
"accept_degraded": True,
},
{
@@ -40,6 +45,18 @@ CHECKS: tuple[dict[str, Any], ...] = (
"cmd": ["python3", "tools/github_dispatch_mcp_smoke.py", "--json", "--quick"],
"accept_degraded": True,
},
{
"name": "freecad",
"cmd": ["python3", "tools/freecad_mcp_smoke.py", "--json", "--quick"],
"accept_degraded": False,
"task": "F-101",
},
{
"name": "openscad",
"cmd": ["python3", "tools/openscad_mcp_smoke.py", "--json", "--quick"],
"accept_degraded": False,
"task": "O-101",
},
{
"name": "nexar-api",
"cmd": ["python3", "tools/nexar_mcp_smoke.py", "--json"],
@@ -144,6 +161,7 @@ def emit(payload: dict[str, Any], *, json_output: bool) -> int:
def main() -> int:
args = parse_args()
load_runtime_env()
results = [run_check(spec) for spec in CHECKS]
payload = {
"status": classify_overall(results, strict=args.strict),
+44
View File
@@ -4,6 +4,7 @@ from __future__ import annotations
import json
import os
import re
import signal
import subprocess
import sys
@@ -13,12 +14,55 @@ from threading import Thread
from typing import Any
PROTOCOL_VERSION = "2025-03-26"
ENV_ASSIGN_RE = re.compile(r"^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$")
DEFAULT_MASCARADE_DIR = Path(
os.environ.get("MASCARADE_DIR", Path(__file__).resolve().parents[2] / "mascarade")
).resolve()
class SmokeError(RuntimeError):
"""Raised when a smoke check fails."""
def _decode_env_value(raw_value: str) -> str:
value = raw_value.strip()
if not value:
return ""
if len(value) >= 2 and value[0] == value[-1] == '"':
inner = value[1:-1]
return inner.replace("\\n", "\n").replace('\\"', '"').replace("\\\\", "\\")
if len(value) >= 2 and value[0] == value[-1] == "'":
return value[1:-1]
return value
def resolve_mascarade_env_file() -> Path:
return Path(
os.environ.get("MASCARADE_ENV_FILE", DEFAULT_MASCARADE_DIR / ".env")
).resolve()
def load_runtime_env(*, override: bool = False) -> dict[str, str]:
env_file = resolve_mascarade_env_file()
loaded: dict[str, str] = {}
if not env_file.exists():
return loaded
for raw_line in env_file.read_text(encoding="utf-8").splitlines():
stripped = raw_line.strip()
if not stripped or stripped.startswith("#"):
continue
match = ENV_ASSIGN_RE.match(stripped)
if not match:
continue
key = match.group(1)
value = _decode_env_value(match.group(2))
if override or key not in os.environ or not os.environ.get(key, "").strip():
os.environ[key] = value
loaded[key] = value
return loaded
def spawn_server(command: list[str], cwd: Path) -> subprocess.Popen[str]:
return subprocess.Popen(
command,
+56 -12
View File
@@ -10,8 +10,9 @@ usage() {
Usage: bash tools/review_local_change_bundle.sh <bundle> [mode]
Bundles:
mcp-runtime Runtime-home, MCP launchers, MCP smokes, docs MCP associees
python-local Bootstrap/test Python repo-local et harness associes
mcp-runtime Runtime-home, knowledge-base, GitHub dispatch, docs MCP associees
cad-mcp Pile CAD/MCP (FreeCAD, OpenSCAD, compose CAD, specs et docs associees)
python-local Commande Python repo-locale stable encore dans le delta courant
all Ensemble des lots suivis localement
Modes:
@@ -21,6 +22,7 @@ Modes:
Examples:
bash tools/review_local_change_bundle.sh mcp-runtime
bash tools/review_local_change_bundle.sh cad-mcp diff
bash tools/review_local_change_bundle.sh python-local diff
bash tools/review_local_change_bundle.sh all paths
EOF
@@ -30,34 +32,76 @@ bundle_paths() {
case "$1" in
mcp-runtime)
cat <<'EOF'
.gitignore
README.md
ai-agentic-embedded-base/specs/README.md
ai-agentic-embedded-base/specs/mcp_tasks.md
docs/QUICKSTART.md
docs/index.md
ai-agentic-embedded-base/specs/knowledge_base_mcp_spec.md
ai-agentic-embedded-base/specs/notion_mcp_conversion_spec.md
ai-agentic-embedded-base/specs/zeroclaw_dual_hw_todo.md
docs/LOCAL_CHANGE_BUNDLES_2026-03-08.md
docs/MCP_ECOSYSTEM_MATRIX.md
docs/MCP_SETUP.md
docs/MCP_SUPPORT_MATRIX.md
docs/RUNTIME_HOME.md
docs/plans/15_plan_mcp_runtime_alignment.md
docs/plans/README.md
mcp.json
specs/README.md
specs/knowledge_base_mcp_spec.md
specs/mcp_tasks.md
specs/notion_mcp_conversion_spec.md
test/test_knowledge_base_mcp.py
test/test_notion_mcp.py
tools/github_dispatch_mcp_smoke.py
tools/hw/kicad_cli.sh
tools/hw/run_kicad_mcp.sh
tools/lib/runtime_home.sh
tools/knowledge_base_mcp.py
tools/knowledge_base_mcp_smoke.py
tools/mcp_runtime_status.py
tools/mcp_smoke_common.py
tools/notion_mcp.py
tools/notion_mcp_smoke.py
tools/review_local_change_bundle.sh
tools/run_github_dispatch_mcp.sh
tools/run_nexar_mcp.sh
tools/run_knowledge_base_mcp.sh
tools/run_notion_mcp.sh
EOF
;;
cad-mcp)
cat <<'EOF'
Makefile
ai-agentic-embedded-base/specs/cad_modeling_tasks.md
ai-agentic-embedded-base/specs/mcp_agentics_target_backlog.md
deploy/cad/README.md
deploy/cad/Dockerfile.openscad-headless
deploy/cad/docker-compose.yml
docs/plans/16_plan_cad_modeling_stack.md
docs/plans/17_plan_target_architecture_mcp_agentics_2028.md
specs/cad_modeling_tasks.md
specs/mcp_agentics_target_backlog.md
test/test_freecad_mcp.py
test/test_openscad_mcp.py
tools/cad_runtime.py
tools/freecad_mcp.py
tools/freecad_mcp_smoke.py
tools/hw/cad_stack.sh
tools/hw/freecad_smoke.py
tools/hw/openscad_smoke.py
tools/mcp_telemetry.py
tools/openscad_mcp.py
tools/openscad_mcp_smoke.py
tools/run_freecad_mcp.sh
tools/run_openscad_mcp.sh
EOF
;;
python-local)
cat <<'EOF'
README.md
test/test_openclaw_sanitizer.py
tools/bootstrap_python_env.sh
tools/hw/schops/tests/test_rules_engine.py
tools/test_python.sh
EOF
;;
all)
{
bundle_paths mcp-runtime
bundle_paths cad-mcp
bundle_paths python-local
} | awk '!seen[$0]++'
;;
+11
View File
@@ -3,10 +3,19 @@ set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MASCARADE_DIR="${MASCARADE_DIR:-$ROOT_DIR/../mascarade}"
MASCARADE_ENV_FILE="${MASCARADE_ENV_FILE:-$MASCARADE_DIR/.env}"
SERVER_SCRIPT="$ROOT_DIR/tools/github_dispatch_mcp.py"
source "$ROOT_DIR/tools/lib/runtime_home.sh"
kill_life_runtime_home_init "$ROOT_DIR" "github-dispatch-mcp"
load_mascarade_env() {
[[ -r "$MASCARADE_ENV_FILE" ]] || return 0
set -a
# shellcheck disable=SC1090
source "$MASCARADE_ENV_FILE"
set +a
}
detect_core_python() {
local candidate="${MASCARADE_CORE_PYTHON:-}"
if [[ -n "$candidate" && -x "$candidate" ]]; then
@@ -31,11 +40,13 @@ detect_core_python() {
}
CORE_PYTHON="$(detect_core_python || true)"
load_mascarade_env
if [[ "${1:-}" == "--doctor" ]]; then
cat <<EOF
ROOT_DIR=$ROOT_DIR
MASCARADE_DIR=$MASCARADE_DIR
MASCARADE_ENV_FILE=$MASCARADE_ENV_FILE
CORE_PYTHON=$CORE_PYTHON
SERVER_SCRIPT=$SERVER_SCRIPT
HOME=$RUNTIME_HOME
@@ -3,9 +3,18 @@ set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MASCARADE_DIR="${MASCARADE_DIR:-$ROOT_DIR/../mascarade}"
SERVER_SCRIPT="$ROOT_DIR/tools/notion_mcp.py"
MASCARADE_ENV_FILE="${MASCARADE_ENV_FILE:-$MASCARADE_DIR/.env}"
SERVER_SCRIPT="$ROOT_DIR/tools/knowledge_base_mcp.py"
source "$ROOT_DIR/tools/lib/runtime_home.sh"
kill_life_runtime_home_init "$ROOT_DIR" "notion-mcp"
kill_life_runtime_home_init "$ROOT_DIR" "knowledge-base-mcp"
load_mascarade_env() {
[[ -r "$MASCARADE_ENV_FILE" ]] || return 0
set -a
# shellcheck disable=SC1090
source "$MASCARADE_ENV_FILE"
set +a
}
detect_core_python() {
local candidate="${MASCARADE_CORE_PYTHON:-}"
@@ -31,11 +40,13 @@ detect_core_python() {
}
CORE_PYTHON="$(detect_core_python || true)"
load_mascarade_env
if [[ "${1:-}" == "--doctor" ]]; then
cat <<EOF
ROOT_DIR=$ROOT_DIR
MASCARADE_DIR=$MASCARADE_DIR
MASCARADE_ENV_FILE=$MASCARADE_ENV_FILE
CORE_PYTHON=$CORE_PYTHON
SERVER_SCRIPT=$SERVER_SCRIPT
HOME=$RUNTIME_HOME