#!/bin/sh # Installe Drop comme serveur MCP pour Claude Code ou Claude Desktop (§17, phase 34). # # Le serveur MCP (bin/drop-mcp.mjs, phase 25) donne à l'assistant de vrais # outils — envoyer_texte, envoyer_fichier, lister_items, recuperer_fichier — # plutôt que des commandes shell à retenir. En échange, il demande Node.js et # une entrée dans la configuration du client : ce sont ces deux gestes que ce # script absorbe, pour que brancher Claude Code coûte la même chose que # brancher n'importe quoi d'autre — une ligne. # # Là où Node.js manque, ou pour tout autre assistant, `drop-ia` reste le chemin : # il ne dépend que de curl (bureau.php?telecharger=ia). # # sh installer-mcp.sh --url https://drop.exemple.fr [--nom NOM] # sh installer-mcp.sh --desinstaller # # Rien n'est écrit hors du dossier personnel : ni /usr, ni /etc, ni aucun # service système. Aucun droit d'administration n'est nécessaire. set -eu DONNEES="${XDG_DATA_HOME:-$HOME/.local/share}/drop" SERVEUR="$DONNEES/drop-mcp.mjs" CONFIG_DOSSIER="${XDG_CONFIG_HOME:-$HOME/.config}/drop" CONFIG_MCP="$CONFIG_DOSSIER/mcp.json" NOM_SERVEUR='drop' dire() { printf ' %s\n' "$1" } etape() { printf '\n== %s\n' "$1" } echec() { printf '\n Échec : %s\n\n' "$1" >&2 exit 1 } # L'aide est écrite en dur, jamais extraite du fichier : lancé par un tube # (« curl … | sh », la forme que propose bureau.php), « $0 » vaut « sh » et une # extraction par sed ne lirait rien — sans même échouer visiblement. aide() { cat <<'AIDE' Installe Drop comme serveur MCP pour Claude Code ou Claude Desktop. sh installer-mcp.sh --url https://drop.exemple.fr [--nom NOM] sh installer-mcp.sh --url … --cercle jeux sh installer-mcp.sh --desinstaller [--cercle jeux] --cercle donne au serveur son propre nom et sa propre configuration : le client en enregistre un par cercle, à brancher autant de fois que voulu. Le code d'appairage s'obtient depuis Drop : menu ⚙ → Appairer un appareil, après avoir basculé sur le cercle voulu — c'est lui qui détermine le cercle auquel l'assistant aura accès. Il vaut deux minutes et une seule fois. Sans Node.js, utilise plutôt le client shell, qui ne dépend que de curl : curl -fsSL /bureau.php?telecharger=ia | sh -s -- installer --url AIDE } # ------------------------------------------------------------- désinstallation desinstaller() { etape 'Désinstallation' if command -v claude >/dev/null 2>&1; then claude mcp remove "$NOM_SERVEUR" >/dev/null 2>&1 && dire "serveur « $NOM_SERVEUR » retiré de Claude Code" || dire "aucun serveur « $NOM_SERVEUR » enregistré dans Claude Code" fi if [ -f "$SERVEUR" ]; then rm -f "$SERVEUR" dire "retiré : $SERVEUR" fi # Le jeton est laissé en place à dessein : le supprimer ici donnerait # l'illusion d'avoir coupé l'accès, alors que l'appareil reste actif côté # serveur tant que personne ne l'a révoqué. if [ -f "$CONFIG_MCP" ]; then printf '\n' dire "La configuration $CONFIG_MCP contient encore un jeton valide." dire 'Pour couper vraiment l’accès : Drop → menu ⚙ → Mes appareils → Révoquer' dire "sur l’appareil de type « ia ». Puis : rm $CONFIG_MCP" fi printf '\n Désinstallation terminée.\n\n' exit 0 } # proposer_code — un code d'appairage pour rejoindre ce même cercle depuis un # autre appareil, affiché dans la foulée de l'installation. Le cercle qu'on # vient de brancher n'a souvent qu'un seul appareil : sans ce code, y accéder # depuis un téléphone ou un navigateur demanderait un accès au serveur, alors # que tout vient de se jouer ici. # # Le jeton est relu depuis la configuration que node vient d'écrire ; il ne sort # jamais de cette fonction. Un échec ne remonte pas : l'installation a réussi. proposer_code() { jeton=$(sed -n 's/.*"jeton"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$CONFIG_MCP" 2>/dev/null | head -n 1) [ -n "$jeton" ] || return 0 # Le jeton ne passe pas en argument de curl : argv est lisible par tout compte # local (/proc//cmdline, ps -ef), ce qui exposerait la crédence permanente # du cercle pendant l'installation (scan sécurité, F8 et F18). --config - le # fait lire sur l'entrée standard. reponse=$(printf 'header = "Authorization: Bearer %s"\n' "$jeton" | curl --config - -sS -X POST "$url/api/appairage.php" 2>/dev/null) || return 0 code_appairage=$(printf '%s' "$reponse" | sed -n 's/.*"code":"\([0-9]*\)".*/\1/p') [ -n "$code_appairage" ] || return 0 etape 'Ouvrir ce cercle sur un autre appareil' printf '\n %s\n\n' "$code_appairage" dire "à saisir sur $url/?code=$code_appairage" dire '(ou dans Drop : menu ⚙ → Rejoindre un autre cercle)' dire '' dire 'Valable 120 secondes, une seule fois. Pour un autre code plus tard :' dire 'depuis Drop, menu ⚙ → Appairer un appareil.' printf '\n' } # ------------------------------------------------------------------ arguments code='' url='' nom='Claude (MCP)' cercle='' desinstallation=0 while [ $# -gt 0 ]; do case "$1" in --desinstaller) desinstallation=1; shift ;; --url) url="${2:-}"; shift 2 ;; --url=*) url="${1#--url=}"; shift ;; --nom) nom="${2:-}"; shift 2 ;; --nom=*) nom="${1#--nom=}"; shift ;; --cercle) cercle="${2:-}"; shift 2 ;; --cercle=*) cercle="${1#--cercle=}"; shift ;; -h|--aide|aide) aide; exit 0 ;; *) code="$1"; shift ;; esac done # Un cercle nommé donne son propre serveur MCP et sa propre configuration : le # client en enregistre un par cercle, chacun avec son jeton et ses outils. Sans # --cercle, on garde les noms canoniques, qui restent le cas courant. if [ -n "$cercle" ]; then # Un nom de cercle vient de l'utilisateur et sert ici à composer un nom de # fichier : tout ce qui n'est pas alphanumérique est réduit à un tiret. suffixe=$(printf '%s' "$cercle" | tr -c 'A-Za-z0-9' '-' | sed 's/^-*//; s/-*$//') [ -n "$suffixe" ] || echec 'nom de cercle inutilisable' NOM_SERVEUR="drop-$suffixe" CONFIG_MCP="$CONFIG_DOSSIER/mcp-$suffixe.json" fi [ "$desinstallation" -eq 1 ] && desinstaller # L'URL peut déjà être connue d'un appairage précédent : un code seul ne dit pas # à quel serveur il s'adresse. if [ -z "$url" ] && [ -f "$CONFIG_MCP" ]; then url=$(sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$CONFIG_MCP" | head -n 1) fi [ -n "$code" ] || echec 'code d’appairage manquant. Usage : sh installer-mcp.sh --url https://drop.exemple.fr' [ -n "$url" ] || echec 'URL du serveur inconnue. Ajoute : --url https://drop.exemple.fr' url="${url%/}" # -------------------------------------------------------------- prérequis etape 'Vérification' command -v curl >/dev/null 2>&1 || echec 'curl est nécessaire pour télécharger le serveur.' if ! command -v node >/dev/null 2>&1; then printf '\n' dire 'Node.js est introuvable sur cette machine.' dire 'Le serveur MCP en a besoin ; sans lui, utilise plutôt le client shell :' dire '' dire " curl -fsSL $url/bureau.php?telecharger=ia | sh -s -- installer $code --url $url" dire '' dire 'Il ne dépend que de curl et fait le même travail, en commandes plutôt' dire 'qu’en outils natifs.' printf '\n' exit 1 fi version_node=$(node --version 2>/dev/null || printf 'inconnue') dire "Node.js $version_node" # ------------------------------------------------------------- installation etape 'Installation du serveur MCP' mkdir -p "$DONNEES" temporaire="$SERVEUR.telechargement.$$" trap 'rm -f "$temporaire"' EXIT INT TERM curl -fsSL "$url/bureau.php?telecharger=drop-mcp" -o "$temporaire" || echec "téléchargement impossible depuis $url/bureau.php?telecharger=drop-mcp" # Une page d'erreur servie en 200 passerait le test de curl : mieux vaut # refuser tout de suite que d'installer un fichier qui ne démarrera jamais. head -n 1 "$temporaire" | grep -q '^#!/usr/bin/env node' || echec 'le fichier téléchargé n’est pas le serveur MCP de Drop' mv "$temporaire" "$SERVEUR" chmod 755 "$SERVEUR" trap - EXIT INT TERM dire "installé : $SERVEUR" # ---------------------------------------------------------------- appairage etape 'Appairage' # Le code passe par l'environnement, pas par argv : pendant les 120 secondes de sa # validité, qui le lit dans la table des processus peut le consommer le premier et # s'appairer à la place de l'utilisateur, qui ne verrait qu'un « appairage refusé » # (scan sécurité, F8). DROP_MCP_CONFIG="$CONFIG_MCP" DROP_MCP_CODE="$code" node "$SERVEUR" appairer --url "$url" --nom "$nom" || echec 'appairage refusé — le code est peut-être expiré ou déjà utilisé.' # ------------------------------------------------------- enregistrement client etape 'Enregistrement auprès du client' if command -v claude >/dev/null 2>&1; then # Un enregistrement précédent bloquerait l'ajout : le retirer d'abord rend # le script rejouable, ce qui est le cas normal après un changement de code. claude mcp remove "$NOM_SERVEUR" >/dev/null 2>&1 || true if claude mcp add "$NOM_SERVEUR" -e "DROP_MCP_CONFIG=$CONFIG_MCP" -- node "$SERVEUR"; then dire "serveur « $NOM_SERVEUR » enregistré dans Claude Code" printf '\n Terminé. Redémarre Claude Code : les outils Drop y apparaîtront\n' printf ' (envoyer_texte, envoyer_fichier, lister_items, recuperer_fichier).\n' proposer_code exit 0 fi dire 'enregistrement automatique impossible — la configuration manuelle suit.' else dire 'la commande « claude » est absente : configuration manuelle ci-dessous.' fi printf '\n Pour Claude Desktop, ajoute ceci à claude_desktop_config.json :\n\n' cat <