MCP e Pi Agent
Quando lavoriamo con un coding agent, il primo limite che incontriamo non è quasi mai la capacità del modello di scrivere codice. Il limite vero è il contesto operativo.
Il modello può ragionare, progettare, modificare file, eseguire comandi. Ma quando deve parlare con un sistema esterno — un database, una API aziendale, un gestionale, un motore di ricerca interno, una piattaforma documentale — ha bisogno di un ponte.
È qui che entra in gioco MCP, cioè Model Context Protocol.
MCP è uno standard aperto pensato per collegare applicazioni AI a strumenti, dati e workflow esterni. In pratica permette a un agent come Pi di dire: “ho bisogno di questa informazione” oppure “esegui questa azione”, delegando il lavoro a un server esterno che espone strumenti utilizzabili dal modello.
In questa guida costruiamo un esempio concreto: un piccolo connettore MCP locale che espone alcuni strumenti legati a un ipotetico sito nodeai.it, e poi lo colleghiamo a Pi Agent.
L’idea: un connettore come ponte tra Pi e il nostro mondo
Un connettore MCP può essere visto come un piccolo server che dichiara:
- quali strumenti mette a disposizione;
- quali parametri accettano questi strumenti;
- quale risultato restituiscono;
- come il client, in questo caso Pi, può chiamarli.
Nel nostro esempio creeremo un server MCP chiamato nodeai-mcp.
Esporrà due tool:
search_articles
Cerca articoli in una piccola base dati locale.get_article
Restituisce il contenuto sintetico di un articolo.
È un esempio volutamente semplice. Ma la stessa logica può essere applicata a un CRM, a un database, a Notion, a WordPress, a un gestionale interno o a una API privata.
Prima di iniziare: cosa serve
Servono:
node -v
npm -v
pi --version
Poi installeremo il pacchetto ufficiale MCP per TypeScript:
npm install @modelcontextprotocol/sdk zod
Il motivo è semplice: la documentazione ufficiale MCP consiglia l’uso di McpServer dal pacchetto @modelcontextprotocol/sdk/server/mcp.js e, per un server locale, il transport StdioServerTransport.
Per Pi useremo invece un’estensione MCP. Una soluzione pratica è:
pi install npm:pi-mcp-adapter
Questa estensione permette a Pi di usare server MCP tramite un file ~/.pi/agent/mcp.json.
1. Creare il progetto MCP
Creiamo una cartella:
mkdir nodeai-mcp
cd nodeai-mcp
npm init -y
Installiamo le dipendenze:
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
Aggiungiamo un tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist",
"strict": true
},
"include": ["src"]
}
Modifichiamo package.json:
{
"name": "nodeai-mcp",
"version": "1.0.0",
"type": "module",
"bin": {
"nodeai-mcp": "./dist/index.js"
},
"scripts": {
"dev": "tsx src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.23.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"tsx": "^4.0.0",
"typescript": "^5.0.0"
}
}
2. Scrivere il server MCP
Creiamo il file:
mkdir src
touch src/index.ts
Dentro src/index.ts inseriamo:
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const articles = [
{
slug: "react-flow-architetture-complesse",
title: "React Flow: visualizzare architetture complesse in modo intelligente",
category: "frontend",
summary:
"Un articolo su come trasformare architetture, pipeline e sistemi complessi in mappe interattive navigabili.",
},
{
slug: "graphrag-knowledge-graph",
title: "GraphRAG e Knowledge Graph nella AI generativa",
category: "ai",
summary:
"Una guida su come i grafi di conoscenza possono migliorare retrieval, contesto e spiegabilità nei sistemi AI.",
},
{
slug: "csv-knowledge-map",
title: "Da CSV a Knowledge Map",
category: "data",
summary:
"Un esempio pratico per trasformare dati strutturati in mappe della conoscenza navigabili.",
},
];
const server = new McpServer({
name: "nodeai-mcp",
version: "1.0.0",
});
server.registerTool(
"search_articles",
{
title: "Cerca articoli NodeAI",
description:
"Cerca articoli nella base dati locale di NodeAI per parola chiave o categoria.",
inputSchema: {
query: z.string().describe("Parola chiave da cercare"),
},
},
async ({ query }) => {
const q = query.toLowerCase();
const results = articles.filter((article) => {
return (
article.title.toLowerCase().includes(q) ||
article.category.toLowerCase().includes(q) ||
article.summary.toLowerCase().includes(q)
);
});
return {
content: [
{
type: "text",
text: JSON.stringify(results, null, 2),
},
],
};
}
);
server.registerTool(
"get_article",
{
title: "Leggi articolo NodeAI",
description:
"Restituisce titolo, categoria e sintesi di un articolo NodeAI dato il suo slug.",
inputSchema: {
slug: z.string().describe("Slug dell'articolo da recuperare"),
},
},
async ({ slug }) => {
const article = articles.find((item) => item.slug === slug);
if (!article) {
return {
content: [
{
type: "text",
text: `Nessun articolo trovato con slug: ${slug}`,
},
],
isError: true,
};
}
return {
content: [
{
type: "text",
text: JSON.stringify(article, null, 2),
},
],
};
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
// Importante: con stdio, i log devono andare su stderr.
console.error("nodeai-mcp running on stdio");
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
La parte importante è questa:
const transport = new StdioServerTransport();
await server.connect(transport);
Nel transport stdio, il client avvia il server come processo locale e comunica tramite stdin e stdout usando JSON-RPC. È il metodo più semplice per un connettore locale.
3. Compilare il connettore
Eseguiamo:
npm run build
A questo punto il server compilato sarà in:
dist/index.js
Possiamo provarlo manualmente con:
node dist/index.js
Non vedremo una normale API HTTP, perché questo server parla via stdio. È pensato per essere avviato da un client MCP, non usato direttamente dal browser.
4. Collegare il connettore a Pi Agent
Pi può essere esteso tramite pacchetti ed estensioni TypeScript. Le estensioni possono registrare tool, comandi e comportamenti aggiuntivi.
Per usare MCP, installiamo un adapter:
pi install npm:pi-mcp-adapter
Poi creiamo il file globale:
mkdir -p ~/.pi/agent
nano ~/.pi/agent/mcp.json
Su Windows il percorso equivalente è di solito:
C:\Users\<utente>\.pi\agent\mcp.json
Inseriamo:
{
"mcpServers": {
"nodeai": {
"command": "node",
"args": [
"/percorso/assoluto/nodeai-mcp/dist/index.js"
],
"lifecycle": "lazy"
}
}
}
Esempio Windows:
{
"mcpServers": {
"nodeai": {
"command": "node",
"args": [
"C:/Users/andrea.belvedere/projects/nodeai-mcp/dist/index.js"
],
"lifecycle": "lazy"
}
}
}
La modalità lazy significa che il server non viene avviato subito. Pi lo attiva solo quando serve. Questo approccio è utile perché evita di caricare strumenti non necessari all’inizio della sessione.
5. Usare il connettore dentro Pi
Riavviamo Pi:
pi
Ora possiamo chiedere:
Cerca tra gli strumenti MCP qualcosa che possa cercare articoli NodeAI.
Con pi-mcp-adapter, spesso l’uso passa dal tool proxy mcp.
Esempio:
Usa mcp per cercare tool relativi agli articoli.
Oppure:
Cerca articoli NodeAI che parlano di GraphRAG usando il server MCP nodeai.
L’adapter può cercare strumenti disponibili, descriverli e poi chiamarli. Un esempio concettuale è:
mcp({ search: "articles" })
poi:
mcp({
tool: "nodeai_search_articles",
args: "{\"query\":\"GraphRAG\"}"
})
Nota importante: in pi-mcp-adapter, gli argomenti dei tool MCP vengono passati come stringa JSON, non come oggetto JavaScript.
6. Variante: esporre i tool direttamente in Pi
Se vogliamo che i tool MCP appaiano direttamente accanto ai tool nativi di Pi, possiamo usare directTools.
Nel file mcp.json:
{
"mcpServers": {
"nodeai": {
"command": "node",
"args": [
"C:/Users/andrea.belvedere/projects/nodeai-mcp/dist/index.js"
],
"lifecycle": "lazy",
"directTools": true
}
}
}
Questa scelta è comoda per pochi strumenti. Se invece un server MCP espone decine o centinaia di tool, conviene usare il proxy mcp, perché ogni tool diretto consuma spazio nel prompt di sistema.
È uno dei motivi per cui pi-mcp-adapter nasce con l’idea di un unico tool proxy: ridurre il peso sul contesto.
7. Quando usare stdio e quando HTTP
Per un connettore locale, stdio è spesso la scelta migliore:
- non serve aprire porte HTTP;
- il client avvia e chiude il processo;
- è semplice da distribuire;
- funziona bene per automazioni locali.
Per un connettore remoto, invece, è meglio usare Streamable HTTP, che la documentazione MCP indica come transport moderno per server remoti.
In sintesi:
| Scenario | Transport consigliato |
|---|---|
| Tool locale sul proprio PC | stdio |
| Server interno aziendale | streamable-http |
| API pubblica o cloud | streamable-http |
| Compatibilità vecchi client | sse, ma solo se necessario |
8. Come trasformare l’esempio in un connettore reale
Il nostro esempio usa un array locale. In un caso reale potremmo sostituirlo con:
- chiamate REST verso WordPress;
- query a un database;
- lettura di file Markdown;
- interrogazioni a un motore di ricerca interno;
- chiamate a un CRM;
- accesso a documentazione tecnica;
- recupero dati da un knowledge graph.
Ad esempio, il tool search_articles potrebbe chiamare una API:
const response = await fetch(
`https://www.nodeai.it/wp-json/wp/v2/search?search=${encodeURIComponent(query)}`
);
const data = await response.json();
Il principio rimane lo stesso: MCP non impone come recuperare i dati. Definisce solo il modo standard con cui il modello può chiedere al connettore di fare qualcosa.
Conclusione
MCP diventa interessante quando smettiamo di pensarlo come “un altro protocollo” e iniziamo a vederlo come un livello di integrazione.
Da una parte c’è Pi Agent, con la sua capacità di ragionare, modificare codice e usare strumenti. Dall’altra ci sono i nostri sistemi: dati, API, documenti, servizi, processi. Il connettore MCP sta in mezzo.
Nel piccolo esempio di questa guida abbiamo costruito un server locale, esposto due tool e collegato tutto a Pi tramite un adapter MCP. È un caso semplice, ma contiene già l’architettura completa:
Pi Agent
↓
pi-mcp-adapter
↓
nodeai-mcp
↓
dati, API, documenti, servizi
La parte più importante non è il codice in sé. È il cambio di prospettiva: ogni volta che un sistema esterno può essere descritto come un insieme di strumenti, può diventare parte del workflow di un agent.
Ed è proprio qui che MCP mostra il suo valore: trasformare integrazioni sparse in un linguaggio comune, leggibile sia dalle applicazioni AI sia dagli strumenti che già usiamo ogni giorno.
Fonti
- Model Context Protocol — introduzione ufficiale:
https://modelcontextprotocol.io/docs/getting-started/intro - MCP TypeScript SDK — server, tool e transport:
https://ts.sdk.modelcontextprotocol.io/documents/server.html - Specifica MCP — transport stdio e Streamable HTTP:
https://modelcontextprotocol.io/specification/2025-06-18/basic/transports.md - Pi MCP Adapter:
https://github.com/sting8k/pi-mcp-adapter - Pi MCP Extension alternativa:
https://github.com/irahardianto/pi-mcp - Pi web access package:
https://pi.dev/packages/pi-web-access
AI Disclaimer
Questo articolo è stato sviluppato a partire dai miei appunti personali, con l’ausilio dell’intelligenza artificiale per riorganizzare i contenuti, rendere più chiara la struttura e trasformare le note iniziali in una guida più leggibile e coerente per tutti.