Jusqu'ici, l'agent ne voit que ce qui est sur votre disque. Ce module lui ouvre l'accès à un navigateur, à une base de données, à un gestionnaire de tickets et à la documentation à jour d'une bibliothèque. Puis il empaquette tout ce que vous avez construit depuis le module 02 pour que l'équipe l'installe en deux commandes.
Le MCP (Model Context Protocol) est un standard ouvert qui décrit comment un agent se connecte à un système tiers. Proposé par Anthropic, il a été adopté par les autres éditeurs. Sans MCP, pour qu'un agent travaille sur un ticket, vous copiez le ticket dans le prompt ; avec MCP, il le lit lui-même et peut le mettre à jour.
┌──────────────┐ ┌──────────────┐ ┌─────────────┐
│ Claude Code │◀───────▶│ serveur MCP │◀──────▶│ le système │
│ (client) │ MCP │ │ API │ ciblé │
└──────────────┘ └──────────────┘ └─────────────┘
Le serveur MCP est un programme séparé qui déclare ce qu'il sait faire : des outils (des actions, comme exécuter une requête SQL), des ressources (des contenus à lire, comme le texte d'un ticket) et des prompts (des procédures fournies par le serveur). Claude Code les présente à l'agent au même titre que la lecture de fichiers.
| Transport | Comment il fonctionne | Pour quels serveurs |
|---|---|---|
stdio |
Claude Code lance le serveur en sous-processus et lui parle par l'entrée et la sortie standard | Serveurs locaux : navigateur, base de données, système de fichiers |
http |
Le serveur est un service web joignable par une adresse, avec authentification si nécessaire | Services partagés et offres commerciales |
sse |
Variante historique de http |
Serveurs anciens qui ne proposent que ce transport |
La commande est claude mcp add <nom> <url ou commande>. --transport choisit stdio, http ou sse, --scope choisit local, project ou user, --env pose une variable d'environnement et --header un en-tête HTTP. Une clé d'API passe par --env ou --header, jamais en clair dans un fichier versionné. Pour un serveur stdio, tout ce qui suit -- est la commande et ses arguments ; sans ce séparateur, --headless serait lu comme une option de claude mcp add.
$ claude mcp add --transport stdio --scope project playwright -- npx @playwright/mcp@latest
Added stdio MCP server playwright with command: npx @playwright/mcp@latest to project config
File modified: ~/projets/quizops/.mcp.json
$ claude mcp add --transport http --scope user context7 https://mcp.context7.com/mcp
Added HTTP MCP server context7 with URL: https://mcp.context7.com/mcp to user config
File modified: ~/.claude.json
| Portée | Où la déclaration atterrit | Qui en profite |
|---|---|---|
local (défaut) |
~/.claude.json, section de ce projet |
Vous seul, sur ce projet |
project |
.mcp.json à la racine du dépôt, versionné |
Toute l'équipe |
user |
~/.claude.json |
Vous, sur tous vos projets |
Le fichier produit par la portée project se relit en revue. C'est celui du tag tp9-depart du dépôt de référence :
{
"mcpServers": {
"playwright": {
"type": "stdio",
"command": "npx",
"args": [
"@playwright/mcp@latest"
],
"env": {}
}
}
}
.mcp.json de projetUn .mcp.json versionné arrive avec le dépôt, donc il n'est pas actif tant que vous ne l'avez pas approuvé. Le serveur est listé, mais aucun de ses outils n'est chargé.
$ claude mcp list
Checking MCP server health…
playwright: npx @playwright/mcp@latest - ⏸ Pending approval (run `claude` to approve)
$ claude mcp get playwright
playwright:
Scope: Project config (shared via .mcp.json)
Status: ⏸ Pending approval (run `claude` to approve)
Type: stdio
Command: npx
Args: @playwright/mcp@latest
Environment:
To remove this server, run: claude mcp remove playwright -s project
Le lancement de claude dans le dossier pose alors la question ; une fois répondu, l'état passe à ✔ Connected et les outils apparaissent. Pour rejouer l'approbation après une modification du fichier, claude mcp reset-project-choices efface les serveurs approuvés et rejetés de ce projet. En session, /mcp ouvre un menu qui liste les serveurs avec leur état (✔ Connected, ! Needs authentication, ✘ Failed to connect, ⏸ Pending approval), déclenche l'authentification OAuth d'un serveur distant et permet de désactiver un serveur pour ce projet.
Un outil MCP porte le nom mcp__serveur__outil. C'est ce nom que vous écrivez dans une règle de permission, dans le champ allowed-tools d'un skill ou dans le champ tools d'un sous-agent.
mcp__playwright__browser_navigate
mcp__playwright__browser_snapshot
mcp__playwright__browser_click
Une ressource se cite dans le prompt comme un fichier, avec @serveur:chemin : @notion:/databases/abc123. Un prompt fourni par le serveur s'appelle comme un skill, avec /mcp__serveur__prompt.
Les outils MCP ne sont plus chargés d'office : Claude Code garde le catalogue de côté et l'agent va y chercher ce dont il a besoin avec ToolSearch. La ligne MCP tools (deferred) de /context compte ce catalogue, ici les 24 outils du serveur Playwright pour 5 940 tokens.
| Category | Tokens | Percentage |
|----------------------|--------|------------|
| System prompt | 8.9k | 0.9% |
| System tools | 13.1k | 1.3% |
| MCP tools (deferred) | 5.9k | 0.6% |
| Skills | 2.2k | 0.2% |
La sortie d'un outil MCP est plafonnée à 25 000 tokens, avec un avertissement dès 10 000 ; au-delà, le résultat part dans un fichier et l'agent ne reçoit que son chemin. Un serveur qui renvoie des schémas entiers demande de relever MAX_MCP_OUTPUT_TOKENS.
Le serveur @playwright/mcp pilote un vrai navigateur. Le chromium se télécharge une fois, la veille de la formation, parce que le téléchargement dure plusieurs minutes.
$ npx playwright install chromium
L'option --headless, ajoutée après @playwright/mcp@latest, évite d'ouvrir une fenêtre. Sur le dépôt de référence, l'application tourne sur le port 8000 et la demande tient en une phrase.
Ouvre http://127.0.0.1:8000 avec le navigateur. Saisis le pseudo playwright,
commence une partie, réponds à toutes les questions (n'importe quelle
proposition), et dis-moi le score affiché à la fin ainsi que le premier
du classement.
⏺ ToolSearch({"query": "select:mcp__playwright__browser_navigate,mcp__playwright__…)
⎿
⏺ mcp__playwright__browser_navigate({"url": "http://127.0.0.1:8000"})
⎿ ### Ran Playwright code (+11 lignes)
⏺ mcp__playwright__browser_snapshot({})
⎿ ### Page (+19 lignes)
⏺ mcp__playwright__browser_type({"target": "e7", "element": "textbox \"Votre pseudo\"", "text": "play…)
⎿ ### Ran Playwright code (+3 lignes)
⏺ mcp__playwright__browser_click({"target": "e13", "element": "button \"Commencer la partie\""})
⎿ ### Ran Playwright code (+9 lignes)
⏺ mcp__playwright__browser_click({"target": "e18", "element": "button \"livenessProbe\" (answer option…)
⎿ ### Ran Playwright code (+9 lignes)
…
⏺ mcp__playwright__browser_click({"target": "e64", "element": "button \"Service\" (answer option)"})
⎿ ### Ran Playwright code (+9 lignes)
⏺ La partie est terminée. Score final : **30 %** pour playwright, et il est aussi premier du classement (seul entrant) : **playwright : 30 %**.
[fin] modèle(s) : claude-sonnet-5 ; entrée 64 + cache 1108906 ; sortie 2863 ; durée 61235 ms
L'agent lit la page par browser_snapshot, qui rend l'arbre d'accessibilité avec un identifiant par élément (e7, e13, e18), puis clique sur ces identifiants. Son résumé de fin de partie ne prouve rien ; la base tranche :
$ sqlite3 quizops.db 'select count(*) from scores'
1
$ sqlite3 quizops.db 'select pseudo, score from scores order by id desc limit 1'
playwright|30
Note : une partie de quiz coûte une minute et plus d'un million de tokens lus en cache, parce que chaque lecture de page repart dans la conversation. Un serveur de navigateur se branche pour une vérification ciblée, pas pour tourner en permanence.
Context7 indexe la documentation des bibliothèques et l'expose en deux outils : resolve-library-id trouve la bibliothèque, query-docs interroge son contenu. La question posée est celle du module 01, à laquelle le modèle seul répond par sa date de coupure.
Avec context7, quelle est la dernière version de FastAPI ? Réponds en une
ligne en citant la source.
⏺ ToolSearch({"query": "select:mcp__context7__resolve-library-id,mcp__context7__qu…)
⎿
⏺ mcp__context7__resolve-library-id({"query": "latest version", "libraryName": "FastAPI"})
⎿ Available Libraries: (+34 lignes)
⏺ mcp__context7__query-docs({"libraryId": "/websites/fastapi_tiangolo", "query": "latest release …)
⎿ ### 0.100.0 (2023-07-07) (+20 lignes)
⏺ mcp__context7__query-docs({"libraryId": "/websites/fastapi_tiangolo_reference", "query": "curre…)
⎿ ### FastAPI > version (+22 lignes)
⏺ Le contenu indexé par context7 (fastapi_tiangolo) ne remonte que jusqu'à la version 0.100.0 (2023-07-07) dans ses notes de version, sans mention d'une version plus récente.
L'agent a cherché dans une source externe et a dit exactement ce qu'il y a trouvé, sans inventer un numéro. Mais l'index ne contenait pas la réponse, et la vérité tient dans une ligne de shell :
$ curl -s https://pypi.org/pypi/fastapi/json | jq -r .info.version
0.141.1
Un index de documentation renseigne sur les API, les motifs d'usage et les migrations. Pour un numéro de version, la source reste le registre du paquet. Avec le CLAUDE.md du module 02, un serveur de documentation forme le contexte indexé du projet : le modèle cesse d'écrire du code d'après ses souvenirs. Context7 existe aussi en plugin, ce qui évite le claude mcp add :
/plugin install context7@claude-plugins-official
DBHub expose une base par son DSN et sait rester en lecture seule.
$ claude mcp add --transport stdio db -- npx -y @bytebase/dbhub --dsn "sqlite:///quizops.db" --readonly
Le même serveur couvre PostgreSQL, seul le DSN change.
$ claude mcp add --transport stdio pg -- npx -y @bytebase/dbhub --dsn "postgresql://lecteur:motdepasse@localhost:5432/quizops" --readonly
L'agent lit alors le schéma et les données réelles, au lieu de deviner les noms de colonnes à partir du code. Un mot de passe écrit dans la ligne de commande finit dans l'historique du shell : on crée un compte dédié en lecture seule et on passe le DSN par --env. Ces deux commandes n'ont pas été capturées pendant la rédaction de ce module ; elles sont données telles que l'éditeur du serveur les documente, et le TP 8 joue la première en direct.
Le serveur GitHub s'installe par le plugin officiel, qui embarque sa configuration MCP et son authentification.
/plugin install github@claude-plugins-official
L'agent va chercher les issues et les pull requests à la source, au lieu de votre reformulation. Le module 06 fait le même travail avec la commande gh, qui suffit tant qu'on reste dans le terminal.
Le plugin figma@claude-plugins-official donne à l'agent la lecture des maquettes : dimensions, couleurs, espacements, noms de composants, au lieu d'une estimation faite sur une capture d'écran. Le flux consiste à sélectionner un cadre dans Figma, à en donner le lien à l'agent, et à lui demander le composant correspondant. Ce serveur demande un compte Figma et un jeton d'accès personnel, ce qui n'a pas été mis en place pour cette formation : la section décrit ce que le serveur permet, elle ne le démontre pas.
Un serveur MCP est du code tiers qui accède à vos données et à vos outils : vérifier l'éditeur, comprendre le périmètre accordé, éviter les serveurs non maintenus.
/context le montre à la ligne MCP tools (deferred)..mcp.json de projet exécute des commandes sur votre poste. npx @playwright/mcp@latest télécharge et lance un paquet. Lisez le fichier avant de l'approuver, comme vous liriez un script d'installation.Note : la question d'approbation ne se pose qu'en session interactive. En mode
claude -p, les serveurs d'un.mcp.jsonsont chargés sans rien demander, sauf si vous passez--strict-mcp-config.
Vous avez, éparpillés dans le projet, un CLAUDE.md, des commandes, des skills, des sous-agents, des hooks, un .mcp.json. Un plugin est le paquet qui regroupe tout cela et s'installe en une commande.
Le dépôt de référence contient le plugin quizops-kit, huit fichiers qui reprennent l'outillage construit aux modules 05 et 06.
$ git ls-tree -r --name-only tp9-depart quizops-kit
quizops-kit/.claude-plugin/plugin.json
quizops-kit/.mcp.json
quizops-kit/commands/revue.md
quizops-kit/hooks/garde-fou.sh
quizops-kit/hooks/hooks.json
quizops-kit/skills/nouvelle-question/SKILL.md
quizops-kit/skills/nouvelle-question/modele.json
quizops-kit/skills/nouvelle-question/verifier.py
Seul .claude-plugin/plugin.json est obligatoire. Les dossiers commands/, skills/, agents/, hooks/ et le fichier .mcp.json sont facultatifs : un plugin qui ne contient qu'un skill est valide.
{
"name": "quizops-kit",
"description": "Outillage de l'équipe QuizOps : revue, ajout de question, hooks de formatage et de garde-fou, serveur MCP Playwright",
"version": "1.0.0",
"author": {
"name": "Formation Vibe Coding"
}
}
C'est le seul endroit où les hooks vivent dans un fichier hooks/hooks.json ; hors plugin, ils se déclarent dans settings.json. Le fichier reprend les deux hooks du module 06 ; voici le garde-fou seul, avec le détail qui change :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/garde-fou.sh"
}
]
}
]
}
}
Un plugin est installé à un emplacement que vous ne choisissez pas, donc aucun chemin en dur n'y survivrait. ${CLAUDE_PLUGIN_ROOT} désigne la racine du plugin une fois installé.
claude plugin init produit le squelette d'un plugin dans ~/.claude/skills/<nom>/, chargé dès la session suivante sous le nom <nom>@skills-dir. Pendant la mise au point, --plugin-dir charge un dossier de plugin pour la session en cours, sans l'installer ni toucher aux réglages ; en session, /reload-plugins recharge les plugins actifs après une modification.
$ claude plugin init quizops-kit --with skills hooks mcp
$ claude --plugin-dir ./quizops-kit
Avant de publier, claude plugin validate relit le manifeste du plugin, puis celui de la place de marché.
$ claude plugin validate ./quizops-kit
Validating plugin manifest: ~/projets/quizops/quizops-kit/.claude-plugin/plugin.json
✔ Validation passed
$ claude plugin validate .
Validating marketplace manifest: ~/projets/quizops/.claude-plugin/marketplace.json
✔ Validation passed
Un plugin s'installe depuis une place de marché, un catalogue déclaré dans un fichier .claude-plugin/marketplace.json. Celle d'Anthropic est ajoutée au premier démarrage interactif de Claude Code.
/plugin install github@claude-plugins-official
/plugin sans argument ouvre un panneau à cinq onglets : Discover pour parcourir les catalogues, Installed pour activer, désactiver ou désinstaller, Marketplaces pour ajouter et mettre à jour les catalogues, Errors pour les plugins qui n'ont pas chargé, Stats pour ce que chaque skill coûte en contexte et la fréquence à laquelle il se déclenche. L'installation demande une portée : user pour vous sur tous vos projets, project pour toute personne qui ouvre le dépôt, local pour vous sur ce dépôt seulement.
Un dossier suffit comme catalogue, ce qui permet d'essayer le plugin de l'équipe avant de le publier. Le dépôt de référence contient son propre marketplace.json à la racine.
$ claude plugin marketplace add ./
Adding marketplace…✔ Successfully added marketplace: quizops-local (declared in user settings)
$ claude plugin marketplace list
Configured marketplaces:
❯ quizops-local
Source: Directory (~/projets/quizops)
$ claude plugin install quizops-kit@quizops-local --scope project
Installing plugin "quizops-kit@quizops-local"...✔ Successfully installed plugin: quizops-kit@quizops-local (scope: project)
La portée project écrit dans .claude/settings.json, donc l'installation se versionne avec le code. Voici le fichier après l'installation, les deux hooks du module 06 retirés pour la lisibilité :
{
"permissions": {
"allow": [
"Bash(uv run pytest*)"
]
},
"enabledPlugins": {
"quizops-kit@quizops-local": true
}
}
$ claude plugin list
Installed plugins:
❯ quizops-kit@quizops-local
Version: 1.0.0
Scope: project
Status: ✔ enabled
Les skills d'un plugin sont préfixés par son nom, ce qui les distingue de ceux du projet. /context les liste séparément :
| Skill | Source | Tokens |
|-------------------------------|----------------------|--------|
| nouvelle-question | Project | ~60 |
| quizops-kit:nouvelle-question | Plugin (quizops-kit) | ~70 |
Ici le skill existe en double, parce que le dépôt garde encore sa version sous .claude/skills/. Le retrait se fait dans l'ordre inverse de l'installation.
$ claude plugin uninstall quizops-kit@quizops-local --scope project
✔ Successfully uninstalled plugin: quizops-kit (scope: project)
$ claude plugin marketplace remove quizops-local
✔ Successfully removed marketplace: quizops-local
Note : retirer une place de marché désinstalle les plugins qui en venaient. Un plugin peut contenir des hooks et des serveurs MCP, donc il exécute du code sur votre poste : l'installer engage la même confiance qu'une dépendance.
| Plugin | Ce qu'il apporte | Où on le voit |
|---|---|---|
github |
Serveur MCP GitHub préconfiguré : issues, pull requests, actions | Décrit plus haut ; le flux gh au module 06 |
figma |
Lecture des maquettes : dimensions, couleurs, composants | Décrit plus haut, non démontré |
context7 |
Le serveur Context7 sans claude mcp add |
Démontré plus haut |
security-guidance |
Relit chaque modification de l'agent et lui fait corriger les vulnérabilités courantes dans la même session | Installé en exercice optionnel du TP 8 |
pr-review-toolkit |
Sous-agents spécialisés dans la revue de pull request | Non démontré ; même principe que les sous-agents de revue du module 08 |
commit-commands |
/commit-commands:commit : indexe, rédige le message, committe |
Non démontré ; le message de commit généré depuis le diff est au module 06 |
frontend-design |
Cadrage visuel quand l'agent construit une interface | Non démontré |
ralph-loop |
Relance l'agent en boucle sur le même objectif jusqu'à un critère d'arrêt | Non démontré, voir ci-dessous |
skill-creator |
Dialogue qui produit l'arborescence complète d'un skill | Module 05 |
pyright-lsp |
Diagnostics Pyright renvoyés à l'agent après chaque édition Python | Module 04 |
ralph-loop mérite un mot. La boucle relance l'agent sans intervention humaine tant que le critère n'est pas atteint, ce qui consomme des tokens et produit des dizaines de modifications sans relecture intermédiaire. On la lance sur une branche jetable, avec git checkout -- . comme sortie de secours.
Sans plugin, l'arrivée d'une personne dans l'équipe suppose de lui expliquer quoi copier où. Avec un plugin, elle exécute deux commandes.
/plugin marketplace add https://github.com/equipe/outillage-claude
/plugin install quizops-kit@outillage-claude
La place de marché est un dépôt Git ordinaire, avec un fichier de catalogue à la racine. Le nom qui suit le @ est le champ name de ce fichier, pas celui du dépôt. Celui du dépôt de référence s'appelle quizops-local et pointe vers un plugin du même dépôt :
{
"name": "quizops-local",
"description": "Place de marché locale de la formation Vibe Coding",
"owner": {
"name": "Formation Vibe Coding"
},
"plugins": [
{
"name": "quizops-kit",
"source": "./quizops-kit",
"description": "Outillage de l'équipe QuizOps : revue, ajout de question, hooks et serveur MCP Playwright"
}
]
}
Pour éviter même la première commande, .claude/settings.json déclare la place de marché du côté du projet. Chacun n'a plus qu'à faire confiance au dossier à sa première session.
{
"extraKnownMarketplaces": {
"outillage-claude": {
"source": {
"source": "github",
"repo": "equipe/outillage-claude"
}
}
},
"enabledPlugins": {
"quizops-kit@outillage-claude": true
}
}
extraKnownMarketplaces ajoute le catalogue, enabledPlugins active le plugin. Un plugin venu d'une source externe reste à installer par chacun : Claude Code le signale comme non installé et affiche la commande claude plugin install à lancer.
Un dépôt interne fonctionne aussi bien qu'un dépôt public, et c'est la solution derrière un proxy d'entreprise : une place de marché locale ne dépend d'aucun accès sortant. Ce qui est propre au projet vit dans .claude/ et se versionne avec le code ; ce qui sert à plusieurs projets de l'équipe devient un plugin.
stdio ou en http avec claude mcp add ; la portée project écrit un .mcp.json versionné qui reste ⏸ Pending approval tant que personne ne l'a approuvé.mcp__serveur__outil et sont chargés à la demande ; /context compte leur catalogue sur la ligne MCP tools (deferred).0.100.0 quand PyPI affiche 0.141.1.plugin.json ; extraKnownMarketplaces et enabledPlugins le distribuent à l'équipe.TP associé : TP 8 : MCP et Plugins
➡️ Module suivant : Subagents, Orchestration et Gouvernance