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.

Il server MCP si scrive in poche righe grazie alla classe FastMCP dell'SDK ufficiale.

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 uv nel PATH. Indica il percorso completo dell'eseguibile uv nel campo command, oppure installa il server con uv run mcp install che 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.