1. Perché serve un protocollo separato
In questo modulo finalmente chiariremo che cos’è MCP (Model Context Protocol) e come si inserisce nello stack di una ChatGPT App. Partiamo fissando il posto di MCP nell’architettura, confrontandolo con il «tipico REST» e analizzando le principali entità del protocollo: tools, resources e prompts.
Immagina di scrivere un normale web service. Per tradizione alzi un’API REST: hai /api/gifts, /api/users, /api/orders, ognuno con il proprio formato di input e output, i propri codici di errore e l’autorizzazione. È familiare, ma c’è una sfumatura: a ogni client devi spiegare cosa e come hai implementato. Documentazione, OpenAPI, esempi, SDK — tutto questo è necessario perché il formato dell’API lo hai inventato tu.
Con una ChatGPT App la situazione si complica. Il client non è solo il frontend, ma anche il modello stesso. Esso deve:
- sapere quali operazioni sono disponibili;
- capire quali argomenti servono a ciascuna operazione;
- invocare queste operazioni durante il dialogo, talvolta più volte e con parametri diversi;
- interpretare la risposta strutturata e decidere cosa mostrare all’utente e cosa usare solo come contesto per la battuta successiva.
Se ogni sviluppatore si inventa il proprio formato API, il modello finisce in un inferno di integrazioni: per ogni App servirà un client custom, un sacco di “colla” e logica fragile. Il problema lo risolve l’idea di un protocollo.
MCP (Model Context Protocol) è una specifica aperta di un modo standard con cui un client LLM (ChatGPT, un plugin IDE, un agente, ecc.) dialoga con il tuo server di strumenti e dati. Definisce un linguaggio comune in cui il server dichiara i propri strumenti, risorse e prompt, e il client — li invoca e ne riceve i risultati.
Intuitivamente, MCP è la porta USB‑C per il mondo dell’AI: se stai facendo una “chiavetta” (servizio, database, CRM, motore di ricerca), devi implementare un unico connettore standard. Così qualsiasi “laptop” (ChatGPT, un altro agente, un IDE) può collegarsi senza cavo personalizzato.
2. Vista dall’alto: dove si trova MCP nell’architettura di una ChatGPT App
Per fissare lo schema, ricordiamo l’architettura già nota, ma ora con un livello MCP esplicito.
L’immagine mentale attuale l’hai già vista: l’utente parla con ChatGPT, all’interno del dialogo viene renderizzato un widget (Apps SDK) e da qualche parte all’esterno vive il tuo backend. Ora aggiungiamo MCP e scomponiamo tutto per livelli.
Ecco uno schema semplificato:
Utente
↓ (linguaggio naturale)
ChatGPT (modello + UI)
↓ (tool calls tramite MCP)
Client MCP dentro ChatGPT
↓ (JSON-RPC, MCP)
Il tuo server MCP (backend)
↓
Il tuo DB / API esterni / code
Con «MCP client dentro ChatGPT» si intende la parte interna della piattaforma che parla con il tuo server MCP tramite il protocollo: fa discovery, invoca gli strumenti e legge le risorse.
Dal punto di vista dell’Apps SDK, una ChatGPT App minima è composta da tre componenti. Il primo è il server MCP, che dichiara gli strumenti e restituisce dati strutturati. Il secondo è il bundle UI (widget), che viene renderizzato dentro ChatGPT e legge questi dati tramite window.openai. Il terzo è il modello stesso, che decide quando invocare quale strumento e come rispondere all’utente.
È importante notare questo: in tutti i moduli precedenti hai lavorato molto al livello dell’Apps SDK e del widget, cioè nella parte alta dello schema. Ora scendiamo al livello del server MCP — è il tuo “linguaggio ufficiale” di comunicazione con ChatGPT e con qualsiasi altro client che decida di usare la tua App.
3. MCP contro il «tipico REST»: qual è la differenza
Nello schema qui sopra abbiamo fissato dove sta MCP nell’architettura di una ChatGPT App. Ora è il momento di confrontare con cura gli approcci «REST proprietario» e MCP, per capire perché, nel contesto delle ChatGPT Apps, il secondo vince quasi sempre.
Nell’approccio REST progetti endpoint, formati di richieste e risposte come è comodo a te. Al client, per lavorare con te, servono URL, metodi, schemi e codici d’errore. A volte aiuta OpenAPI, a volte butti un esempio di richiesta nel README. Il modello, di per sé, non capisce nulla di tutto questo: gli serve uno strato di codice che trasformi «scegli un regalo per la mamma per i 50 anni» in una specifica richiesta HTTP e, al ritorno, trasformi la risposta JSON in dati utili al dialogo.
In MCP è diverso. Il protocollo di per sé definisce:
- come il client può conoscere l’elenco dei tuoi strumenti;
- come descrivere argomenti e risultati tramite JSON Schema;
- come descrivere risorse e prompt;
- com’è fatta la chiamata a uno strumento e la sua risposta.
Grazie a questo, ChatGPT e gli altri client MCP possono automaticamente:
- eseguire la discovery — sapere quali tools/resources/prompts hai;
- costruire uno schema interno dei parametri per ciascuno strumento;
- invocarli senza logica client hardcoded e personalizzata;
- cachare i metadati e usarli per la ricerca e il ranking delle applicazioni.
Possiamo riassumere la differenza in una piccola tabella.
| Domanda | REST/gRPC proprietario | MCP |
|---|---|---|
| Come fa il client a sapere cosa sai fare? | Da documentazione, README, OpenAPI | Tramite metodi standard di discovery (elenco di tools/resources) |
| Chi descrive i parametri? | Tu, liberamente (JSON, FormData, qualunque cosa) | JSON Schema nei campi dello strumento |
| Come il modello invoca le funzioni? | Tramite il tuo codice client personalizzato | Direttamente tramite i primitive MCP |
| Quanta “colla” serve al client? | Tanta e diversa per ogni servizio | Un protocollo unico per tutti i server MCP |
| Supporto da più client | Bisogna scrivere un SDK per ogni client | Il server MCP è autodocumentante, il client può riusare la logica |
Detto in modo evocativo: REST è «ognuno per sé», MCP è «un accordo tra tutti i partecipanti all’ecosistema su come dialogare con il modello e i dati».
4. Le entità principali di MCP: tools, resources, prompts
Nominiamo ora i tre protagonisti di MCP: strumenti, risorse e prompt.
Tools: azioni a cui sei già abituato
Con i tools ti sei già imbattuto nel Modulo 4: lì abbiamo descritto uno strumento, gli abbiamo dato un nome, una descrizione e lo JSON Schema degli argomenti, e poi il modello lo ha invocato tramite callTool. A livello di MCP uno strumento è un’operazione server con un contratto chiaro:
- nome e descrizione (per il modello e per UX/discovery);
- JSON Schema per gli argomenti;
- JSON Schema o una descrizione della struttura del risultato;
- metainformazioni aggiuntive (ad esempio, l’associazione a un componente UI specifico nell’Apps SDK).
Il server MCP deve almeno saper rispondere alla «richiesta dell’elenco degli strumenti» e gestire la «chiamata dello strumento», restituendo un risultato strutturato.
Nella nostra applicazione didattica Gift‑App esiste già, per esempio, lo strumento suggest_gifts, che accetta età, genere, budget e un paio di preferenze e restituisce un elenco di regali consigliati.
Uno sketch TypeScript di tale strumento nel codice del server MCP può assomigliare, ad esempio, a questo (pseudocodice/placeholder):
// Pseudo-codice, non API SDK finale
const suggestGiftsTool = defineTool({
name: "suggest_gifts",
description: "Seleziona idee regalo in base ai parametri del destinatario",
inputSchema: z.object({
age: z.number(),
relation: z.enum(["friend", "partner", "parent"]),
budgetUsd: z.number(),
}),
handler: async (input) => {
// TODO: la tua logica di business
return { items: [] };
},
});
Analizzeremo le firme reali nelle prossime lezioni; qui conta l’idea: uno strumento non è solo un endpoint REST, è un elemento del protocollo con uno schema dichiarato.
Risorse (resources): dati accessibili tramite ID/URI
Le risorse (resources) in MCP sono un modo per descrivere i dati disponibili: file, directory, record di database, pagine wiki, persino risultati di indici di ricerca. Il client può:
- ottenere l’elenco delle risorse;
- leggere una risorsa specifica tramite ID/URI;
- talvolta — effettuare ricerche su di esse.
A differenza dei tools, che «fanno qualcosa», le resources di solito «contengono qualcosa». Per esempio, in Gift‑App puoi rappresentare il catalogo prodotti come la risorsa gift_catalog, a cui il modello si rivolge per conoscere categorie disponibili, filtri, fasce di prezzo e così via.
Nel codice può apparire concettualmente così:
const giftCatalogResource = defineResource({
uri: "catalog://gifts",
description: "Catalogo dei regali disponibili per la raccomandazione",
read: async () => {
// Restituisce la struttura del catalogo
return { categories: [], priceRanges: [] };
},
});
Per ora non entriamo nel formato dei messaggi MCP, ma teniamo a mente: le risorse sono entità indirizzabili cui il server MCP può fare riferimento e che il client può leggere e usare come parte del contesto.
Prompts: suggerimenti predefiniti
I Prompts nel contesto di MCP sono modelli di richieste o istruzioni che il server può fornire al client. Per esempio, puoi dichiarare il prompt gift_followup, che descrive come il modello dovrebbe chiedere all’utente dettagli sul destinatario del regalo prima di invocare lo strumento.
Un esempio tipico nello spirito del protocollo: il server fornisce un nome del prompt, il suo scopo e talvolta i parametri. Il client può chiedere l’elenco dei prompt, scegliere quello necessario e inserirlo nella richiesta al modello.
Perché serve alla ChatGPT App? Primo, è un modo unico per riusare prompt complessi tra client diversi. Secondo, MCP rende tali prompt espliciti e “contrattualizzati”, invece di nasconderli in punti casuali del codice.
Capabilities: la dichiarazione di ciò che supporti
Infine c’è un quarto elemento — le capabilities. È semplicemente una dichiarazione: il server indica quali entità supporta (tools, resources, prompts, notifiche, ecc.) e quali metodi implementa. Per il client è un modo per non indovinare cosa si può fare e cosa no, e adattare con cura il proprio comportamento alle capacità del server.
In pratica, collegandosi al tuo server MCP, ChatGPT esegue prima un “handshake”, ottiene l’elenco delle capabilities e solo dopo chiede: «Ok, mostrami i tuoi strumenti e le tue risorse».
5. Come MCP si integra con la tua App attuale
Tutto questo può suonare un po’ astratto, ma in realtà ti sei già imbattuto in MCP tramite l’Apps SDK. Penso valga la pena capire come tutto questo si incastri con ciò che hai già scritto usando l’Apps SDK. Colleghiamo le entità appena introdotte con il modo in cui è costruito il tuo template di App.
Ricordiamo la catena che hai già implementato nel template:
- Il widget, tramite window.openai o hook pronti, invoca callTool con il nome dello strumento e gli argomenti.
- L’Apps SDK dentro ChatGPT trasforma questo in una chiamata alla parte server dell’App.
- Il server esegue lo strumento e restituisce un ToolOutput, che include structuredContent, content e _meta.
- Il widget riceve il ToolOutput e disegna la UI.
Il segreto è che i passi 2–3 sono implementati come un dialogo secondo MCP. Il tuo template Next.js contiene un endpoint (di solito app/mcp/route.ts o simile) che è proprio il server MCP. Esso:
- registra i tuoi strumenti;
- li descrive tramite JSON Schema;
- implementa i relativi handler;
- risponde a ChatGPT alle richieste MCP list tools e call tool.
In pratica, anche ora, usando il template, stai già lavorando con MCP in modo “automatico”: gran parte della magia protocollare è nascosta nell’SDK.
Il Modulo 6 serve per smettere di trattare MCP come una «scatola nera magica» e iniziare a progettarlo consapevolmente:
- aggiungere e versionare gli strumenti;
- usare resources e prompts, non solo tools;
- leggere e capire i log di MCP;
- se necessario, avviare server MCP separati fuori dal template Next.js (ad esempio, un servizio Python per lavorare con un modello ML o un servizio separato per l’accesso a un database aziendale).
6. MCP visto da ruoli diversi: product vs sviluppatore
È utile formulare separatamente cosa dà MCP a un product manager e cosa a un ingegnere.
MCP per il product
Dal punto di vista del prodotto, MCP è un modo per rendere il tuo servizio un «modulo collegabile» per un intero zoo di client: ChatGPT, altri client LLM, plugin IDE, agenti propri. Una volta descritte le capacità del server come set di tools/resources/prompts, permetti a qualsiasi client di:
- scoprire automaticamente il tuo servizio;
- capire quali problemi risolve;
- invocare in modo sicuro le operazioni necessarie.
Nel caso di una ChatGPT App questo aumenta anche la probabilità che la tua applicazione venga scelta: il modello utilizza i metadati dei tuoi strumenti per decidere quando proporre la tua App all’utente e come rappresentarla correttamente.
In estrema sintesi: MCP rende il tuo servizio un “mattone” standard dell’ecosistema, non un’integrazione custom per uno o due client.
MCP per lo sviluppatore
Dal punto di vista dell’ingegnere, MCP è un contratto e un protocollo. Risponde alle domande:
- In che formato devo dichiarare uno strumento?
- Come descrivere gli argomenti e restituire il risultato?
- Come farà il client a capire che supporto risorse e prompt?
- Quale JSON transiterà effettivamente in rete?
Con un protocollo del genere diventa più semplice:
- scrivere server in linguaggi diversi (ci sono SDK ufficiali per TypeScript e Python);
- debuggare l’applicazione tramite MCP Inspector o tool analoghi;
- separare le responsabilità tra team: un team realizza il server MCP con dati e strumenti, un altro — il widget con l’Apps SDK, un terzo — può costruire propri agenti sopra lo stesso server MCP.
7. Una piccola prospettiva pratica: il nostro primo server MCP
In questa lezione evitiamo volutamente i dettagli del formato dei messaggi e dell’implementazione del server — è materiale per i prossimi argomenti. Ma, per capire dove stiamo andando, è utile vedere la struttura generale di un server MCP minimo in TypeScript.
Nella realtà, la libreria ufficiale TypeScript di MCP fornisce primitive per creare un server, registrare tools/resources/prompts e avviare il trasporto (di solito HTTP o SSE).
Un esempio pseudocodice può apparire così:
// Esempio concettuale, analizzeremo l'API dell'SDK più avanti
import { createServer } from "@modelcontextprotocol/sdk";
const server = createServer({
name: "gift-genius",
version: "1.0.0",
});
// Registriamo lo strumento
server.tool("suggest_gifts", {
description: "Seleziona regali in base alle preferenze del destinatario",
inputSchema: {/* ... */},
handler: async (input) => {
// la tua logica
return { items: [] };
},
});
// Avviamo il trasporto (ad esempio, HTTP)
server.listen(3001);
Punto importante: qui non si menzionano ChatGPT, Apps SDK o il tuo frontend specifico. Il server MCP è autosufficiente. Sa semplicemente rispondere alle richieste MCP. La ChatGPT App è solo uno dei tipi di client che possono usare tale server.
Nel corso rimarremo sul template Next.js, dove il server MCP vive come parte del progetto, ma non è l’unica possibilità.
8. MCP nell’ecosistema: Apps SDK, Agents SDK e ACP
Per non percepire MCP come «una feature solo dell’Apps SDK», è utile vederlo in un quadro più ampio.
Primo, l’Apps SDK si appoggia direttamente a MCP come ponte standard tra ChatGPT e servizi esterni. La documentazione ufficiale sottolinea: l’Apps SDK funziona con qualsiasi server MCP. Il protocollo consente di descrivere strumenti, restituire dati strutturati e indicare il componente da renderizzare nella UI.
Secondo, anche l’Agents SDK, che analizzerai in un modulo separato, sa collegarsi ai server MCP. Ciò significa che lo stesso server MCP con logica di business può essere usato:
- dentro ChatGPT come parte della tua App;
- dentro un agente autonomo che lavora, ad esempio, in background nel tuo prodotto o in modalità batch.
Terzo, l’ACP (Agentic Commerce Protocol), di cui avrai bisogno per gli acquisti e l’Instant Checkout, si costruisce logicamente sopra l’approccio MCP: il modello e gli agenti invocano strumenti di commerce anch’essi descritti tramite contratti standardizzati.
In tal modo, MCP diventa il fondamento su cui si costruiscono l’UI (Apps SDK), gli scenari agentici (Agents SDK) e il commercio (ACP). Se ti senti a tuo agio con MCP, tutto il resto diventa più chiaro e prevedibile.
Nota: Formalmente l’ACP non dipende da MCP come specifica, ma in implementazioni reali gli strumenti ACP molto probabilmente saranno invocati dal modello proprio tramite interfacce MCP. I due approcci si sovrappongono molto bene; non manca molto.
9. Piccoli esercizi «mentali» prima della pratica
Prima di tuffarci, nella prossima lezione, nel formato dei messaggi MCP, è utile fare un paio di esercizi mentali. Questo aiuterà a “commutare” il pensiero da «tipico REST» a «protocollo + contratto».
Immagina che alla tua Gift‑App vogliano collegarsi non solo ChatGPT, ma anche un plugin IDE per VS Code e un assistente aziendale interno in Slack. Descrivi in una frase ciò che tutti devono sapere sul tuo servizio. Probabilmente la risposta sarà qualcosa come: «Abbiamo lo strumento suggest_gifts con tali parametri e un catalogo di regali disponibile tramite una certa risorsa». Questo è esattamente ciò che MCP formalizza.
Prova anche a formulare in due frasi:
- che cos’è MCP per il product della tua App (suggerimento: un modo standard per “impacchettare” funzionalità per client diversi);
- che cos’è MCP per lo sviluppatore (suggerimento: un protocollo JSON‑RPC con primitive chiare tools/resources/prompts).
Se riesci a farlo senza esitazioni — sei già a metà strada per lavorare con MCP con sicurezza.
Se riduciamo tutto quanto a un’unica tesi: MCP non è un altro API di livello superiore, ma un contratto di base tra la tua logica e i client LLM. Nelle prossime lezioni guarderemo dentro il protocollo: analizzeremo il formato dei messaggi MCP, handshake/capabilities e impareremo a osservare il traffico tramite inspector, così che questi principi non restino astratti ma diventino strumenti operativi.
10. Errori e fraintendimenti tipici attorno a MCP
Errore n. 1: considerare MCP «solo un altro layer API sopra il mio REST».
A volte viene la tentazione: «Ho già un REST, aggiungo un sottile adattatore che traduca le chiamate MCP in REST e viceversa, e basta». Formalmente si può fare, ma poi spesso inizi a trascinare le particolarità della vecchia API dentro MCP: tipi strani, risposte non strutturate, assenza di schemi espliciti. Col tempo l’adattatore cresce e il vantaggio di MCP si riduce. È meglio considerare MCP come il contratto principale e il vecchio REST come dettaglio interno d’implementazione, se ancora serve.
Errore n. 2: pensare che MCP sia «solo per le ChatGPT Apps».
MCP è un protocollo aperto generale per qualsiasi client LLM: ChatGPT, plugin IDE, agenti autonomi. Se progetti un server MCP mirando a una sola App, ti limiti per il futuro. Conviene molto di più pensare subito: «questo server potrà essere usato anche da altri client», e progettare strumenti e risorse un po’ più universali.
Errore n. 3: ignorare lo JSON Schema e descrivere gli argomenti “a parole”.
Anche se l’SDK ti permette di passare “qualunque JSON” da qualche parte, non essere pigro: descrivi gli schemi di argomenti e risultati. Da questo dipendono direttamente la capacità del modello di invocare correttamente il tuo strumento, la qualità dell’autocompletamento e della discovery, nonché la comodità del debug tramite inspector. Argomenti non descritti o descritti male portano dritti a errori enigmatici di tool‑call.
Errore n. 4: percepire MCP come «trasporto magico» e non guardare i log.
Finché tutto funziona, sembra che MCP sia qualcosa di invisibile di cui non ci si deve occupare. Il problema è che, appena qualcosa si rompe, senza capire la struttura di MCP perderai tempo a chiederti: «è l’Apps SDK? è il modello? è il mio backend?». L’abitudine di guardare i messaggi MCP e i log fin da subito ti risparmierà ore di tentativi a vuoto.
Errore n. 5: provare a progettare workflow complessi solo tramite REST, ignorando le primitive MCP.
Quando compaiono scenari multi‑step (ricerca del regalo → chiarimento delle preferenze → scelta → completamento dell’ordine), viene voglia di «fare un unico grande endpoint REST». Nel contesto delle ChatGPT Apps spesso peggiora la controllabilità: il modello capisce peggio i passi intermedi e il client MCP perde la possibilità di riusare risorse e prompt. È molto meglio suddividere la funzionalità in più tools/resources ben descritti e collegare la logica tramite prompt di sistema e descrizioni appropriate.
GO TO FULL VERSION