Claude devient bien plus utile lorsqu'il cesse d'être une simple interface de chat.
Un serveur MCP local permet à Claude d'interagir avec votre machine réelle : fichiers locaux, commandes approuvées, captures d'écran et lancements d'applications. L'important n'est pas l'accès brut, mais un accès contrôlé.
Dans ce guide, nous allons construire un serveur MCP local pour Claude qui soit pratique, ciblé et suffisamment sûr pour être utilisé dans des flux de travail réels.
Une brève note avant de construire quoi que ce soit
Cet article évite délibérément la version irresponsable du « contrôle d'ordinateur ».
Nous n'allons pas donner à Claude un accès shell illimité, une autorisation complète sur le système de fichiers, ou la permission de modifier votre machine sans garde-fous. Le moyen le plus rapide de construire un mauvais serveur MCP local est d'exposer un énorme outil run_anything() et d'appeler ça innovation.
Le meilleur modèle est :
- répertoires autorisés
- commandes autorisées
- valeurs par défaut sûres
- journaux lisibles par l'humain
- réponses explicites
- séparation claire entre outils de lecture et d'action
Si Claude peut tout faire, vous avez construit une démo.
Si Claude peut faire les bonnes choses en toute sécurité, vous avez construit quelque chose d'utilisable.
Pourquoi cette architecture mérite d'être apprise
La valeur d'un serveur MCP local n'est pas la nouveauté. C'est la réduction de friction.
Sans couche d'outils locale, votre flux de travail ressemble à ceci :
- Demander à Claude quoi faire
- Copier la réponse
- Ouvrir le dossier vous-même
- Exécuter la commande vous-même
- Prendre la capture d'écran vous-même
- Coller le résultat dans le chat
Avec un serveur MCP local, cette boucle devient considérablement plus serrée. Claude peut inspecter le contexte nécessaire, utiliser des outils à portée étroite et renvoyer une réponse ancrée dans l'état réel de votre machine.
C'est utile pour :
- les flux de travail de développement
- l'inspection de journaux
- les opérations de contenu
- les pipelines de recherche
- l'automatisation de bureau
- les tâches administratives répétables
Et parce que la couche d'outils vous appartient, vous choisissez exactement où le modèle s'arrête.
Vous voulez apprendre l'IA et rester en avance dans votre carrière ?
Je partage :
Plus de 1 000 prompts IA
Outils et automatisations IA
Conseils de carrière et de croissance LinkedIn
Ressources tech et productivité sélectionnées
Abonnez-vous ici :
Suivez-moi pour plus de conseils IA
👇
Le design que nous construisons

Nous allons construire un serveur local avec cinq outils :
- list_files — voir ce qui existe dans les dossiers approuvés
- read_file — ouvrir des fichiers texte sûrs
- run_command — exécuter un petit ensemble de commandes locales approuvées
- take_screenshot — enregistrer une capture d'écran dans un emplacement connu
- open_target — ouvrir une application, un fichier, un dossier ou une URL

Ce périmètre est délibéré.
Il est suffisant pour rendre Claude vraiment utile sur une machine locale sans tomber dans une automatisation généralisée dangereuse.
Le modèle mental doit ressembler à ceci :
Claude → client MCP → serveur MCP local → outils ciblés → système d'exploitation
Claude ne doit jamais parler directement à votre système d'exploitation. Votre serveur MCP est le plan de contrôle au milieu.
La pile technologique
Pour une construction locale, Python est un choix propre car le SDK MCP officiel est mature, l'abstraction FastMCP est concise, et Python reste le langage le plus facile pour le travail avec le système de fichiers, les sous-processus et les scripts de bureau 4 2.
Nous allons utiliser :
- Python 3.11+
- mcp[cli] pour l'exécution du serveur MCP
- mss pour les captures d'écran multiplateformes
- les modules de la bibliothèque standard pour l'accès aux fichiers, les appels de sous-processus et la gestion du système d'exploitation
Configurez un nouveau projet :
1mkdir local-mcp-server2cd local-mcp-server3uv init --python 3.114uv add "mcp[cli]>=1.0,<2.0" "mss>=9.0,<10.0"
Le style FastMCP basé sur les décorateurs maintient la couche de protocole hors de votre chemin afin que vous puissiez vous concentrer sur la qualité des outils plutôt que sur le câblage 4 5.
Une structure de projet simple fonctionne bien :
1mkdir local-mcp-server2cd local-mcp-server3uv init --python 3.114uv add "mcp[cli]>=1.0,<2.0" "mss>=9.0,<10.0"
Vous n'avez pas besoin d'une architecture complexe pour la v1. Ce dont vous avez besoin, c'est de clarté.
Le serveur proprement dit
Créez server.py et commencez par une implémentation pilotée par les politiques.
1from __future__ import annotations23import json4import os5import platform6import shlex7import subprocess8from pathlib import Path9from typing import Any1011import mss12from mcp.server.fastmcp import FastMCP1314app = FastMCP("local-computer-control", json_response=True)1516HOME = Path.home()17PROJECT_ROOT = Path(__file__).parent.resolve()18CAPTURE_DIR = PROJECT_ROOT / "captures"19CAPTURE_DIR.mkdir(exist_ok=True)2021ALLOWED_ROOTS = [22 HOME / "Documents",23 HOME / "Desktop",24 PROJECT_ROOT,25]2627ALLOWED_COMMANDS = {28 "pwd",29 "ls",30 "git status",31 "git diff --stat",32 "python --version",33 "node --version",34 "npm --version",35}3637READABLE_EXTENSIONS = {38 ".txt",39 ".md",40 ".json",41 ".py",42 ".js",43 ".ts",44 ".tsx",45 ".jsx",46 ".yaml",47 ".yml",48 ".toml",49 ".csv",50 ".log",51}5253def _resolve_path(raw_path: str) -> Path:54 path = Path(raw_path).expanduser().resolve()55 for root in ALLOWED_ROOTS:56 root = root.resolve()57 if path == root or root in path.parents:58 return path59 raise ValueError(f"Path not allowed: {path}")6061def _ensure_safe_command(command: str) -> str:62 normalized = " ".join(shlex.split(command))63 if normalized not in ALLOWED_COMMANDS:64 raise ValueError(65 "Command not allowed. Add it explicitly to ALLOWED_COMMANDS if you really need it."66 )67 return normalized6869@app.tool()70def list_files(path: str = "~") -> dict[str, Any]:71 """List files and folders inside an approved directory."""72 target = _resolve_path(path)73 if not target.is_dir():74 raise ValueError(f"Not a directory: {target}")7576 items = []77 for child in sorted(target.iterdir(), key=lambda p: (not p.is_dir(), p.name.lower())):78 items.append(79 {80 "name": child.name,81 "path": str(child),82 "type": "directory" if child.is_dir() else "file",83 }84 )8586 return {87 "path": str(target),88 "count": len(items),89 "items": items,90 }9192@app.tool()93def read_file(path: str, max_chars: int = 12000) -> dict[str, Any]:94 """Read a safe text file from an approved location."""95 target = _resolve_path(path)96 if not target.is_file():97 raise ValueError(f"Not a file: {target}")98 if target.suffix.lower() not in READABLE_EXTENSIONS:99 raise ValueError(f"Unsupported file type: {target.suffix}")100101 content = target.read_text(encoding="utf-8", errors="replace")102 truncated = len(content) > max_chars103 content = content[:max_chars]104105 return {106 "path": str(target),107 "truncated": truncated,108 "content": content,109 }110111@app.tool()112def run_command(command: str, cwd: str | None = None, timeout: int = 15) -> dict[str, Any]:113 """Run one allowlisted local command."""114 safe_command = _ensure_safe_command(command)115 working_dir = _resolve_path(cwd) if cwd else PROJECT_ROOT116117 completed = subprocess.run(118 safe_command,119 shell=True,120 cwd=str(working_dir),121 capture_output=True,122 text=True,123 timeout=timeout,124 )125126 return {127 "command": safe_command,128 "cwd": str(working_dir),129 "returncode": completed.returncode,130 "stdout": completed.stdout.strip(),131 "stderr": completed.stderr.strip(),132 }133134@app.tool()135def take_screenshot(name: str = "latest") -> dict[str, Any]:136 """Capture a screenshot and save it locally."""137 output_path = CAPTURE_DIR / f"{name}.png"138139 with mss.mss() as sct:140 sct.shot(output=str(output_path))141142 return {143 "saved": True,144 "path": str(output_path),145 }146147@app.tool()148def open_target(target: str) -> dict[str, Any]:149 """Open an approved file, folder, app, or URL using the local OS."""150 system = platform.system().lower()151152 if target.startswith("http://") or target.startswith("https://"):153 resolved = target154 else:155 resolved = str(_resolve_path(target))156157 if system == "darwin":158 subprocess.run(["open", resolved], check=True)159 elif system == "windows":160 os.startfile(resolved) # type: ignore[attr-defined]161 else:162 subprocess.run(["xdg-open", resolved], check=True)163164 return {165 "opened": True,166 "target": resolved,167 }168169if __name__ == "__main__":170 app.run(transport="stdio")
C'est un serveur compact, mais l'important n'est pas sa longueur. L'important est la forme de l'interface :
- chaque outil a un travail très clair
- chaque outil renvoie des données structurées
- l'exécution des commandes est filtrée
- l'accès aux fichiers est limité
- les captures d'écran vont dans un dossier connu
C'est exactement ce que vous voulez dans un serveur MCP local.
Pourquoi ces outils sont conçus ainsi
Un contenu de qualité sur les agents logiciels ne devrait jamais s'arrêter à « voici le code ». La forme de l'outil est la vraie leçon.
list_files
Cet outil donne à Claude une surface de découverte sécurisée. Il doit pouvoir répondre à des questions comme :
- Qu'y a-t-il dans ce dossier de projet ?
- Quelles notes existent dans Documents ?
- Existe-t-il déjà un fichier journal que je peux inspecter ?
Mais il ne doit pas devenir un explorateur récursif de tout le disque.
read_file
C'est souvent l'outil local le plus utile de tous. Un énorme pourcentage du travail réel est encore caché dans des notes Markdown locales, des journaux, des CSV, des documents et des fichiers de projet.
La limite max_chars est importante. Les gros fichiers sont un problème de contexte et de latence. Renvoyer l'intégralité d'un fichier journal géant est rarement utile.
run_command
C'est là que la plupart des gens deviennent négligents.
Le modèle sécurisé n'est pas « autoriser l'accès shell, puis espérer le meilleur ». Le modèle sécurisé est « autoriser un tout petit ensemble de commandes exactes et vérifiables ». C'est pourquoi l'exemple utilise une liste blanche stricte.
take_screenshot
Un outil de capture d'écran est utile car il permet à Claude de participer aux flux de travail de bureau. Même si votre première version ne fait qu'enregistrer l'image sur le disque, c'est déjà utile pour les rapports, le débogage d'interface utilisateur, la capture de documentation et les transferts structurés.
open_target
Le contrôle d'application n'a pas besoin de commencer par l'automatisation de l'interface graphique. Pour de nombreux flux de travail, « ouvrir le bon dossier, fichier ou URL » est suffisant.
C'est une v1 plus durable que de prétendre avoir besoin d'une automatisation complète du curseur dès le premier jour.
Connecter le serveur à Claude
Les serveurs MCP locaux sont généralement exécutés via stdio, ce qui signifie que Claude lance le processus localement et communique directement avec lui via stdin/stdout. Pour un serveur de contrôle d'ordinateur local, c'est la bonne valeur par défaut car cela évite une exposition réseau inutile 4 5.
Claude Desktop prend en charge les serveurs MCP locaux via une configuration, où il lance le processus serveur pour vous. En pratique, utiliser des chemins absolus pour l'interpréteur et le script est la configuration la moins fragile car les environnements d'applications GUI locales sont souvent plus stricts que votre terminal 2.
Une configuration minimale ressemble à ceci :
1{2 "mcpServers": {3 "local-computer-control": {4 "command": "/absolute/path/to/python",5 "args": [6 "/absolute/path/to/local-mcp-server/server.py"7 ]8 }9 }10}
Si vous préférez uv, c'est également valable :
1{2 "mcpServers": {3 "local-computer-control": {4 "command": "/absolute/path/to/uv",5 "args": [6 "--directory",7 "/absolute/path/to/local-mcp-server",8 "run",9 "python",10 "server.py"11 ]12 }13 }14}
Après avoir enregistré la configuration et redémarré Claude, les outils du serveur devraient apparaître dans la liste des outils MCP locaux. La configuration MCP locale de Claude Desktop est construite exactement autour de ce modèle : lancer un processus local, se connecter via stdio, et exposer les outils au modèle 2 3.

Des prompts réellement utiles pour les tests
Une fois le serveur connecté, ne commencez pas par une orchestration compliquée. Commencez par des vérifications directes et simples.
Essayez des prompts comme :
- « Liste les fichiers dans mon dossier Bureau. »
- « Lis ~/Documents/todo.md et résume les trois priorités principales. »
- « Exécute git status dans mon dossier de projet local et explique ce qui a changé. »
- « Prends une capture d'écran nommée workspace-check. »
- « Ouvre mon README de projet. »
Si ces flux simples fonctionnent de manière cohérente, vous avez un serveur qui mérite d'être étendu.
Si ce n'est pas le cas, ajouter plus d'outils ne fera que masquer les vrais problèmes.
Où les serveurs MCP locaux deviennent réellement précieux
Le cas d'utilisation évident est le développement, mais ce n'est qu'un aspect.
Flux de travail du développeur
Claude peut :
- inspecter un dossier de dépôt
- lire un fichier de configuration
- exécuter git status
- capturer une capture d'écran d'un état de bogue
- ouvrir le répertoire du projet
Cela élimine déjà beaucoup de changements de contexte.
Flux de travail de recherche
Claude peut :
- lister les dossiers de recherche
- ouvrir et résumer des notes Markdown
- lire des CSV structurés
- enregistrer des captures d'écran d'outils ou de tableaux de bord
- ouvrir des fichiers sources ou des liens de navigateur
Flux de travail de contenu
Claude peut :
- analyser un dossier de brouillons
- lire des idées d'articles existantes
- capturer une capture d'écran d'une référence de design
- ouvrir le bon fichier d'écriture ou URL
- exécuter une commande limitée qui génère un artefact de construction ou une exportation de brouillon
Flux de travail opérationnel
Claude peut :
- inspecter les journaux à partir de répertoires approuvés
- exécuter une commande de diagnostic en lecture seule
- ouvrir le dossier ou le lien de tableau de bord pertinent
- enregistrer une capture d'écran de preuve
C'est le véritable objectif de l'architecture : pas le « contrôle d'ordinateur » comme un coup d'éclat, mais la compression du flux de travail.
La couche de sécurité est le produit
C'est la section que trop d'articles techniques trivialisent.
La partie dangereuse du MCP local n'est pas le protocole. C'est une mauvaise conception des permissions.
Si vous voulez que ce serveur soit utilisable au-delà d'une démo, construisez le modèle de sécurité tôt.

Utilisez des listes blanches de répertoires
Claude ne doit pouvoir voir que les chemins que vous approuvez explicitement. C'est pourquoi _resolve_path() est le cœur des outils de fichiers.
Utilisez des listes blanches de commandes
N'exposez jamais une exécution shell arbitraire dans une première version. Commencez par des commandes exactes que vous pouvez auditer ligne par ligne.
Séparez les outils de lecture des outils d'action
Les outils en lecture seule devraient être la valeur par défaut. Les outils d'action devraient être introduits délibérément.
Tout journaliser
Même un simple journal JSON en ajout seul rend le débogage et la confiance nettement meilleurs.
Ajoutez une couche de confirmation pour les écritures
Si vous ajoutez plus tard write_file, move_file ou delete_file, faites en sorte que ces outils nécessitent un deuxième jeton de confirmation ou restent désactivés par défaut.
Envisagez un mode de simulation (dry-run)
Pour les outils d'action, le mode dry-run est sous-estimé. Il permet à Claude d'expliquer ce qu'il ferait avant de le faire.
Exécutez sous un utilisateur restreint si possible
Si vous prenez l'automatisation locale au sérieux, ne donnez pas à votre serveur MCP plus de privilèges système qu'il n'en a besoin.
Une règle empirique utile :
- Niveau 1 : outils en lecture seule
- Niveau 2 : actions à faible risque comme ouvrir un fichier / ouvrir une application
- Niveau 3 : actions d'écriture confirmées
- Niveau 4 : actions destructrices que vous ne devriez probablement pas exposer à la légère
La plupart des gens n'ont jamais besoin du niveau 4.

Que améliorer après la v1
Une première version solide mérite de devenir plus capable.
Une fois le serveur de base stable, les prochaines améliorations sensées sont :
- Fichier de politique centralisé
Déplacez vos règles dans config/policy.json afin que les modifications soient déclaratives.
Exemple :
1{2 "allowed_roots": [3 "~/Documents",4 "~/Desktop",5 "./"6 ],7 "allowed_commands": [8 "pwd",9 "ls",10 "git status",11 "git diff --stat",12 "python --version"13 ]14}
- Journalisation structurée
Journalisez les appels d'outils, les horodatages, les arguments et les résultats dans logs/server.log ou un fichier JSONL.
- Exécution de commandes plus sûre
Au lieu d'un seul outil de commande générique, divisez les commandes en outils plus ciblés comme :
- git_status
- show_current_directory
- list_project_files
Cela facilite le choix de l'outil pour Claude et la sécurité pour vous.
- Meilleure gestion des captures d'écran
Vous pouvez évoluer de « enregistrer une capture d'écran sur le disque » vers :
- des captures horodatées
- la capture de la fenêtre active
- la capture d'une région
- des règles de conservation des fichiers
- Adaptateurs d'automatisation spécifiques au système d'exploitation
Sur macOS, vous pouvez ajouter plus tard AppleScript ou les Raccourcis. Sur Windows, PowerShell ou UI Automation. Sur Linux, des lanceurs spécifiques au bureau et des outils de fenêtrage.
Mais cela devrait venir après que le cœur local et banal soit fiable.
Erreurs courantes avec les serveurs MCP locaux
Les erreurs sont prévisibles.
Erreur 1 : Trop de pouvoir, trop tôt
Les gens aiment l'idée du contrôle total de l'ordinateur. Ils détestent déboguer cela. Commencez plus petit.
Erreur 2 : Noms d'outils vagues
Si les noms de vos outils sont ambigus, Claude les utilisera mal. Soyez explicite.
Mauvais :
- system_action
- computer_control
Meilleur :
- list_files
- read_file
- run_command
- take_screenshot
- open_target
Erreur 3 : Sorties non structurées
Un bloc de texte mélangé est plus difficile à raisonner pour Claude qu'un objet JSON propre.
Erreur 4 : Absence de journalisation
Si un outil échoue et que vous ne pouvez pas voir pourquoi, le système devient un jeu de devinettes.
Erreur 5 : Traiter le modèle comme la couche de contrôle
Claude est la couche de raisonnement. Votre serveur doit toujours être la couche d'application des règles.
Cette distinction est non négociable.
Ce que cette architecture fait de mieux que l'automatisation simple
L'automatisation de bureau traditionnelle se résume généralement à deux choses :
- un script GUI fragile
- des scripts isolés qui nécessitent qu'un humain sache exactement quand les exécuter
Un serveur MCP local change cela car Claude peut décider quel outil utiliser en fonction de la demande de l'utilisateur et du contexte disponible.
Cela signifie que vous n'automatisez pas seulement une commande. Vous construisez une couche de capacité locale sur laquelle le modèle peut raisonner.
C'est pourquoi MCP semble important. Ce n'est pas simplement un autre modèle d'intégration. C'est une manière plus propre d'exposer l'utilisation d'outils au modèle sans coder en dur chaque flux de travail possible dans la couche applicative.
Les limites à respecter
Même un bon serveur MCP local a des limitations réelles.
- L'automatisation de bureau peut être instable selon les systèmes d'exploitation.
- Les captures d'écran sont utiles, mais pas magiques.
- Le lancement d'applications est facile ; la manipulation fiable de l'interface utilisateur est plus difficile.
- L'accès shell générique est dangereux.
- Le gonflement du contexte est réel si les sorties des outils sont trop volumineuses.
- L'approbation humaine reste précieuse pour tout ce qui est important.
En d'autres termes : ne confondez pas « le modèle peut agir » avec « le modèle doit agir sans supervision ».
Le modèle le plus précieux est le contrôle collaboratif, pas l'autonomie aveugle.





