[cite_start]Prima di intraprendere la progettazione e l'implementazione di una soluzione specifica, è indispensabile stabilire una solida comprensione dei principi architetturali che governano il Model Context Protocol (MCP). [cite: 1] [cite_start]L'MCP non è semplicemente una tecnologia, ma un paradigma emergente per l'integrazione dell'Intelligenza Artificiale, progettato per standardizzare e rendere sicura la comunicazione tra i Large Language Models (LLM) e l'universo di strumenti e dati esterni. [cite: 2] [cite_start]Introdotto da Anthropic, l'MCP si propone di risolvere il problema della frammentazione delle integrazioni, agendo come una "porta USB-C per le applicazioni AI", ovvero un connettore universale che permette a qualsiasi modello AI di interfacciarsi con sorgenti dati e tool esterni senza la necessità di sviluppare codice custom per ogni singola connessione. [cite: 2]
[cite_start]L'architettura del Model Context Protocol si fonda su una chiara separazione delle responsabilità tra tre componenti distinti: l'Host, il Client e il Server. [cite: 3] [cite_start]Questa struttura tripartita è progettata per massimizzare la modularità, la sicurezza e la componibilità dell'ecosistema. [cite: 4]
-
[cite_start]Host: L'Host è l'applicazione orchestratrice che funge da contenitore per l'intera interazione AI. [cite: 4] [cite_start]Esempi comuni includono ambienti di sviluppo integrati (IDE) come Cursor, applicazioni desktop come Claude Desktop, o un'interfaccia utente di un chatbot personalizzato. [cite: 5] [cite_start]Il suo ruolo primario è quello di agire come una "torre di controllo": gestisce la sessione dell'utente, avvia e termina le istanze dei Client e, soprattutto, è responsabile dell'applicazione delle policy di sicurezza. [cite: 5] [cite_start]Un compito cruciale dell'Host è la gestione del consenso dell'utente[cite: 6]; [cite_start]è l'Host che deve richiedere e ottenere l'approvazione esplicita dell'utente prima che un qualsiasi "Tool" esposto da un Server venga eseguito. [cite: 7]
-
[cite_start]Client: Il Client è un'istanza software che risiede all'interno dell'Host. [cite: 8] [cite_start]La sua funzione è quella di agire come un agente specializzato nella comunicazione protocollare. [cite: 9] [cite_start]Ogni Client stabilisce e mantiene una connessione stato-pieno (stateful) e uno-a-uno con un singolo MCP Server. [cite: 10] [cite_start]Il Client traduce le richieste di alto livello dall'Host in messaggi JSON-RPC 2.0 e li instrada al Server appropriato. [cite: 10] [cite_start]Gestisce inoltre il ciclo di vita della connessione, la negoziazione delle capacità e la ricezione di notifiche dal Server. [cite: 11]
-
[cite_start]Server: Il Server è il servizio specializzato che espone capacità esterne al mondo AI. [cite: 12] [cite_start]Questo è il componente che verrà costruito per soddisfare la richiesta dell'utente. [cite: 13] [cite_start]Un Server MCP è progettato per essere focalizzato su un compito specifico e altamente componibile. [cite: 14] [cite_start]Può esporre l'accesso a un file system, a un database, o agire da gateway verso un set di API esterne. [cite: 14] [cite_start]La responsabilità principale del nostro Server sarà quella di fungere da intermediario intelligente e sicuro, gestendo l'autenticazione e inoltrando le richieste alle API di backend. [cite: 15] [cite_start]Questo eleva il suo ruolo a quello di un componente critico per la sicurezza, la cui progettazione deve seguire standard di robustezza e sicurezza elevati. [cite: 18]
[cite_start]L'MCP definisce due meccanismi di trasporto primari per la comunicazione tra Client e Server[cite: 19]:
-
[cite_start]stdio (Standard Input/Output): Ideale per scenari di sviluppo locale, dove l'Host può gestire il Server come un sottoprocesso. [cite: 19] [cite_start]È efficiente per la comunicazione sulla stessa macchina e semplifica la gestione del processo del server. [cite: 20]
-
[cite_start]HTTP con Server-Sent Events (SSE): Richiesto per i Server remoti e centralizzati, accessibili attraverso una rete. [cite: 20] [cite_start]La comunicazione avviene tramite un endpoint HTTP, tipico per un ambiente di produzione. [cite: 21, 22] [cite_start]La scelta del trasporto influisce sulla strategia di deployment e sulla sicurezza; un server remoto, ad esempio, richiederà l'uso di TLS (https). [cite: 23, 24]
[cite_start]La comunicazione nell'ecosistema MCP si basa sul formato JSON-RPC 2.0. [cite: 25] [cite_start]Questo standard definisce la struttura dei messaggi, che si dividono in quattro tipi[cite: 26]:
- [cite_start]Requests: Messaggi che si aspettano una risposta. [cite: 26]
- [cite_start]Results: Risposte di successo a una richiesta. [cite: 27]
- [cite_start]Errors: Risposte che indicano il fallimento di una richiesta. [cite: 27]
- [cite_start]Notifications: Messaggi unidirezionali che non richiedono risposta. [cite: 28]
[cite_start]Un Server MCP espone le sue capacità attraverso tre primitive fondamentali[cite: 28]:
- [cite_start]Tools (Strumenti): Funzioni che un LLM può decidere di eseguire per compiere azioni, come chiamare un'API esterna. [cite: 29] [cite_start]Questa è la primitiva centrale per la nostra implementazione. [cite: 30]
- [cite_start]Resources (Risorse): Dati di sola lettura che arricchiscono il contesto dell'LLM, come il contenuto di un file o la documentazione di un'API. [cite: 32, 33]
- [cite_start]Prompts (Suggerimenti): Template di interazione riutilizzabili per guidare l'utente. [cite: 35]
[cite_start]L'implementazione si concentrerà esclusivamente sulla creazione di Tools. [cite: 36]
[cite_start]La sicurezza è un pilastro dell'MCP, con diversi principi incorporati[cite: 37, 38]:
- [cite_start]Consenso e Controllo dell'Utente: L'Host è l'unico responsabile di ottenere il consenso esplicito dell'utente prima di invocare un tool. [cite: 39] [cite_start]Il server assume che ogni chiamata ricevuta sia stata pre-approvata. [cite: 40]
- [cite_start]Privacy e Isolamento dei Dati: I server operano in isolamento, senza accesso alla cronologia della conversazione o ai dati gestiti da altri server. [cite: 41, 42] [cite_start]L'Host fornisce a ciascun server solo il contesto strettamente necessario. [cite: 43]
- [cite_start]Sicurezza dei Tool: I tool sono trattati con massima cautela. [cite: 44] [cite_start]La loro descrizione è considerata non attendibile dall'Host, che deve informare chiaramente l'utente sull'azione imminente. [cite: 45] [cite_start]È compito dell'Host iniettare in modo sicuro le credenziali (come API key) attraverso le variabili d'ambiente. [cite: 47] [cite_start]Di conseguenza, il codice del server non deve contenere segreti hardcoded, ma deve leggerli dal suo ambiente di esecuzione. [cite: 48]
L'architettura da implementare è centralizzata e orientata alla produzione:
- [cite_start]Client Fornisce il Bearer Token: Il client (es. VS Code) viene configurato con un Bearer Token di produzione pre-esistente. [cite: 49] [cite_start]Questo token è inviato al server MCP tramite l'header
Authorization. [cite: 50] - [cite_start]Server MCP come Proxy Autenticato: Il server agisce come un proxy. [cite: 51] [cite_start]Riceve la richiesta, estrae il Bearer Token e lo utilizza per chiamare l'API di backend. [cite: 52]
- [cite_start]Endpoint di Produzione: Le chiamate sono dirette agli URL di produzione (es.
https://company.openapi.com). [cite: 53]
[cite_start]Questo design è efficiente e sicuro, poiché il server MCP gestisce solo il token di sessione, non le credenziali utente. [cite: 54]
Le dipendenze sono semplificate. [cite_start]Si utilizzano fastmcp, requests e pydantic. [cite: 56]
uv add "fastmcp" requests pydantic[cite_start]Il file .env non è più necessario, poiché il server non gestisce configurazioni o credenziali esterne. [cite: 57]
Di seguito il codice server.py completo e semplificato. [cite_start]Non è presente un AuthenticationService in quanto il token viene passato direttamente. [cite: 58, 59]
import os
import sys
import requests
from fastmcp import FastMCP, Context
from typing import Dict, Any, Optional
from pydantic import BaseModel
# --- Modello Pydantic per Risposte di Errore Standard ---
class ApiError(BaseModel):
error: str
message: str
# --- Funzione Helper per Chiamate API ---
def make_api_call(ctx: Context, method: str, url: str, **kwargs) -> Any:
"""
Funzione helper per estrarre il token e fare la chiamata API.
"""
try:
# Recupera l'header 'Authorization' inviato dal client mcp.json
auth_header = ctx.request.headers.get("authorization")
if not auth_header or not auth_header.lower().startswith('bearer '):
raise ValueError("Header 'Authorization: Bearer <token>' mancante o malformato.")
except Exception as e:
return ApiError(error="Auth Error", message=f"Token non fornito dal client: {e}").dict()
headers = {"Authorization": auth_header, **kwargs.pop("headers", {})}
try:
response = requests.request(method, url, headers=headers, **kwargs)
response.raise_for_status()
return response.json().get('data', {})
except requests.exceptions.HTTPError as e:
# Tenta di leggere il corpo della risposta per un messaggio di errore più chiaro
error_details = e.response.text
return ApiError(error="API HTTP Error", message=f"{e.response.status_code}: {error_details}").dict()
except requests.exceptions.RequestException as e:
return ApiError(error="API Request Error", message=str(e)).dict()
# --- Inizializzazione del Server MCP ---
mcp = FastMCP(
name="Openapi.com Gateway",
instructions="Questo server fornisce un gateway unificato per diversi servizi di openapi.com."
)
# --- Definizione Manuale dei Tool ---
@mcp.tool
async def get_company_full_profile(vat_or_tax_code: str, ctx: Context) -> Any:
"""
Recupera il profilo completo e dettagliato di un'azienda italiana
fornendo la sua Partita IVA o il suo Codice Fiscale.
"""
print(f"Running Tool: get_company_full_profile per {vat_or_tax_code}")
url = f"https://company.openapi.com/IT-full/{vat_or_tax_code}"
return make_api_call(ctx, "GET", url)
@mcp.tool
async def find_cap_by_comune(comune: str, ctx: Context) -> Any:
"""
Cerca i CAP associati a un dato comune italiano.
"""
print(f"Running Tool: find_cap_by_comune per {comune}")
url = "https://cap.openapi.com/cerca_comuni"
params = {"comune": comune}
return make_api_call(ctx, "GET", url, params=params)
# --- Puoi aggiungere altri tool per le altre API qui seguendo lo stesso pattern ---
if __name__ == "__main__":
print(f"\n--- Server Pronto ---")
print("Per avviare in modalità remota, eseguire:")
print("python server.py")
mcp.run(transport="http", host="0.0.0.0", port=8000)- [cite_start]Sistema Operativo: Ubuntu 24.04 LTS (Noble Numbat) [cite: 67]
- [cite_start]Accesso al Terminale [cite: 67]
- [cite_start]Connessione Internet [cite: 67]
- Aggiornamento del Sistema:
sudo apt update && sudo apt upgrade -y - Installazione di Python e Strumenti Correlati:
sudo apt install python3 python3-pip python3-venv -y
- Installazione di uv:
[cite_start]Dopo l'installazione, segui le istruzioni per aggiungere
curl -LsSf https://astral.sh/uv/install.sh | shuval PATH. [cite: 68] - Installazione di Visual Studio Code:
[cite_start]Avvia VS Code e installa l'estensione GitHub Copilot Chat. [cite: 69]
sudo snap install --classic code
- Creazione della Struttura del Progetto:
mkdir mcp_gateway cd mcp_gateway uv init uv venv source .venv/bin/activate uv add "fastmcp" requests pydantic
- [cite_start]Creazione dei File di Progetto: Crea il file
server.pycome descritto nella Sezione 3.3. [cite: 70]
- [cite_start]Prepara il Server: Assicurati che la directory del progetto con
server.pysia sulla macchina server. [cite: 71] - [cite_start]Avvia il Server: Nel terminale del server, attiva l'ambiente virtuale e avvia lo script. [cite: 72]
[cite_start]Il server sarà in esecuzione su
cd mcp_gateway source .venv/bin/activate python server.py
http://0.0.0.0:8000. [cite: 73]
[cite_start]Sulla macchina client, configura VS Code per inviare il Bearer Token. [cite: 74]
-
[cite_start]Ottieni il Tuo Bearer Token: Genera un Bearer Token valido dal portale
https://console.openapi.com/oauth. [cite: 75] [cite_start]Assicurati di creare un token con gli scope necessari (es.*:*/*). [cite: 76] -
[cite_start]Crea la Configurazione
.vscode/mcp.json: Nel progetto VS Code, crea il file.vscode/mcp.jsoncon la seguente configurazione[cite: 77]:{ "servers": { "openapi.com": { "type": "http", "url": "http://INDIRIZZO_IP_DEL_TUO_SERVER:8000", "headers": { "Authorization": "Bearer IL_TUO_BEARER_TOKEN_DI_PRODUZIONE" } } } }- [cite_start]Sostituisci
INDIRIZZO_IP_DEL_TUO_SERVERcon l'IP della macchina server. [cite: 78] - [cite_start]Sostituisci
IL_TUO_BEARER_TOKEN_DI_PRODUZIONEcon il token generato. [cite: 79]
- [cite_start]Sostituisci
-
Esegui il Test:
- [cite_start]Ricarica la finestra di VS Code. [cite: 79]
- Apri la chat di Copilot e digita
@workspace. [cite_start]Vedrai il toolopenapi.com. [cite: 80] - [cite_start]Invia un prompt per testare una delle API, ad esempio[cite: 81]:
@workspace usa lo strumento di openapi.com per trovare i dati dell'azienda con partita IVA 12485671007
-
Analizza il Flusso:
- [cite_start]VS Code invia la richiesta al server MCP, includendo l'header
Authorization: Bearer .... [cite: 81] - [cite_start]La funzione helper
make_api_callestrae questo header. [cite: 81] - [cite_start]Il token viene usato direttamente per chiamare l'API di backend richiesta. [cite: 82]
- [cite_start]VS Code invia la richiesta al server MCP, includendo l'header
[cite_start]Questo completa il ciclo, dimostrando un'architettura di produzione efficiente, sicura e scalabile. [cite: 83]