Claude diventa molto più utile quando smette di essere solo un'interfaccia di chat.
Un server MCP locale permette a Claude di interagire con la tua macchina reale: file locali, comandi approvati, screenshot e avvio di applicazioni. La parte importante non è l'accesso diretto. È l'accesso controllato.
In questa guida, costruiremo un server MCP locale per Claude che sia pratico, mirato e abbastanza sicuro da essere usato in flussi di lavoro reali.
Una nota rapida prima di costruire qualsiasi cosa
Questo articolo evita intenzionalmente la versione irresponsabile del "controllo del computer."
Non daremo a Claude accesso illimitato alla shell, autorità completa sul filesystem o il permesso di modificare la tua macchina senza protezioni. Il modo più veloce per costruire un server MCP locale scadente è esporre un enorme strumento run_anything() e chiamarlo innovazione.
Il modello migliore è:
- directory consentite
- comandi consentiti
- impostazioni predefinite sicure
- log leggibili dall'uomo
- risposte esplicite
- chiara separazione tra strumenti di sola lettura e strumenti d'azione
Se Claude può fare tutto, hai costruito una demo.
Se Claude può fare le cose giuste in modo sicuro, hai costruito qualcosa di utilizzabile.
Perché vale la pena imparare questa architettura
Il valore di un server MCP locale non è la novità. È la riduzione dell'attrito.
Senza un livello di strumenti locale, il tuo flusso di lavoro è così:
- Chiedi a Claude cosa fare
- Copia la risposta
- Apri tu la cartella
- Esegui tu il comando
- Fai tu lo screenshot
- Incolla il risultato nella chat
Con un server MCP locale, quel ciclo diventa molto più stretto. Claude può ispezionare il contesto di cui ha bisogno, usare strumenti con ambito limitato e restituire una risposta basata sullo stato effettivo della tua macchina.
Questo è utile per:
- flussi di lavoro di sviluppo
- ispezione dei log
- operazioni sui contenuti
- pipeline di ricerca
- automazione del desktop
- attività amministrative ripetitive
E poiché il livello degli strumenti è tuo, scegli esattamente dove si ferma il modello.
Vuoi imparare l'IA e rimanere al passo nella tua carriera?
Condivido:
Oltre 1.000 prompt IA
Strumenti IA e automazioni
Consigli di carriera e crescita su LinkedIn
Risorse curate su tecnologia e produttività
Iscriviti qui:
Seguimi per altri consigli sull'IA
👇
Il design che stiamo costruendo

Costruiremo un server locale con cinque strumenti:
- list_files — vedere cosa esiste all'interno delle cartelle approvate
- read_file — aprire file di testo sicuri
- run_command — eseguire un piccolo insieme di comandi locali approvati
- take_screenshot — salvare uno screenshot in una posizione nota
- open_target — aprire un'app, un file, una cartella o un URL

Quell'ambito è deliberato.
È abbastanza per rendere Claude significativamente utile su una macchina locale senza cadere in un'automazione generica e insicura.
Il modello mentale dovrebbe essere questo:
Claude → client MCP → server MCP locale → strumenti mirati → sistema operativo
Claude non dovrebbe mai parlare direttamente al tuo sistema operativo. Il tuo server MCP è il piano di controllo nel mezzo.
Lo stack
Per una build locale, Python è una scelta pulita perché l'SDK MCP ufficiale è maturo, l'astrazione FastMCP è concisa e Python rimane il linguaggio più semplice per lavori di scripting su filesystem, subprocess e desktop 4 2.
Useremo:
- Python 3.11+
- mcp[cli] per il runtime del server MCP
- mss per screenshot multipiattaforma
- moduli della libreria standard per accesso ai file, chiamate subprocess e gestione del sistema operativo
Imposta un nuovo progetto:
1mkdir local-mcp-server2cd local-mcp-server3uv init --python 3.114uv add "mcp[cli]>=1.0,<2.0" "mss>=9.0,<10.0"
Lo stile FastMCP basato su decorator tiene il livello del protocollo fuori dai piedi in modo che tu possa concentrarti sulla qualità degli strumenti invece che sul cablaggio 4 5.
Una struttura di progetto semplice funziona bene:
1mkdir local-mcp-server2cd local-mcp-server3uv init --python 3.114uv add "mcp[cli]>=1.0,<2.0" "mss>=9.0,<10.0"
Non hai bisogno di un'architettura complessa per la v1. Ciò di cui hai bisogno è chiarezza.
Il server vero e proprio
Crea server.py e inizia con un'implementazione basata su policy.
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"Percorso non consentito: {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 "Comando non consentito. Aggiungilo esplicitamente a ALLOWED_COMMANDS se ne hai davvero bisogno."66 )67 return normalized6869@app.tool()70def list_files(path: str = "~") -> dict[str, Any]:71 """Elenca file e cartelle all'interno di una directory approvata."""72 target = _resolve_path(path)73 if not target.is_dir():74 raise ValueError(f"Non è una 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 """Legge un file di testo sicuro da una posizione approvata."""95 target = _resolve_path(path)96 if not target.is_file():97 raise ValueError(f"Non è un file: {target}")98 if target.suffix.lower() not in READABLE_EXTENSIONS:99 raise ValueError(f"Tipo di file non supportato: {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 """Esegue un comando locale consentito."""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 """Cattura uno screenshot e lo salva localmente."""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 """Apre un file, una cartella, un'app o un URL approvato usando il sistema operativo locale."""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")
Questo è un server compatto, ma la parte importante non è la sua lunghezza. La parte importante è la forma dell'interfaccia:
- ogni strumento ha un compito molto chiaro
- ogni strumento restituisce dati strutturati
- l'esecuzione dei comandi è limitata
- l'accesso ai file è radicato
- gli screenshot vanno in una cartella nota
Questo è esattamente ciò che vuoi in un server MCP locale.
Perché questi strumenti sono progettati in questo modo
I contenuti avanzati sugli strumenti per agenti non dovrebbero mai fermarsi a "ecco il codice." La forma dello strumento è la vera lezione.
list_files
Questo strumento dà a Claude una superficie di scoperta sicura. Dovrebbe essere in grado di rispondere a domande come:
- Cosa c'è in questa cartella di progetto?
- Quali note esistono in Documents?
- Esiste già un file di log che posso ispezionare?
Ma non dovrebbe diventare un crawler ricorsivo dell'intero disco.
read_file
Questo è spesso lo strumento locale più utile di tutti. Una percentuale enorme del lavoro reale è ancora nascosta in note Markdown locali, log, CSV, documenti e file di progetto.
Il limite max_chars è importante. I file di grandi dimensioni sono un problema di contesto e latenza. Restituire l'intero contenuto di un file di log enorme è raramente utile.
run_command
Qui è dove la maggior parte delle persone diventa sciatta.
Il modello sicuro non è "consenti l'accesso alla shell, poi spera per il meglio." Il modello sicuro è "consenti un minuscolo insieme di comandi esatti e verificabili." Ecco perché l'esempio usa una lista di consentiti rigorosa.
take_screenshot
Uno strumento per screenshot è prezioso perché permette a Claude di partecipare ai flussi di lavoro del desktop. Anche se la tua prima versione salva solo l'immagine su disco, è già utile per report, debug dell'interfaccia utente, cattura di documentazione e passaggi di consegne strutturati.
open_target
Il controllo delle app non deve iniziare con l'automazione dell'interfaccia grafica. Per molti flussi di lavoro, "apri la cartella, il file o l'URL giusto" è sufficiente.
Questa è una v1 più duratura che fingere di aver bisogno della piena automazione del cursore dal primo giorno.
Connettere il server a Claude
I server MCP locali sono comunemente eseguiti su stdio, il che significa che Claude avvia il processo localmente e comunica con esso direttamente tramite stdin/stdout. Per un server di controllo del computer locale, questa è l'impostazione predefinita corretta perché evita inutili esposizioni di rete 4 5.
Claude Desktop supporta i server MCP locali tramite configurazione, dove avvia il processo del server per te. In pratica, usare percorsi assoluti per l'interprete e lo script è la configurazione meno fragile perché gli ambienti delle app GUI locali sono spesso più restrittivi del tuo terminale 2.
Una configurazione minima è questa:
1{2 "mcpServers": {3 "local-computer-control": {4 "command": "/percorso/assoluto/per/python",5 "args": [6 "/percorso/assoluto/per/local-mcp-server/server.py"7 ]8 }9 }10}
Se preferisci uv, va bene anche quello:
1{2 "mcpServers": {3 "local-computer-control": {4 "command": "/percorso/assoluto/per/uv",5 "args": [6 "--directory",7 "/percorso/assoluto/per/local-mcp-server",8 "run",9 "python",10 "server.py"11 ]12 }13 }14}
Dopo aver salvato la configurazione e riavviato Claude, gli strumenti del server dovrebbero apparire nell'elenco degli strumenti MCP locali. La configurazione MCP locale di Claude Desktop è costruita esattamente su questo modello: avvia un processo locale, connettiti tramite stdio ed esponi gli strumenti al modello 2 3.

Prompt che sono effettivamente utili per i test
Una volta che il server è connesso, non iniziare con orchestrazioni complicate. Inizia con controlli diretti e banali.
Prova prompt come:
- "Elenca i file nella mia cartella Desktop."
- "Leggi ~/Documents/todo.md e riassumi le tre priorità principali."
- "Esegui git status nella mia cartella di progetto locale e spiega cosa è cambiato."
- "Fai uno screenshot chiamato workspace-check."
- "Apri il README del mio progetto."
Se questi flussi semplici funzionano in modo coerente, hai un server che vale la pena espandere.
Se non funzionano, aggiungere più strumenti nasconderà solo i veri problemi.
Dove i server MCP locali diventano veramente preziosi
Il caso d'uso ovvio è lo sviluppo, ma è solo una corsia.
Flusso di lavoro dello sviluppatore
Claude può:
- ispezionare una cartella del repository
- leggere un file di configurazione
- eseguire git status
- catturare uno screenshot di uno stato di bug
- aprire la directory del progetto
Questo elimina già molti cambi di contesto.
Flusso di lavoro della ricerca
Claude può:
- elencare le cartelle di ricerca
- aprire e riassumere note Markdown
- leggere CSV strutturati
- salvare screenshot da strumenti o dashboard
- aprire file sorgente o link del browser
Flusso di lavoro dei contenuti
Claude può:
- scansionare una cartella di bozze
- leggere idee di post esistenti
- catturare uno screenshot di un riferimento di design
- aprire il file di scrittura o l'URL giusto
- eseguire un comando limitato che genera un artefatto di build o un'esportazione di bozza
Flusso di lavoro operativo
Claude può:
- ispezionare i log dalle directory approvate
- eseguire un comando diagnostico di sola lettura
- aprire la cartella pertinente o il link della dashboard
- salvare uno screenshot come prova
Questo è il vero punto dell'architettura: non il "controllo del computer" come trovata, ma la compressione del flusso di lavoro.
Il livello di sicurezza è il prodotto
Questa è la sezione che troppi articoli tecnici banalizzano.
La parte pericolosa dell'MCP locale non è il protocollo. È una cattiva progettazione dei permessi.
Se vuoi che questo server sia utilizzabile oltre una demo, costruisci il modello di sicurezza all'inizio.

Usa liste di directory consentite
Claude dovrebbe essere in grado di vedere solo i percorsi che approvi esplicitamente. Ecco perché _resolve_path() è il cuore degli strumenti per i file.
Usa liste di comandi consentiti
Non esporre mai l'esecuzione arbitraria della shell in una prima versione. Inizia con comandi esatti che puoi controllare riga per riga.
Separa gli strumenti di lettura dagli strumenti d'azione
Gli strumenti di sola lettura dovrebbero essere l'impostazione predefinita. Gli strumenti d'azione dovrebbero essere introdotti deliberatamente.
Registra tutto
Anche un semplice log JSON append-only rende il debug e la fiducia enormemente migliori.
Aggiungi un livello di conferma per le scritture
Se in seguito aggiungi write_file, move_file o delete_file, rendi questi strumenti che richiedono un secondo token di conferma o lasciali disabilitati per impostazione predefinita.
Considera una modalità di simulazione
Per gli strumenti che eseguono azioni, la modalità di simulazione è sottovalutata. Permette a Claude di spiegare cosa farebbe prima di farlo.
Esegui sotto un utente con restrizioni quando possibile
Se fai sul serio con l'automazione locale, non dare al tuo server MCP più privilegi del sistema operativo di quanto necessario.
Una buona regola pratica:
- Livello 1: strumenti di sola lettura
- Livello 2: azioni a basso rischio come apri file / apri app
- Livello 3: azioni di scrittura confermate
- Livello 4: azioni distruttive che probabilmente non dovresti esporre casualmente
La maggior parte delle persone non ha mai bisogno del Livello 4.

Cosa migliorare dopo la v1
Una solida prima versione guadagna il diritto di diventare più capace.
Una volta che il server di base è stabile, i prossimi aggiornamenti sensati sono:
- File di policy centralizzato
Sposta le tue regole in config/policy.json in modo che le modifiche siano dichiarative.
Esempio:
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}
- Logging strutturato
Registra le chiamate agli strumenti, i timestamp, gli argomenti e i risultati in logs/server.log o in un file JSONL.
- Esecuzione di comandi più sicura
Invece di un singolo strumento di comando generico, suddividi i comandi in strumenti più mirati come:
- git_status
- show_current_directory
- list_project_files
Questo rende la scelta dello strumento più facile per Claude e la sicurezza più facile per te.
- Migliore gestione degli screenshot
Puoi evolvere da "salva uno screenshot su disco" a:
- catture con timestamp
- cattura della finestra attiva
- cattura di una regione
- regole di conservazione dei file
- Adattatori di automazione specifici per sistema operativo
Su macOS, potresti in seguito aggiungere AppleScript o Shortcuts. Su Windows, PowerShell o UI Automation. Su Linux, lanciatori specifici del desktop e strumenti per finestre.
Ma questo dovrebbe venire dopo che il noioso nucleo locale è affidabile.
Errori comuni che le persone fanno con i server MCP locali
Gli errori sono prevedibili.
Errore 1: Troppo potere, troppo presto
Alla gente piace l'idea del controllo totale del computer. A loro non piace fare il debug. Inizia in piccolo.
Errore 2: Nomi di strumenti vaghi
Se i nomi dei tuoi strumenti sono ambigui, Claude li userà male. Sii esplicito.
Male:
- system_action
- computer_control
Meglio:
- list_files
- read_file
- run_command
- take_screenshot
- open_target
Errore 3: Output non strutturati
Un blob di testo misto è più difficile da elaborare per Claude rispetto a un oggetto JSON pulito.
Errore 4: Nessun logging
Se uno strumento fallisce e non puoi vedere perché, il sistema diventa un'ipotesi.
Errore 5: Trattare il modello come il livello di controllo
Claude è il livello di ragionamento. Il tuo server deve essere ancora il livello di applicazione.
Quella distinzione non è negoziabile.
Cosa fa questa architettura meglio dell'automazione semplice
L'automazione desktop tradizionale è di solito una di due cose:
- scripting GUI fragile
- script isolati che richiedono che un umano sappia esattamente quando eseguirli
Un server MCP locale cambia questo perché Claude può decidere quale strumento usare in base alla richiesta dell'utente e al contesto disponibile.
Questo significa che non stai solo automatizzando un comando. Stai costruendo un livello di capacità locale su cui il modello può ragionare.
Ecco perché MCP sembra importante. Non è semplicemente un altro modello di integrazione. È un modo più pulito per esporre l'uso degli strumenti al modello senza codificare ogni possibile flusso di lavoro nel livello dell'applicazione.
I limiti che dovresti rispettare
Anche un buon server MCP locale ha limiti reali.
- L'automazione desktop può essere instabile tra i sistemi operativi.
- Gli screenshot sono utili, ma non magici.
- L'avvio di app è facile; la manipolazione affidabile dell'interfaccia utente è più difficile.
- L'accesso generico alla shell è pericoloso.
- Il gonfiamento del contesto è reale se gli output degli strumenti sono troppo grandi.
- L'approvazione umana è ancora preziosa per qualsiasi cosa di conseguenza.
In altre parole: non confondere "il modello può eseguire azioni" con "il modello dovrebbe agire senza supervisione."
Il modello più prezioso è il controllo collaborativo, non l'autonomia cieca.





