Quando si progetta un mcp client, il punto non è solo “collegarsi” a un server. Il vero obiettivo è farlo in modo prevedibile, sicuro e facile da mantenere nel tempo. Per avere prima una vista d’insieme del protocollo, può essere utile leggere anche questa panoramica sull’architettura del Model Context Protocol. MCP standardizza come un’applicazione o un agente AI espone e consuma strumenti, risorse e prompt tramite messaggi JSON-RPC 2.0, con trasporti come stdio e Streamable HTTP.null
Che cos’è davvero un mcp client
Un mcp client è il componente che apre la connessione verso uno o più server MCP, negozia versione e capability, scopre ciò che il server mette a disposizione e decide quando usare tool, risorse o prompt. In pratica, è il lato che orchestri dentro una mcp app, un assistente interno, un plugin di sviluppo o un mcp agent che deve lavorare con fonti e funzioni esterne senza integrare ogni sistema con API custom.null
Dal punto di vista operativo, il client non deve limitarsi a inoltrare richieste. Deve anche gestire timeout, retry, caching della discovery, controllo dei permessi, selezione intelligente dei tool e telemetria. È qui che si decide gran parte della qualità percepita: un buon server non basta, se il client apre troppe sessioni, richiama tool inutili o non osserva gli errori in modo strutturato.null
Il lifecycle che un client robusto deve rispettare
La base di una buona implementazione è il lifecycle MCP. In fase di inizializzazione, client e server devono concordare una singola versione del protocollo e dichiarare le capability supportate. La specifica segnala che il versioning usa stringhe data nel formato YYYY-MM-DD e che la revisione corrente pubblicata della specifica era 2025-06-18; inoltre, via HTTP il client deve inviare l’header MCP-Protocol-Version nelle richieste successive all’inizializzazione.null
Perché la negoziazione iniziale conta più di quanto sembri
Molti problemi di compatibilità nascono qui. Se il client presume capability non negoziate, si espone a comportamenti incoerenti. Le capability lato server includono tipicamente tools, resources, prompts e logging; lato client possono esserci roots, sampling ed estensioni ulteriori. Un’implementazione solida usa solo le feature effettivamente concordate, senza affidarsi a supposizioni o fallback impliciti.null
Regola pratica
- inizializza la sessione una sola volta per contesto logico;
- salva versione negoziata e capability in memoria;
- non invocare feature non dichiarate dal server;
- se lavori via HTTP, applica sempre l’header di versione dopo l’initialize;
- tratta incompatibilità e 400 come errori di protocollo, non come semplici errori di rete.
Discovery dei server: come evitare integrazioni fragili
La discovery è il primo vero tema pratico per chi lavora con mcp usage in ambienti reali. Storicamente molti client hanno usato configurazioni manuali, ma l’ecosistema si sta muovendo verso un modello più standardizzato: nel settembre 2025 è stato presentato in preview l’MCP Registry, un catalogo aperto per migliorare discoverability e implementazione dei server pubblici. Questo non elimina i casi privati, ma fornisce una direzione chiara anche per i client maintainer.null
Nella pratica, conviene distinguere tre livelli di discovery: manuale, catalogata e runtime. La discovery manuale è adatta a prototipi e ambienti controllati. Quella catalogata usa registry interni o pubblici. La discovery runtime, invece, riguarda il recupero delle capability e dell’inventario reale del server una volta connessi. Per un’integrazione più rapida, può aiutare anche questa guida dedicata all’integrazione di un client MCP.null
Cosa conviene salvare in cache
Un mcp client affidabile non rifà sempre tutto da zero. In genere ha senso mettere in cache:
- endpoint e trasporto supportato;
- versione del protocollo negoziata;
- capability del server;
- lista dei tool con metadati utili alla selezione;
- eventuali informazioni di autenticazione e policy locali.
La cache però deve avere invalidazione chiara. La specifica prevede notifiche di cambiamento per liste come tool, risorse e prompt, e i client devono reagire aggiornando il proprio stato quando il server segnala che l’inventario è cambiato. In altre parole, cache sì, ma mai trattata come verità assoluta.null
Trasporto: quando usare stdio e quando Streamable HTTP
Il protocollo definisce due trasporti standard: stdio e Streamable HTTP. Stdio è molto adatto quando il client lancia un server locale come sottoprocesso, perché riduce overhead e semplifica i casi desktop o di sviluppo. Streamable HTTP è invece il trasporto moderno per server remoti, usa POST e GET HTTP e può combinarsi con SSE per lo streaming dei messaggi server-to-client.null
Scelta pratica per ambienti diversi
| Scenario | Trasporto consigliato | Motivo |
|---|---|---|
| Tool locale su macchina sviluppatore | stdio | Minimo overhead e setup semplice |
| Server condiviso tra team o utenti | Streamable HTTP | Scalabilità, auth standard, deployment centralizzato |
| Compatibilità con client legacy | HTTP + SSE solo se necessario | La documentazione SDK lo tratta come compatibilità retroattiva |
Le indicazioni ufficiali più recenti degli SDK mostrano chiaramente che Streamable HTTP è la scelta raccomandata per server remoti, mentre HTTP+SSE puro viene mantenuto soprattutto per retrocompatibilità. Questo è un punto importante per chi pianifica un’architettura duratura e non vuole fare un refactor dopo pochi mesi.null
Gestione delle sessioni senza degradare latenza e stabilità
Uno degli errori più comuni nel mcp use lato client è aprire una nuova sessione per ogni messaggio utente. Su carta sembra semplice, ma in produzione porta a più handshake, più latenza e meno continuità di stato. Con Streamable HTTP, il server può assegnare un session ID tramite header MCP-Session-Id; il client dovrebbe riusarlo finché il contesto logico rimane valido.null
Quando creare una nuova sessione
- quando il server restituisce 404 per una sessione non più valida;
- quando cambia in modo sostanziale il contesto utente o workspace;
- quando ruotano credenziali o scope di accesso;
- quando la sessione è stata chiusa esplicitamente dal client o dal server.
La specifica del trasporto HTTP indica che, se il client riceve un 404 su una richiesta che include un MCP-Session-Id, deve riaprire una nuova sessione inviando un nuovo InitializeRequest senza session ID. Inoltre, quando una sessione non serve più, il client dovrebbe provare a terminarla con una richiesta HTTP DELETE al medesimo endpoint.null
Stateful o stateless?
Gli SDK ufficiali mostrano che Streamable HTTP può funzionare sia in modalità stateless sia stateful. Se il tuo caso d’uso è semplice e API-like, lo stateless può bastare. Ma se il client deve orchestrare logging, notifiche, task lunghi, resumability o interazioni più ricche, la gestione stateful offre più controllo. La scelta giusta dipende dal carico e dalla continuità che vuoi dare alla conversazione o al workflow.null
Tool discovery e tool selection: come scegliere bene cosa esporre al modello
In un mcp agent, il collo di bottiglia non è quasi mai la disponibilità di tool, ma la loro selezione. Un client che passa al modello tutti i tool di tutti i server, sempre, aumenta costo cognitivo, latenza e probabilità di chiamate sbagliate. Gli SDK e la documentazione MCP ruotano attorno a primitive come listTools e callTool, ma la vera qualità nasce da un layer di policy applicato dal client.null
Una buona strategia è introdurre una preselezione deterministica prima di coinvolgere il modello. In pratica, il client filtra i tool usando contesto utente, dominio applicativo, permessi, storico e confidenza. Solo dopo costruisce il set finale che l’LLM può vedere. Se vuoi capire anche come valutare gli strumenti più utili in casi concreti, può tornare utile questa selezione dei migliori MCP tools.null
Schema pratico di selezione tool
- filtra per dominio: CRM, documenti, analytics, supporto, sviluppo;
- filtra per rischio: sola lettura, scrittura, side effect esterni;
- filtra per contesto: workspace, account, progetto, tenant;
- limita il numero di tool passati al modello per turno;
- favorisci tool con descrizioni chiare e input schema ben definiti;
- escludi tool temporaneamente degradati o in errore ricorrente.
Questa logica riduce le allucinazioni operative. Inoltre, con gli aggiornamenti del protocollo del 2025, MCP ha aggiunto il supporto a structured tool output, utile per far elaborare al client risultati più prevedibili e riusabili, soprattutto quando il tool produce dati che poi devono alimentare altri passaggi del workflow.null
Risorse, prompt e roots: non solo tool
Chi pensa a un mcp client solo in termini di tool perde una parte importante del protocollo. Le resources servono a esporre dati leggibili, i prompts offrono template riusabili e le roots definiscono i confini del filesystem che il client decide di mostrare al server. Questa separazione è utile perché evita di usare un tool dove basta una risorsa o un prompt guidato.null
Quando usare i prompt esposti dal server
I prompt sono pensati per essere user-controlled: la documentazione li descrive come elementi che il client può esporre anche tramite comandi o interfacce dedicate, senza che il protocollo imponga un unico pattern UI. Questo è molto utile in una mcp app dove vuoi standardizzare task frequenti, per esempio “analizza ticket”, “genera riepilogo cliente” o “verifica regressioni”.null
Roots: importante soprattutto per client desktop e dev tool
Le roots lato client servono a dichiarare quali directory il server può considerare nel lavoro. La specifica 2025-06-18 precisa che il server può richiedere la lista delle roots e che, nella revisione corrente, ogni root deve usare un URI file://. È una leva importante per sicurezza e governance, perché evita esposizioni troppo larghe del filesystem. Per un approfondimento introduttivo sul tema, può essere utile anche questo articolo su che cos’è il Model Context Protocol.null
Fallback intelligenti: cosa fare quando qualcosa va storto
In produzione il problema non è se ci sarà un errore, ma quale. Un client MCP robusto deve distinguere tra errori di trasporto, errori di protocollo, errori di autorizzazione, errori di tool execution e timeout. Se li gestisci tutti nello stesso modo, perdi osservabilità e peggiori l’esperienza utente.null
Fallback di trasporto
Gli esempi ufficiali del TypeScript SDK includono un client compatibile che prova prima Streamable HTTP e poi effettua fallback a SSE in presenza di specifiche risposte 4xx. Questo non significa che SSE debba essere la prima scelta, ma conferma che il fallback di trasporto può essere una misura utile quando devi convivere con server eterogenei o legacy.null
Fallback funzionale
- se un tool fallisce, prova una risorsa equivalente in sola lettura;
- se una risorsa non è disponibile, usa un prompt guidato con input manuale;
- se il server secondario è più lento, limita l’invocazione ai casi ad alta confidenza;
- se l’autorizzazione remota non è pronta, offri una modalità ridotta ma utilizzabile.
Un buon pattern è avere livelli di degradazione espliciti: full, reduced, read-only, manual assist. Così il tuo mcp usage non si interrompe bruscamente e l’utente capisce subito cosa può ancora fare.null
Timeout, cancellazione e richieste lunghe
La documentazione lifecycle raccomanda timeout appropriati su tutte le richieste per prevenire connessioni sospese e consumo eccessivo di risorse. È una regola semplice ma decisiva: senza timeout differenziati per initialize, list, read e tool call, il client finisce per accumulare code e ritardi a catena.null
Cancellazione corretta
MCP supporta la cancellazione opzionale di richieste in corso tramite notifications/cancelled. La specifica draft chiarisce che la notifica deve riferirsi a una richiesta ancora in corso nello stesso verso di comunicazione e che l’initialize non può essere cancellato dal client. Questa distinzione è utile per progettare UI reattive e interrompere tool lenti senza lasciare sessioni appese.null
Consiglio operativo
- timeout breve per discovery e listing;
- timeout medio per lettura risorse;
- timeout più lungo solo per tool con costo noto e valore alto;
- supporto a cancel da interfaccia o orchestration layer;
- idempotenza dove possibile, per facilitare retry sicuri.
Osservabilità: il pezzo che separa demo e produzione
Se vuoi un mcp client affidabile, devi poter capire cosa succede quando qualcosa rallenta, fallisce o devia dal comportamento atteso. La specifica include una capability di logging lato server: i server che emettono messaggi di log strutturati devono dichiararla, e il client può controllare il livello minimo di verbosità. I livelli seguono la semantica syslog di RFC 5424.null
Quali metriche raccogliere davvero
- tempo di initialize per server e per trasporto;
- tempo medio di
listTools,readResourceecallTool; - percentuale di errori per categoria;
- frequenza dei fallback attivati;
- numero di tool passati al modello per turno;
- latenza end-to-end percepita dall’utente;
- sessioni riaperte per 404 o scadenza.
È utile anche tracciare il decision path del client: quali server erano disponibili, quali tool sono stati scartati, perché il ranking finale ha privilegiato una certa chiamata e se il modello ha chiesto un tool non ammesso. Questo rende i problemi di qualità molto più diagnostici rispetto al solo log di errore finale.null
Sicurezza e autorizzazione: aspetti da non trattare come extra
Per i server HTTP, il tema auth è ormai centrale nel protocollo. Il changelog della revisione 2025-06-18 evidenzia l’introduzione del modello in cui i server MCP sono trattati come OAuth Resource Server, con metadata per scoprire l’Authorization Server e con richiesta esplicita che i client implementino i Resource Indicators secondo RFC 8707 per ridurre il rischio che server malevoli ottengano token non destinati a loro.null
Implicazioni pratiche per il client
- non riutilizzare token tra server diversi senza audience corretta;
- separi token storage, session state e configurazione endpoint;
- valida sempre metadata e issuer attesi;
- minimizza gli scope;
- preferisci secret manager o vault, mai token hardcoded.
Le best practice di sicurezza insistono anche sul fatto che una gestione debole dei token può trasformare il server in un proxy per esfiltrazione di dati. Per questo il client deve avere una politica chiara di trust: quali server può contattare, con quali credenziali e con quale livello di accesso.null
Pattern architetturale consigliato per una mcp app o un mcp agent
In progetti reali funziona bene un’architettura a quattro livelli. Il primo è il transport layer, che gestisce connessioni, sessioni, retry e auth. Il secondo è il discovery layer, che mantiene inventario e metadati. Il terzo è il selection layer, che decide quali tool, risorse e prompt esporre al modello. Il quarto è il policy/observability layer, che applica guardrail, logging e metriche. Questo approccio riflette bene anche la separazione concettuale presente nella documentazione MCP tra trasporto, protocollo e primitive di alto livello.null
Checklist rapida per andare in produzione
- supporto chiaro a stdio e/o Streamable HTTP in base al caso d’uso;
- negoziazione versione e capability persistita correttamente;
- session reuse dove serve, session reset gestito su 404;
- discovery cache con invalidazione su notifiche di cambiamento;
- tool selection deterministica prima del passaggio al modello;
- fallback di trasporto e fallback funzionale documentati;
- timeout e cancellazione implementati per ogni request type;
- logging strutturato, metriche e tracing del decision path;
- OAuth e Resource Indicators implementati nei client remoti;
- test separati per sviluppo locale, staging e produzione.
Se il tuo obiettivo è integrare MCP in workflow esistenti senza introdurre complessità inutile, questa checklist è spesso più utile di una demo brillante. Una demo mostra che il protocollo funziona; un client ben progettato dimostra che il protocollo continua a funzionare quando aumentano utenti, server, tool e dipendenze.null
