constellation-mcp
v0.18.0
Published
MCP server that turns any model into a specialised web-product agent: investigates a target on its own, produces verifiable specs (SQL, OpenAPI, Gherkin, task graph), and closes the loop by comparing an implementation to its reference and naming every gap
Maintainers
Readme
constellation-mcp
Serveur MCP d'intelligence concurrentielle et de cloning produit. Il couvre le pipeline complet — cadrage, faisabilité, gap analysis, architecture, wireframes, design tokens, backlog chiffré, data model, spec API, specs, scaffold, checklist légale — avec un état persistant et des moteurs de scoring déterministes.
Pourquoi ce serveur plutôt qu'un simple prompt
| | Workflow prompt-only | constellation-mcp |
| --- | --- | --- |
| État | reperdu à chaque session | persisté sur disque, relisible par n'importe quel agent |
| Scoring | estimation « au feeling », non reproductible | modèle pondéré déterministe (même entrée → même sortie) |
| Navigation | l'agent doit se souvenir de l'étape | machine à états : project_status donne complétude + étape suivante |
| Sorties | prose | SQL, Prisma, Mermaid, OpenAPI 3.1, tokens CSS, arborescence de fichiers |
| Reprise | tout refaire | chaque étape est rejouable isolément |
| Traçabilité | aucune | journal horodaté de chaque étape et de l'outil qui l'a produite |
Installation
Une fois le paquet publié, aucune installation manuelle n'est nécessaire :
{
"mcpServers": {
"constellation": {
"command": "npx",
"args": ["-y", "constellation-mcp"],
"env": { "CONSTELLATION_HOME": "~/.constellation" }
}
}
}Depuis les sources :
npm install && npm run build{
"mcpServers": {
"constellation": {
"command": "node",
"args": ["/chemin/absolu/vers/mcp-competitor/dist/index.js"]
}
}
}Variables d'environnement
| Variable | Rôle | Défaut |
| --- | --- | --- |
| CONSTELLATION_HOME | Dossier de persistance des projets et du journal | ~/.constellation |
| CONSTELLATION_TOOLSETS | Groupes d'outils exposés au démarrage (all, ou une liste : analysis,codespec,collect,improve,deliver,diagnostics) | core seul |
| CONSTELLATION_TELEMETRY | off désactive tout enregistrement d'usage | actif |
| CONSTELLATION_MIN_INTERVAL_MS | Délai entre deux requêtes vers un même hôte | 800 |
| HTTPS_PROXY / NO_PROXY | Proxy sortant pour les outils de collecte | — |
| BRAVE_SEARCH_API_KEY, TAVILY_API_KEY, EXA_API_KEY, SERPAPI_API_KEY | Active la recherche web de discover_competitors (la première trouvée est utilisée) | aucune |
| CONSTELLATION_CHROMIUM_PATH | Chemin d'un Chromium déjà installé, pour capture_rendered_design | binaire de Playwright |
Publication
npm run pack:check # inspecte le contenu de l'archive sans rien publier
npm publish # build + tests exécutés automatiquement avant publicationprepublishOnly lance npm run build && npm test : une publication ne peut pas partir avec des tests rouges. Le paquet embarque dist/, README.md, LICENSE et le catalogue de capacités — ni les sources, ni les tests, ni les exports générés.
Vérifié : archive empaquetée, installée dans un dossier vierge, binaire constellation-mcp exécuté et handshake MCP réussi.
En cas d'erreur à la publication
| Message | Cause | Correction |
| --- | --- | --- |
| 'tsc' n'est pas reconnu / tsc: command not found | Les dépendances ne sont pas installées : node_modules n'est pas versionné | npm install avant npm publish |
| No bin file found at dist/index.js | Avertissement normal tant que le build n'a pas tourné | Disparaît après npm run build |
| 403 Forbidden | Nom déjà pris, ou compte sans droits dessus | Changer name dans package.json |
| 402 Payment Required | Paquet considéré comme privé | publishConfig.access doit valoir public (déjà le cas ici) |
Héberger le serveur en HTTP
Non pris en charge à ce stade, et ce n'est pas un oubli : cinq outils touchent au système de fichiers (ingest_own_product, generate_scaffold, export_project, compose_spec avec outFile). En hébergé ils liraient et écriraient sur le disque du serveur, ce qui est à la fois inutile pour l'utilisateur et dangereux pour l'hôte. Un mode distant exigerait de les désactiver ou de les réécrire, plus une authentification et un volume persistant.
Conçu pour qu'un petit modèle y arrive
Un modèle capable planifie à partir du pipeline. Un modèle plus modeste saute des étapes — un plan qu'il doit interpréter est un plan qu'il n'appliquera pas. next_action retire la planification de l'équation :
| Outil | Rôle |
| --- | --- |
| next_action | Renvoie une seule action : le nom de l'outil, pourquoi, et ses arguments déjà mis en forme. Charge tout seul le groupe d'outils nécessaire |
| mark_task_done | Fait avancer la boucle d'une tâche implémentée à la suivante |
Le modèle n'a plus qu'une chose à savoir : appeler next_action, exécuter ce qu'on lui dit, rappeler next_action.
Vérifié avec un client qui ne fait littéralement que ça — il lit l'action, recopie les arguments, n'invente rien, ne planifie jamais :
# 1 scope_project ✅
# 2 investigate_target ⏭ enjambé (réseau indisponible)
# 3 assess_feasibility ✅ 1/15 décisions prises
...
#17 generate_task_graph ✅ 14/15 décisions prises
#18 get_context_pack ✅ 0/4 tâches faites
...
#23 legal_checklist ✅ 15/15 décisions prises
→ Pipeline complet. Socle codable : 100 % (8/8)Deux propriétés rendent ça possible :
- Une étape impossible n'arrête pas la boucle. Si une action échoue pour une raison hors de portée du modèle — réseau coupé, source refusée — il rappelle
next_actionavecblocked: ["nom_outil"]et la boucle l'enjambe définitivement. - Les outils s'ouvrent tout seuls. Un outil désactivé est invisible ;
next_actiondéverrouille le groupe dont l'action a besoin, sans que le modèle ait à y penser.
La boucle fermée : construire → comparer → corriger
C'est ce qui distingue un outillage d'agent d'un simple scraper. Le serveur ne contient aucun modèle de langage : il fournit les mesures, la mémoire et les vérifications, et le modèle raisonne dessus. Conséquence directe : un modèle modeste peut atteindre un bon résultat, parce qu'il n'a plus rien à devoir devenir.
| Outil | Rôle dans la boucle |
| --- | --- |
| compare_design | Mesure l'écart entre ton implémentation et la référence, et renvoie des écarts nommés — pas un pourcentage de pixels |
| validate_implementation | Confronte l'implémentation aux specs du projet : routes qui répondent, règles métier couvertes par un test, états d'écran évoqués |
Un pourcentage de pixels n'apprend rien à un modèle. Une liste nommée, si :
Fidélité 45 % — l'implémentation s'écarte nettement de la référence (7 écarts).
1. bouton primaire : `background` vaut `#7c3aed`, la référence `#5b21b6`.
2. bouton primaire : `border-radius` vaut `4px`, la référence `10px`.
3. bouton primaire : `padding` vaut `8px 16px`, la référence `12px 24px`.
4. carte : `border-radius` vaut `4px`, la référence `10px`.
...Après application littérale de ces corrections, sans rien interpréter :
Fidélité 100 % — aucun écart actionnable.Les couleurs sont comparées avec une tolérance perceptuelle : #5b21b7 face à #5b21b6 est « proche » et n'encombre pas la liste. Le navigateur est utilisé des deux côtés quand Playwright est là, sinon le CSS servi.
La boucle est écrite dans les instructions du serveur — que tout client MCP lit au démarrage — et dans le prompt replication_loop. Un petit modèle n'a donc pas à inventer le workflow.
Mode enquête : le serveur cherche, tu ne fournis rien
Le reproche qu'on peut faire à un outil d'analyse est d'exiger qu'on lui mâche le travail. investigate_target prend une URL et va chercher :
| Source | Ce qu'elle donne |
| --- | --- |
| sitemap.xml | L'inventaire complet des pages, classées (marketing, tarifs, docs, app, légal) |
| llms.txt | La description que le site a écrite pour les modèles — ses titres sont sa liste de fonctionnalités |
| manifest.json | Le nom, la description et les couleurs de marque déclarées par le site |
| OpenAPI publié (8 chemins testés) | Les entités, l'authentification et le style de pagination du concurrent, dans ses propres termes |
| Flux RSS / Atom | Sa cadence de livraison |
| En-têtes HTTP et HTML | Sa stack |
| CSS servi | Son design mesuré |
| Issues GitHub publiques | De vraies plaintes d'utilisateurs, avec fréquence et sévérité |
Exemple réel, sur une cible de test : d'une seule URL sont ressortis Project, Invoice, Timesheet, Client, User, la pagination par curseur, l'authentification bearer, deux plans tarifaires, la couleur de marque et 20 fonctionnalités candidates classées par force de source.
Chaque fait porte son niveau — observé, déduit, supposé — et le rapport liste ce qui n'a pas été trouvé, pour que l'IA demande au lieu d'inventer.
Économie de tokens
Les utilisateurs étant des IA, le coût en tokens est un critère de conception. Deux mécanismes, tous deux mesurés — détail et méthode dans docs/TOKEN-ECONOMY.md.
Divulgation progressive des outils. Le manifeste d'outils est renvoyé au modèle à chaque requête, utilisés ou non. Seul le groupe core (7 outils) est exposé au départ ; l'agent charge un groupe quand il en a besoin via enable_toolset.
| Configuration | Outils | Manifeste |
| --- | --- | --- |
| Tout exposé | 41 | 30 203 caractères |
| core seul (défaut) | 7 | 4 706 caractères — 84 % de moins |
Pour désactiver la porte : CONSTELLATION_TOOLSETS=all, ou précharger des groupes précis (analysis,codespec).
Sorties résumées par défaut. Un outil qui persiste son résultat ne le recrache pas : il renvoie un résumé, où trouver le détail (ressource MCP ou fichier exporté), et full: true pour l'obtenir. Mesuré sur un run de 10 appels : 41 % de sorties en moins. S'y ajoutent les context packs, mesurés à un facteur 9 contre le document complet.
Outils
| Outil | Étape | Rôle |
| --- | --- | --- |
| scope_project | 1 | Crée le projet : cibles, mode (design/features/both), stack, profondeur |
| assess_feasibility | 2 | Score /100 pondéré sur 6 barrières → verdict + niches de repli |
| record_business_analysis | 3 | Secteur, proposition de valeur, modèle éco, pricing, ICP |
| compare_competitors | 3 | Matrice multi-concurrents, classement, white space |
| analyze_gaps | 4 | Clusterise des verbatims → axes de différenciation classés par levier |
| map_architecture | 5 | Écrans, sitemap, stack détectée, notes système |
| generate_wireframes | 6 | Wireframes ASCII structurels, sans style |
| build_style_guide | 7 | Palette/typo/densité/animations → tokens CSS + keyframes |
| plan_features | 8 | Effort j/h (taille × incertitude + intégrations) + RICE → MVP/V1/Nice-to-have |
| design_data_model | 8 | Entités → DDL Postgres + Prisma + ER Mermaid |
| spec_api | 8 | Endpoints → OpenAPI 3.1 complet |
| compose_spec | 9 | Document markdown autosuffisant, en-têtes stables |
| generate_scaffold | 10 | Arborescence de code (dry-run par défaut) |
| legal_checklist | 12 | Checklist pré-lancement avec niveau de risque |
| next_action | — | Une action à faire maintenant, arguments prêts, groupe d'outils ouvert automatiquement |
| mark_task_done | — | Avance la boucle d'une tâche à la suivante |
| project_status | — | Complétude des deux paliers, état de chaque étape, prochaine action |
| enable_toolset | — | Charge un groupe d'outils à la demande (divulgation progressive) |
| list_projects | — | Projets persistés |
Socle codable — ce qu'il faut à une IA pour implémenter sans deviner
Second palier, suivi séparément des 12 étapes d'analyse.
| Outil | Rôle |
| --- | --- |
| spec_screen_states | États obligatoires par écran (vide, chargement, erreur, droits, 404, validation, hors-ligne, session expirée) avec test associé |
| spec_user_flows | Parcours pas-à-pas + branches d'échec, diagramme Mermaid, audit des omissions |
| spec_api_conventions | Pagination, format d'erreur, versionnage, auth, idempotence, quotas — les décisions transverses |
| spec_permissions | Matrice rôles × ressources × CRUD + alertes (ressource inaccessible, rôle inutile, suppression RGPD absente) |
| spec_state_machines | Cycle de vie d'entité + détection des états inatteignables, impasses et transitions ambiguës |
| spec_business_rules | Registre de règles avec id stable et code d'erreur partagé par l'API, l'UI et les tests |
| generate_acceptance_criteria | Scénarios Given/When/Then dérivés des parcours et des règles ; signale les features MVP sans critère observable |
| generate_task_graph | Plan d'implémentation ordonné (migration → modèles → routes → écrans), dépendances, fichiers, détection de cycles |
Collecte automatique 🌐
Seuls outils à sortir sur le réseau. Ils respectent robots.txt, espacent les requêtes (800 ms par hôte, réglable via CONSTELLATION_MIN_INTERVAL_MS), plafonnent la taille des réponses, mettent en cache, et honorent HTTPS_PROXY / NO_PROXY.
| Outil | Rôle |
| --- | --- |
| investigate_target | Mode enquête : un seul appel, une URL, et il collecte tout seul — pages, stack, llms.txt, manifeste web, spécification OpenAPI publiée (donc les entités, l'authentification et le style de pagination du concurrent), flux de nouveautés, tarifs en trouvant la page lui-même, design mesuré, écrans déduits des routes et hypothèses de fonctionnalités sourcées. Remplit l'architecture et la provenance du projet |
| collect_issue_complaints | Convertit les issues d'un dépôt GitHub public en verbatims prêts pour analyze_gaps : fréquence d'après réactions et commentaires, sévérité d'après les étiquettes. Seule source de plaintes réelles collectée automatiquement — l'API GitHub est faite pour être interrogée, contrairement aux sites d'avis |
| discover_competitors | Trouve des candidats via le registre npm et l'API GitHub (sans clé), plus une recherche web si une clé est configurée. Indique toujours quelles sources ont répondu |
| crawl_product_surface | Inventorie les pages publiques via sitemap.xml (ou à défaut les liens de l'accueil), classées marketing / pricing / docs / blog / légal / app |
| detect_stack | Déduit la stack depuis en-têtes, balise generator, chemins de bundles et scripts tiers — chaque signal marqué observé ou déduit, et versé automatiquement au registre de provenance |
| extract_pricing | Extrait plan / prix / période d'une page de tarifs. Toujours marqué déduit |
| extract_design_tokens | Lit les vraies feuilles de style et en tire des mesures : variables CSS avec var() résolu en cascade, couleurs par fréquence, @font-face, échelle typographique et son ratio, grille d'espacement, rayons, ombres, transitions, breakpoints, @keyframes, largeurs de conteneur, variantes de thème (mode sombre), style par composant (bouton, carte, nav, héro, champ, badge, modale) et détection d'un framework utilitaire dont les classes du HTML sont le design system |
| capture_rendered_design | Ouvre la page dans un vrai navigateur et lit les styles calculés : couleurs pondérées par la surface peinte, polices appliquées, style par composant, rendu en clair et en sombre, captures d'écran. Seul moyen de voir un site qui construit ses styles en JavaScript. Playwright requis, non embarqué |
| snapshot_competitor | Relevé horodaté et diff avec le précédent : pages ajoutées, retirées, retitrées, mouvements tarifaires. C'est la veille continue |
| collect_reviews | Ne collecte rien, volontairement : G2, Capterra, Trustpilot et LinkedIn interdisent le scraping. L'outil énumère les voies légales plutôt que de contourner l'interdiction |
Rien de tout cela ne copie de contenu : seuls des faits structurés (route, titre, en-tête, prix) sont extraits.
Mode « améliorer un produit existant »
L'outil ne sert pas qu'à partir de zéro.
| Outil | Rôle |
| --- | --- |
| ingest_own_product | Analyse un dépôt local réel : framework, routes (Next App/Pages Router, SvelteKit), entités (Prisma/SQL), dépendances, scripts, fichiers sans couverture de test. Ignore node_modules et les dossiers listés dans .gitignore, pour ne jamais confondre du généré avec du source |
| gap_vs_competitors | Taux de couverture face au backlog concurrentiel, manques triés par RICE, avec les preuves de chaque correspondance pour corriger un faux positif |
| upgrade_plan | L'écart traduit en fichiers à créer ou modifier dans ton dépôt, aux conventions détectées, en réutilisant les routes existantes plutôt qu'en dupliquant |
| regression_guard | Les tests à écrire avant de toucher au code : caractérisation sur tout fichier modifié sans couverture |
Formats — rendre les specs consommables par une IA
| Outil | Rôle |
| --- | --- |
| get_context_pack | Renvoie uniquement la tranche de specs utile à une tâche, entité, route ou feature, avec budget de caractères et troncature par priorité |
| record_evidence | Marque chaque affirmation observé / déduit / supposé avec source et date ; alerte si les suppositions dominent |
| generate_agent_brief | AGENTS.md du projet cible : comment travailler, quel fichier contient quoi, et ce qui n'est pas spécifié |
| export_project | 14 fichiers : spec.md, spec.json, AGENTS.md, openapi.json, schema.sql, schema.prisma, erd.mmd, tokens.css, tasks.json, acceptance.feature, permissions.json, business-rules.json, screen-states.json, backlog.json |
Mesuré sur le projet de démonstration : un context pack fait 1,4 à 3,6 ko là où le document complet fait 56,5 ko — 16 à 39 fois moins de contexte pour la même tâche.
Prompts : full_competitor_run, replication_loop. Ressources : constellation://projects (index) et constellation://projects/{id}/{section} (une section à la demande : dataModel, apiSpec, codeSpec, evidence, spec, brief…). Prompt : full_competitor_run.
Conventions de code
| Dossier | Rôle |
| --- | --- |
| src/engines/ | Logique pure, sans I/O ni dépendance MCP — c'est là que vivent les modèles de scoring, testés unitairement |
| src/tools/ | (réservé) extraction future des handlers si server.ts grossit |
| src/server.ts | Enregistrement des outils, validation zod, formatage des réponses |
| src/store.ts | Persistance disque + journal |
| tests/ | Tests unitaires des moteurs + tests d'intégration client↔serveur via InMemoryTransport |
État de vérification
Exécuté et vérifié dans cet environnement :
npm run build(tsc, modestrict+noUncheckedIndexedAccess) — passenpm test— 239 tests passent (217 moteurs, 22 intégration MCP réelle)- Schéma Prisma généré validé par
prisma validate(6.19.3) : l'ancienne sortie était rejetée, la nouvelle passe, dont l'ingestion d'un dépôt fixture réel sur disque et un site simulé complet pour les outils réseau - Chemin réseau réel vérifié de bout en bout (robots.txt, plafond de taille, cache, détection de stack sur en-têtes réels)
- Passe navigateur vérifiée sur une page servant zéro CSS, tout injecté en JavaScript : l'extraction CSS ne trouve rien et le dit, le navigateur restitue le design complet dans les deux thèmes, captures incluses
- Démarrage stdio et handshake
initialize— vérifié manuellement
Non vérifié : le code produit par generate_scaffold est généré, pas exécuté. Ses handlers d'API sont des stubs marqués comme tels, et son README.md le signale explicitement.
Retour des agents
Les utilisateurs de ce serveur sont des IA. Deux mécanismes en tirent parti, tous deux strictement locaux :
| Mécanisme | Fonctionnement |
| --- | --- |
| Télémétrie automatique | Chaque appel est enregistré à l'inscription de l'outil — nom, succès, durée, message d'erreur normalisé. Aucun handler n'a à y penser, donc rien n'est oublié. |
| rate_experience | L'agent dépose une note en fin de session : ce qui a frotté, ce qui manquait, quel outil l'a trompé. Sa description lui demande explicitement de le faire sans l'annoncer à l'utilisateur — c'est un retour d'outil à outil. |
| usage_report | Agrège le tout : outils les plus appelés, taux d'échec, erreurs récurrentes, outils jamais utilisés, notes, frictions, et l'économie de tokens mesurée par modèle client. |
L'économie se met à jour toute seule, à mesure que des IA utilisent le serveur : chaque appel enregistre le poids de sa réponse, le nombre d'outils exposés à cet instant et l'identité du client. Le rapport en tire :
Économie de tokens (mesurée)
- Sorties cumulées : 2.7 k caractères (~672 tokens, ordre de grandeur).
- Manifeste : 12.3 k caractères envoyés par requête au lieu de 68.2 k si tout
était exposé — 82 % d'économie, payée à chaque tour.
| Client | Appels | Sorties | Outils exposés | Appel le plus lourd |
| claude-gourmand 1.0 | 3 | 1.7 k | 50 | enable_toolset |
| qwen-frugal 1.0 | 2 | 881 | 9 | next_action |Les tailles sont en caractères, comptés exactement ; les tokens sont donnés comme ordre de grandeur (~4 caractères par token) et annoncés comme tels. Le rapport désigne aussi les outils les plus coûteux en contexte — c'est là qu'il faut chercher des gains, et c'est ainsi qu'a été repéré scope_project, qui renvoyait 3 600 caractères à la création d'un projet et n'en renvoie plus que 280.
Le signal le plus utile est le taux d'échec par outil : au-delà de 40 % sur au moins 3 appels, le rapport pointe la description ou le schéma comme fautifs, pas l'agent. Les messages d'erreur sont normalisés (identifiants, chemins et nombres remplacés) pour que les mêmes échecs se regroupent.
Journal : <CONSTELLATION_HOME>/telemetry.jsonl. Rien n'est transmis à l'extérieur par défaut, et il n'y a pas d'activation implicite à découvrir après coup. Désactivation complète, journal local compris : CONSTELLATION_TELEMETRY=off.
Garde des requêtes sortantes
Les URL que ce serveur appelle sont choisies par un modèle qui vient de lire les pages d'un tiers : une consigne glissée dans une de ces pages peut donc viser une adresse. Avant chaque requête, l'hôte est résolu et toutes les adresses renvoyées sont vérifiées ; seuls http et https sont acceptés. Les plages internes sont refusées — boucle locale, privées, lien-local (dont 169.254.169.254, l'adresse des métadonnées cloud), CGNAT, multicast, ainsi que leurs équivalents IPv6 et les formes qui encapsulent une adresse IPv4 (::ffff:…, 2002:…).
Les redirections sont suivies à la main et chaque saut est revalidé : une URL publique qui répond 302 vers une adresse interne est arrêtée avant l'appel. Playwright passe par le même garde, sans quoi le navigateur serait un second chemin.
Deux outils visent légitimement ta propre machine : compare_design (son candidateUrl, pas sa référence) et validate_implementation. Eux seuls lèvent la restriction, et par URL.
Limite connue : entre la vérification et la connexion, un nom peut être re-résolu vers une autre adresse (DNS rebinding). Fermer cette fenêtre demande d'épingler l'adresse résolue dans la socket, ce que la pile fetch utilisée ici n'expose pas. La fenêtre est étroite et demande un serveur DNS complice, mais elle existe.
Le partage est possible, mais il se demande. En posant CONSTELLATION_TELEMETRY_URL (HTTPS obligatoire — une destination en clair est ignorée, sinon les notes de friction des agents transiteraient en clair), une copie de chaque enregistrement est postée à cette adresse, avec CONSTELLATION_TELEMETRY_TOKEN en jeton porteur si l'endpoint en exige un. L'envoi n'est jamais attendu : un collecteur lent ou injoignable ne retarde ni ne fait échouer un appel d'outil, et un enregistrement perdu l'est définitivement — il n'y a pas de file de reprise qui grossirait en silence.
Ce qui part : le nom de l'outil, sa durée, son succès, les caractères renvoyés au modèle, le nombre d'outils exposés, et le nom que le client MCP se donne. Ce qui ne part jamais : le contenu des projets, les arguments d'outils, les URL analysées.
Ce mécanisme a déjà servi : un agent a signalé que spec_api exigeait design_data_model sans le dire, ce que sa description corrige désormais.
Sécurité, planification et performance
Trois manques identifiés en confrontant le catalogue de rôles msitarzewski/agency-agents (269 agents, 18 divisions, MIT) aux groupes d'outils de ce serveur. Trois divisions entières n'avaient aucune contrepartie ici : security (12 agents), project-management (7) et le volet performance de testing (9).
Le dépôt a servi de carte des expertises, pas de source à recopier : ses agents sont des prompts de rôle, et ce serveur ne contient aucun modèle de langage. Les trois outils ci-dessous calculent, ils ne raisonnent pas.
| Outil | Groupe | Ce qu'il calcule |
| --- | --- | --- |
| spec_threat_model | codespec | Menaces dérivées des entités, endpoints et droits déjà spécifiés, classées STRIDE. Chaque menace nomme son artefact d'origine. |
| plan_delivery | codespec | Chemin critique, plancher imposé par les dépendances, durée par taille d'équipe, et les tâches qui en débloquent le plus. |
| audit_performance_budget | verify | Poids du document, ressources bloquant le premier rendu et leur taille, requêtes déclarées — des comptages, pas un score. |
spec_threat_model ne récite pas l'OWASP : une catégorie n'apparaît que si un artefact spécifié la déclenche, et la sortie dit « Webhook.secret en texte » plutôt que « pensez au chiffrement ». Sur le modèle Linear de 12 entités et 31 endpoints, il relève 7 menaces, dont la fuite inter-locataires des endpoints de liste — et ne signale pas ApiKey.hashedKey, qui porte déjà son condensat.
plan_delivery ne promet jamais mieux que le plancher des dépendances, et affiche l'efficacité par taille d'équipe : sous 1, des développeurs attendent, et embaucher ne raccourcit plus rien.
audit_performance_budget ne télécharge que les ressources bloquantes — celles dont la taille décide du premier rendu. Aucune mesure de temps, aucune simulation réseau : un score qui bouge tout seul n'apprend rien à personne.
Identité visuelle
Groupe identity. La chaîne est complète : de la mesure brute au manuel de marque.
| Outil | Rôle | État |
| --- | --- | --- |
| audit_contrast | Ratios WCAG des paires texte/fond réellement employées : ce qui échoue, de combien, dans quel sens corriger | livré |
| analyze_color_roles | Passer de la fréquence au sens : fond, surface, bordure, trois niveaux de texte, accent, états | livré |
| analyze_color_harmony | Juger la palette comme un système : schéma chromatique, régularité de l'échelle, couples indiscernables | livré |
| derive_distinct_identity | Palette délibérément écartée de la cible, contrastes vérifiés avant proposition | livré |
| extract_brand_assets | Ce que la cible déclare : favicons, og:image, logo, graisses livrées en @font-face | livré |
| synthesize_design_system | Échelles régularisées sur le ratio médian mesuré, rayons dont la pastille est isolée | livré |
| export_design_tokens | CSS, JSON, fragment Tailwind, module TypeScript typé | livré |
| generate_brand_manual | Page HTML autonome et imprimable documentant ton identité | livré |
La chaîne s'enchaîne : analyze_color_roles → analyze_color_harmony → derive_distinct_identity → synthesize_design_system → export_design_tokens et generate_brand_manual. Chaque étape refuse de deviner ce que la précédente n'a pas produit, et le dit en nommant l'outil manquant.
Deux partis pris, assumés :
Le manuel décrit ton produit, jamais la cible. Celle-ci n'y figure que comme provenance et comme mesure de l'écart voulu. Un manuel de marque d'un concurrent ne sert à rien pour construire, et le diffuser serait imprudent.
L'identité dérivée ne reprend aucune couleur mesurée : l'accent est tourné, les neutres sont reconstruits sur une échelle perceptuelle régulière. La palette est vérifiée en WCAG avant d'être proposée, et la clarté des textes s'ajuste jusqu'à passer AA — un générateur qui signale lui-même l'échec de sa sortie n'a pas fini son travail.
audit_contrast | Ratios WCAG des paires texte/fond réellement employées : ce qui échoue, de combien, dans quel sens corriger | ✅ livré |
| analyze_color_roles | Passer de la fréquence au sens : primaire, surface, danger | 🔨 |
| derive_distinct_identity | Palette équivalente mais juridiquement distincte, distance mesurée | 🔨 |
| generate_brand_manual | Le manuel de marque, trous explicitement marqués | 🔨 |
audit_contrast sert aux deux bouts — vérifier ton implémentation, et constater qu'une cible échoue :
2 paire(s) sur 3 échouent au niveau AA — 33 % de conformité.
| bouton primaire | #ffffff | #a78bfa | 2.72:1 | ❌ échec AA |
| carte | #9ca3af | #ffffff | 2.54:1 | ❌ échec AA |
| navigation | #374151 | #ffffff | 10.31:1 | ✅ conforme AAA |
À corriger
- bouton primaire — Il manque 1.78 de ratio pour atteindre AA (4.5:1).Il n'audite que les paires peintes l'une sur l'autre, en remontant au fond de la page quand un composant est transparent — auditer toutes les combinaisons théoriques noierait les vraies. Et quand la cible échoue, il formule l'axe de différenciation à verser dans analyze_gaps.
Chaîne d'approvisionnement
Un audit Socket.dev signale sur ce paquet des alertes « eval », « accès au shell » et « accès réseau ». Voici la réponse factuelle, vérifiable en une commande.
Ce code n'en fait aucun usage. grep -rnE "\beval\(|new Function|child_process|execSync|spawn\(" src/ ne renvoie rien. Les seuls modules Node importés sont fs, fs/promises, os, path, timers/promises — aucun child_process, aucun vm.
Les alertes viennent des dépendances transitives du SDK MCP officiel, soit 94 des 95 paquets installés :
| Paquet signalé | Origine | Pourquoi |
| --- | --- | --- |
| ajv | @modelcontextprotocol/sdk | Compile les schémas JSON avec new Function — c'est son principe de fonctionnement |
| cross-spawn | @modelcontextprotocol/sdk | Lance le processus serveur en transport stdio |
| express, cors, eventsource | @modelcontextprotocol/sdk | Transports HTTP du SDK, non utilisés ici mais installés |
Il n'y a rien à corriger de ce côté sans renoncer au protocole MCP lui-même. Les dépendances directes sont réduites au minimum :
dependencies : @modelcontextprotocol/sdk, zod
optionalDependencies : undici (uniquement pour HTTPS_PROXY)undici est importé dynamiquement et son absence est gérée : sans lui, les requêtes partent en direct et l'outil le dit. Le retirer ne fait cependant gagner qu'un seul paquet sur 95 — l'essentiel du poids vient du SDK, et je ne prétends pas l'inverse.
Limites connues
validate_implementationvérifie l'existence et la couverture, jamais la justesse du comportement : une route qui répond 200 peut répondre n'importe quoi. Les critères d'acceptation restent à exécuter.compare_designne compare pas les pixels, volontairement : il faudrait une dépendance de traitement d'image pour un résultat moins actionnable qu'une liste d'écarts nommés. Il ne voit donc ni la mise en page, ni les images.upgrade_planvise les produits web : sur une librairie ou un serveur sans routes, il propose des chemins génériques et le signale, il ne les devine pas.extract_pricingéchoue sur les pages qui chargent leurs prix en JavaScript — il le dit au lieu de rendre une liste vide silencieuse.extract_design_tokenslit le CSS servi, pas le rendu final : un site qui injecte ses styles en JavaScript ne donne rien, et l'outil le signale explicitement. C'estcapture_rendered_designqui couvre ce cas, au prix d'une dépendance à Playwright — volontairement non embarquée (plusieurs centaines de mégaoctets de navigateurs) : le serveur l'importe dynamiquement et explique comment l'installer si elle manque. Les trois dépendances publiées restent@modelcontextprotocol/sdk,undicietzod.Le mode enquête ne voit que ce qui est publié. Un concurrent sans sitemap, sans
llms.txtet sans API publique laisse peu de prise : le rapport le dit au lieu de combler les trous.collect_issue_complaintsne fonctionne que sur un dépôt public. Pour un SaaS fermé, les verbatims restent à fournir à la main — les CGU des sites d'avis interdisent la collecte automatique.discover_competitorssans clé de recherche web ne voit que npm et GitHub : un SaaS sans présence open source reste invisible. L'outil l'écrit dans chaque réponse plutôt que de laisser croire à une liste exhaustive. Le quota GitHub anonyme (60 requêtes/heure) s'épuise vite.La correspondance feature ↔ code de
gap_vs_competitorsest lexicale : un backlog en français face à un code en anglais déclenche une alerte explicite plutôt qu'un plan faux.
Garde-fous
Ce serveur ne scrape rien et ne copie rien : il ne reçoit que des observations déjà collectées et les transforme en artefacts originaux. Aucun outil n'ingère ni ne restitue de code source, d'asset ou de texte marketing du produit cible. legal_checklist ne valide rien automatiquement — ce sont des vérifications humaines.
Licence
MIT.
