Se usi Claude o un altro assistente e vorresti che potesse davvero fare qualcosa — leggere i tuoi file, interrogare un database, chiamare un'API interna — invece di limitarsi a rispondere, la strada standard nel 2026 è il Model Context Protocol (MCP). In questa guida costruiamo da zero un server MCP in Python e lo colleghiamo a Claude Desktop, con codice funzionante e i comandi reali. È un tutorial di livello intermedio-avanzato: al termine avrai un «strumento» personalizzato che l'IA può invocare.
A chi serve e cosa otterrai
Questa guida è per sviluppatori (anche alle prime armi con l'IA) che vogliono estendere un assistente con capacità su misura. MCP è un protocollo aperto, introdotto da Anthropic e oggi adottato da molti client, che standardizza il modo in cui un modello si collega a strumenti e dati esterni: invece di scrivere un'integrazione diversa per ogni assistente, ne scrivi una sola compatibile con tutti. Otterrai un server che espone due strumenti — uno che salva note, uno che le rilegge — e che Claude potrà usare durante la conversazione.
Prerequisiti
- Un computer con macOS, Windows o Linux e Python 3.10 o superiore.
- uv, il gestore di progetti e pacchetti Python veloce che useremo (in alternativa va bene anche
pip). - Un client MCP: useremo Claude Desktop (gratuito), ma il server funziona con qualsiasi client compatibile.
- Dimestichezza di base con il terminale.
Passo 1: installare uv e creare il progetto
Installa uv (su macOS/Linux):
curl -LsSf https://astral.sh/uv/install.sh | sh
Su Windows, da PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Chiudi e riapri il terminale, poi crea il progetto e aggiungi l'SDK ufficiale MCP:
uv init note-server
cd note-server
uv add "mcp[cli]"
Il pacchetto mcp[cli] include sia la libreria sia gli strumenti da riga di comando che useremo per testare e installare il server.
Passo 2: scrivere il server
Crea un file server.py con questo contenuto. Usiamo FastMCP, il modo più rapido per definire strumenti: ogni funzione decorata con @mcp.tool() diventa uno strumento che il modello può chiamare, e la docstring spiega al modello a cosa serve.
from mcp.server.fastmcp import FastMCP
# Il nome identifica il server nel client
mcp = FastMCP("note-server")
# Un semplice archivio in memoria (in un caso reale useresti un file o un DB)
NOTE = []
@mcp.tool()
def salva_nota(testo: str) -> str:
"""Salva una nota di testo e restituisce una conferma."""
NOTE.append(testo)
return f"Nota salvata. Totale note: {len(NOTE)}"
@mcp.tool()
def leggi_note() -> str:
"""Restituisce tutte le note salvate, numerate."""
if not NOTE:
return "Nessuna nota salvata."
return "\n".join(f"{i+1}. {n}" for i, n in enumerate(NOTE))
if __name__ == "__main__":
# 'stdio' e' il trasporto usato dai client desktop locali
mcp.run(transport="stdio")
Poche righe, ma sufficienti: abbiamo definito due strumenti con tipi espliciti (testo: str) e descrizioni. I tipi sono importanti, perché il client li mostra al modello e lo aiutano a passare gli argomenti corretti.
Cosa succede sotto il cofano
Vale la pena capire il meccanismo. Quando parte, il server annuncia al client l'elenco degli strumenti disponibili, con nome, descrizione e tipi degli argomenti. Durante la conversazione, se il modello ritiene utile uno strumento, il client — previa autorizzazione dell'utente — invia al server una richiesta con gli argomenti; il server esegue la funzione e restituisce il risultato, che il modello usa per formulare la risposta. La comunicazione avviene con messaggi in formato JSON-RPC su un «trasporto»: in locale è stdio (input/output standard tra i due processi), in rete è l'HTTP. Il bello di MCP è proprio questo: tu scrivi solo la funzione Python, il protocollo si occupa del resto e del fatto che il tuo strumento sia comprensibile a qualunque client compatibile.
Un secondo strumento: chiamare un'API esterna
Gli strumenti diventano interessanti quando toccano il mondo reale. Aggiungiamo uno strumento che interroga un'API pubblica — qui un semplice servizio di orario — per mostrare come integrare dati esterni. Aggiungi al file:
import httpx
@mcp.tool()
def orario_utc() -> str:
"""Restituisce data e ora correnti in formato UTC."""
r = httpx.get("https://worldtimeapi.org/api/timezone/Etc/UTC", timeout=10)
r.raise_for_status()
dati = r.json()
return f"Orario UTC: {dati['datetime']}"
Ricordati di aggiungere la dipendenza con uv add httpx. Dopo aver riavviato il client, potrai chiedere «che ore sono in UTC?» e Claude userà il tuo strumento invece di tirare a indovinare. Lo stesso schema vale per un'API aziendale: incapsuli la chiamata in una funzione, la decori con @mcp.tool() e l'assistente acquisisce quella capacità.
Esporre dati in sola lettura con una risorsa
Se invece vuoi dare al modello del contesto da leggere — non un'azione, ma un dato — usi una risorsa. Esempio: esporre un file di configurazione.
@mcp.resource("config://app")
def config_app() -> str:
"""Espone il contenuto del file di configurazione."""
with open("config.txt", encoding="utf-8") as f:
return f.read()
La differenza concettuale è utile: gli strumenti fanno cose (e possono modificare lo stato), le risorse forniscono informazioni. Tenerle distinte rende il server più chiaro e più sicuro.
Passo 3: testare il server con l'inspector
Prima di collegarlo a Claude, conviene verificare che funzioni. L'SDK include un «inspector» con interfaccia web:
uv run mcp dev server.py
Il comando avvia il server e apre uno strumento in cui puoi vedere gli strumenti esposti, chiamarli a mano e leggerne la risposta. Se salva_nota e leggi_note compaiono e rispondono, il server è pronto.
Passo 4: collegarlo a Claude Desktop
Il modo più semplice è lasciare che l'SDK scriva la configurazione al posto tuo:
uv run mcp install server.py
In alternativa puoi configurarlo a mano. Apri il file di configurazione di Claude Desktop:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
e aggiungi il tuo server (sostituisci il percorso con quello assoluto della tua cartella):
{
"mcpServers": {
"note-server": {
"command": "uv",
"args": ["--directory", "/PERCORSO/ASSOLUTO/note-server", "run", "server.py"]
}
}
}
Salva il file e riavvia completamente Claude Desktop. Dovresti vedere comparire l'icona degli strumenti: da quel momento, in chat, potrai scrivere «salva una nota: comprare il latte» e Claude chiederà il permesso di usare lo strumento salva_nota. Poi «leggimi le note» richiamerà leggi_note.
Andare oltre: risorse, prompt e trasporto remoto
Gli strumenti sono solo una delle tre capacità di MCP. Ci sono anche le risorse (dati di sola lettura, come il contenuto di un file, esposti con @mcp.resource(...)) e i prompt (modelli di richiesta riutilizzabili). Per un server che deve essere raggiungibile in rete, e non solo in locale, si usa un trasporto HTTP invece di stdio: l'SDK supporta anche questa modalità, utile per esporre uno strumento aziendale a più utenti. La documentazione ufficiale su modelcontextprotocol.io mostra tutti i dettagli.
Errori comuni e come risolverli
- Il server non compare in Claude. Quasi sempre è un percorso sbagliato nel file di configurazione: deve essere assoluto, non relativo. Verifica anche di aver riavviato del tutto l'app, non solo chiuso la finestra.
- «command not found: uv». Il client non trova
uvnel PATH. Indica il percorso completo dell'eseguibileuvnel campocommand, oppure installa il server conuv run mcp installche gestisce i percorsi. - Errori di tipo negli argomenti. Assicurati che ogni parametro degli strumenti abbia un'annotazione di tipo (
str,int, ecc.) e una docstring chiara: sono ciò che guida il modello. - Modifiche non applicate. Dopo aver cambiato
server.py, riavvia Claude Desktop: il server viene lanciato all'avvio del client.
Sicurezza: dare strumenti significa dare potere
Un server MCP esegue codice sul tuo computer per conto di un modello: è potente, e va trattato con attenzione. Alcune regole pratiche: esponi solo gli strumenti strettamente necessari; valida sempre gli argomenti in ingresso (per esempio non passare mai un percorso ricevuto dal modello direttamente a un comando di sistema); evita strumenti che cancellano dati o inviano denaro senza un passaggio di conferma esplicito; e ricorda che i buoni client, come Claude Desktop, chiedono comunque il permesso all'utente prima di eseguire uno strumento. Se il server maneggia dati sensibili o gira in azienda, aggiungi log delle chiamate e limita i permessi del processo. La comodità di far agire l'IA non deve far dimenticare che ogni strumento è una porta aperta.
Quando non usare MCP (e come proseguire)
MCP è potente ma non sempre necessario. Se ti serve solo far rispondere il modello a partire da alcuni documenti, un semplice sistema di recupero (RAG) può bastare; se devi automatizzare un flusso senza un assistente in chat, uno script diretto o uno strumento no-code come n8n è più adatto. MCP brilla quando vuoi dare a un assistente conversazionale la possibilità di agire su strumenti reali, in modo standard e riutilizzabile su più client.
Da qui puoi crescere: sostituisci l'archivio in memoria con un vero database, aggiungi uno strumento che chiama un'API meteo o aziendale, esponi come risorse i file di un progetto. Ogni nuovo @mcp.tool() è una capacità in più che il tuo assistente acquisisce — e, essendo MCP uno standard, lo stesso server funzionerà anche con i client che adotterai in futuro.




