Il Model Context Protocol (MCP) e' diventato in meno di un anno lo standard di fatto per collegare modelli linguistici e strumenti esterni. Aperto da Anthropic a fine 2024, oggi e' supportato nativamente da Claude (Desktop e API), OpenAI (Agent Mode), Google (Gemini Agents), Mistral, Cursor, Zed e centinaia di applicazioni indipendenti. In questa guida costruiamo un server MCP funzionante in Python, in circa 30 minuti, e lo colleghiamo a Claude Desktop.
A chi serve e cosa otterrai
La guida e' pensata per sviluppatori Python con basi solide ma senza esperienza specifica su MCP. Alla fine avrai: un server MCP funzionante che espone tre tool (lettura di un file, query a un database SQLite, chiamata HTTP a una API esterna); l'integrazione con Claude Desktop su macOS, Windows o Linux; gli strumenti di debug e gli errori tipici. Tempo richiesto: 30-45 minuti.
Prerequisiti reali: Python 3.10 o superiore; uv o pip per la gestione dei pacchetti; un account Claude (anche gratuito) e Claude Desktop installato; un editor di codice (VS Code, Cursor o Zed). Il tutto gira su macOS, Windows o Linux senza differenze significative.
Cos'e' MCP e perche' usarlo
MCP e' un protocollo che permette a un LLM di scoprire e usare strumenti esterni ("tools"), risorse statiche ("resources") e prompt template ("prompts") esposti da un server remoto o locale. Funziona via JSON-RPC su stdin/stdout (server locali) o WebSocket/SSE (server remoti). Il vantaggio rispetto alle vecchie function calls proprietarie e' duplice: lo stesso server funziona con qualsiasi client MCP compatibile (Claude, ChatGPT, Cursor, ecc.), e gli strumenti sono dichiarati con metadata standardizzati.
Casi d'uso comuni: dare a Claude accesso al database aziendale, esporre la knowledge base di una documentazione interna, automatizzare interazioni con Jira/GitHub/Notion, ponte verso strumenti legacy. Anthropic mantiene una galleria ufficiale di server pronti per Postgres, Slack, Filesystem, Brave Search e altri.
Setup dell'ambiente
Crea una cartella di progetto e l'ambiente virtuale (uso uv, che e' piu' veloce di pip):
mkdir mio-server-mcp && cd mio-server-mcp
uv init
uv add "mcp[cli]" "fastmcp>=3.0" requestsFastMCP 3.0, rilasciato a gennaio 2026, e' lo strato di astrazione che genera schema e validazione con un singolo decoratore. Sotto il cofano usa il Python SDK ufficiale di Anthropic.
Il server: 30 righe di codice
Crea il file server.py:
from fastmcp import FastMCP
import sqlite3, requests, pathlib
mcp = FastMCP("Mio Server MCP")
@mcp.tool()
def leggi_file(percorso: str) -> str:
"""Restituisce il contenuto del file indicato (max 50KB)."""
p = pathlib.Path(percorso).expanduser()
if not p.is_file():
return f"File non trovato: {percorso}"
return p.read_text(encoding="utf-8")[:50_000]
@mcp.tool()
def query_db(sql: str, db_path: str = "data.db") -> list[dict]:
"""Esegue una query SQL su SQLite. Solo SELECT consentite."""
if not sql.strip().lower().startswith("select"):
return [{"errore":"solo SELECT consentite"}]
con = sqlite3.connect(db_path)
con.row_factory = sqlite3.Row
rows = con.execute(sql).fetchall()
con.close()
return [dict(r) for r in rows]
@mcp.tool()
def meteo(citta: str) -> dict:
"""Recupera il meteo corrente da open-meteo.com."""
g = requests.get("https://geocoding-api.open-meteo.com/v1/search",
params={"name":citta,"count":1}).json()
if not g.get("results"):
return {"errore":"citta' non trovata"}
r = g["results"][0]
w = requests.get("https://api.open-meteo.com/v1/forecast",
params={"latitude":r["latitude"],"longitude":r["longitude"],
"current":"temperature_2m,wind_speed_10m"}).json()
return {"citta":r["name"], "meteo":w["current"]}
if __name__ == "__main__":
mcp.run()Tre tool: leggi_file per leggere un file locale, query_db per query SELECT su SQLite, meteo per chiamare l'API gratuita di Open-Meteo. I docstring (in inglese o italiano) diventano automaticamente la descrizione che Claude usa per capire quando invocare lo strumento.
Collegare il server a Claude Desktop
Claude Desktop legge i server MCP da un file di configurazione che si trova in:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Apri il file (creane uno se non esiste) e aggiungi:
{
"mcpServers": {
"mio-server": {
"command": "uv",
"args": ["--directory", "/percorso/assoluto/a/mio-server-mcp",
"run", "python", "server.py"]
}
}
}Salva, chiudi e riapri Claude Desktop. In basso a destra dell'input apparira' una piccola icona "hammer" con il numero di tool disponibili. Chiedi a Claude: "Che meteo c'e' a Bologna?". Vedrai partire l'invocazione del tool meteo con la citta' "Bologna" e la risposta integrata nella conversazione.
Debugging con MCP Inspector
Per debuggare il server, Anthropic offre uno strumento chiamato MCP Inspector. Lancialo cosi':
npx @modelcontextprotocol/inspector uv run python server.pySi apre un'interfaccia web (http://localhost:5173) in cui puoi vedere la lista dei tool esposti, invocarli manualmente e ispezionare le richieste JSON-RPC scambiate. E' lo strumento piu' efficace quando i tool non vengono chiamati nel modo atteso.
Esporre il server in remoto
Il setup visto e' "locale" (Claude lancia il processo Python sul tuo computer). Per esporlo a piu' utenti, conviene passare alla modalita' HTTP+SSE. Modifica l'ultima riga del server:
if __name__ == "__main__":
mcp.run(transport="sse", host="0.0.0.0", port=8000)Avvialo con uv run python server.py e poi configura il client puntando a http://tuo-server.it:8000/sse. Per Claude Desktop la sintassi diventa:
{
"mcpServers": {
"mio-server-remoto": {
"transport": "sse",
"url": "https://api.miosito.it/mcp/sse"
}
}
}Importante: il server remoto va sempre protetto con autenticazione. FastMCP supporta token bearer in header (@mcp.middleware) o JWT firmati. Senza protezione, chiunque conosca l'URL puo' invocare i tuoi tool, inclusi quelli che toccano il database.
Risorse e prompt: gli altri due primitivi
Oltre ai tool (azioni che Claude puo' invocare), MCP supporta resources (dati statici come file, log, documentazione) e prompts (template riutilizzabili). Esempio di resource:
@mcp.resource("file://manuale.md")
def manuale() -> str:
return pathlib.Path("manuale.md").read_text()Esempio di prompt template:
@mcp.prompt()
def revisione_codice(codice: str) -> str:
return f"Rivedi questo codice Python e suggerisci miglioramenti:\n\n{codice}"Risorse e prompt appaiono in Claude Desktop come voci selezionabili da menu (la barra delle slash command e l'@ per allegare risorse).
Errori comuni
"MCP server failed to start": percorso nel config sbagliato (deve essere assoluto). Verifica con which uv e usa il path completo del comando. Claude non vede i tool: il processo del server e' partito ma e' crashato; lancia il comando dal terminale per leggere il traceback. "Tool not found": controlla che il nome del tool nel docstring coincida con quanto richiesto. JSON serialization error: stai restituendo un tipo non JSON-friendly (datetime, set, ecc.); usa solo dict/list/str/int/float/bool. Permessi sul filesystem: macOS chiede esplicitamente l'autorizzazione la prima volta che Claude legge un file, accetta dal pannello di Sistema.
Quando NON usare MCP
MCP e' la scelta giusta quando devi connettere lo stesso strumento a piu' client (Claude + Cursor + ChatGPT). Per integrazioni una tantum dentro un singolo agente Python, il function calling diretto dell'SDK Anthropic resta piu' rapido (meno overhead di setup, meno parti in movimento). Se invece stai costruendo un prodotto che venderai a piu' clienti, conviene MCP fin dall'inizio: in cinque minuti il tuo strumento e' usabile da chiunque, ovunque.
Come proseguire
Una volta familiarizzato con i tre primitivi, conviene esplorare la galleria ufficiale: il server filesystem e' un'ottima base per file browser; il server postgres permette query a un database aziendale; il server brave-search aggiunge ricerca web. Per applicazioni production, dai un'occhiata anche a mcp-context-forge, un proxy che fa rate limiting, caching e auditing su server MCP. L'ecosistema cresce velocemente: tenere d'occhio il repository GitHub di modelcontextprotocol e' il modo migliore per rimanere aggiornato.



