Il Model Context Protocol (MCP) è nato per risolvere il problema dell'incompatibilità. Nella vita di tutti i giorni, l'incompatibilità ci crea inconvenienti in molti modi.
Ti è mai capitato di portare con te un asciugacapelli o un dispositivo elettronico durante un viaggio all'estero e scoprire che la sua spina non è compatibile con la presa di corrente? Dal punto di vista di uno sviluppatore, questo problema è frustrante quanto creare API e strumenti di sviluppo per il proprio agente AI e scoprire che non riesce a connettersi o a invocarli correttamente. È proprio qui che l'MCP risolve questo problema di incompatibilità.
Il Model Context Protocol (MCP), introdotto da Anthropic nel 2024, funge da livello di standardizzazione che consente alle applicazioni di AI di comunicare efficacemente con servizi esterni, come strumenti, origini dati/set di dati e modelli predefiniti. MCP funge essenzialmente da standard aperto e da connettore per le interazioni tra l'AI e gli strumenti. L'architettura di MCP può essere suddivisa in tre componenti architetturali fondamentali:
Prima di tutto, cos'è IBM Bob? IBM Bob è un ambiente di sviluppo integrato (IDE) basato su AI generativa e un assistente per la modernizzazione. Pensa a Bob come al tuo IDE AI-first e assistente di sviluppo: uno strumento che comprende il tuo intento, la tua base di codice e gli standard della tua organizzazione.
Creare da zero il proprio server MCP può richiedere molto tempo, soprattutto per gli sviluppatori alle prime armi. In questo tutorial esploreremo invece come avviare rapidamente questo workflow con IBM Bob utilizzando alcuni semplici prompt in linguaggio naturale.
L'integrazione di MCP estende le funzionalità di Bob collegandolo a strumenti e servizi esterni, configurabili a livello globale (applicato a tutti i workspace) oppure a livello di progetto (condivisibile con il team tramite i livelli .Bob/mcp.json). MCP supporta due tipi di trasporto: standard input/output (STDIO) per server locali a bassa latenza e server-sent events (SSE) per server MCP remoti accessibili tramite HTTP/HTTPS. Gli utenti possono configurare i server tramite file JSON nel menu delle impostazioni di Bob, definendo comandi, variabili d'ambiente e strumenti approvati automaticamente. Entrambi i tipi di trasporto consentono di abilitare o disabilitare i server, approvare automaticamente strumenti specifici e gestirne il funzionamento tramite il pannello delle impostazioni MCP di Bob.
Cominciamo. Se preferisci seguire questo tutorial su GitHub, dai un'occhiata al nostro repository.
1. Apri IBM Bob IDE, che hai installato come prerequisito, e familiarizza con il layout del tuo nuovo assistente di AI coding.
2. Per accedere al pannello delle impostazioni MCP, fai clic sui tre puntini accanto all'icona dell'ingranaggio nell'angolo superiore destro della finestra della chat. Seleziona quindi i server MCP dal menu a discesa.
Qui è possibile abilitare o disabilitare MCP a livello globale oppure per singolo server e gestire gli strumenti (ad esempio approvazione automatica, eliminazione o riavvio). Possiamo anche esplorare i server della community tramite il Bob Marketplace oppure crearne uno nostro utilizzando l'MCP SDK.
Se hai scelto di installare un server dal Bob Marketplace, noterai che le configurazioni possono essere impostate su due livelli: globale (memorizzate in
Le impostazioni a livello di progetto hanno la precedenza su quelle globali, offrendo la flessibilità necessaria per adattare il comportamento di MCP a diversi casi d'uso. Per gestire queste configurazioni, puoi modificare direttamente i file JSON dal menu delle impostazioni di Bob, dove puoi definire i dettagli del server, come i comandi, le variabili d'ambiente e gli strumenti approvati automaticamente. In questo tutorial, useremo l'SDK.
3. Assicurati che l'impostazione Enable MCP Server Creation sia attiva per creare server MCP personalizzati con Bob.
4. Se hai una directory preferita in cui configurare il progetto, puoi aprirla direttamente nell'IDE oppure chiedere a Bob di farlo tramite la finestra della chat.
3. È pratica comune creare ambienti virtuali Python per isolare le dipendenze di un progetto, in modo che progetti diversi non entrino in conflitto tra loro. Per farlo, inserisci il prompt: "In this directory, activate a Python virtual environment".
4. Dovresti vedere Bob eseguire una serie di comandi nel terminale. Questi comandi probabilmente somiglieranno a:
Ti consigliamo di mantenere disattivata l'opzione di approvazione automatica, così potrai approvare o rifiutare ogni comando prima che Bob lo esegua in tempo reale.
Perfetto. Bob ha creato e attivato correttamente un nuovo ambiente virtuale nella directory
Una volta configurato l'ambiente virtuale, possiamo passare alla creazione del server MCP. Quando chiedi a Bob di generare codice, o ti rivolgi a qualsiasi altro modello o assistente AI, è utile includere tutti i dettagli importanti. Per vedere Bob in azione, inviamo il prompt:
"Crea un server MCP che fornisca accesso in sola lettura ad arXiv. Il server dovrebbe:
Con questo semplice prompt, Bob dispone di informazioni sufficienti sia per comprendere l'attività sia per elaborare un elenco di passaggi da seguire per completarla. Nota che l'elenco include non solo la creazione del server MCP, ma anche la sua configurazione e il relativo test. Fantastico.
Tieni presente che in questo tutorial utilizziamo l'API di arXiv come semplice esempio, poiché non richiede chiavi API né autenticazione per iniziare. Tuttavia, si tratta solo di un esempio: Bob è perfettamente in grado di gestire anche server più complessi che richiedono autorizzazioni specifiche.
Prima di eseguire ogni comando, possiamo approvare o negare l'azione. Se noti che i comandi vengono eseguiti automaticamente, è possibile che tu abbia attivato l'opzione di approvazione automatica.
2. Successivamente, Bob crea un file
{
"name": "arxiv-server",
"version": "0.1.0",
"description": "MCP server for read-only access to arXiv papers",
"type": "module",
"bin": {
"arxiv-server": "./build/index.js"
},
"files": [
"build"
],
"scripts": {
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
"prepare": "npm run build",
"watch": "tsc --watch"
},
"keywords": [
"mcp",
"arxiv",
"research",
"papers"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.4",
"axios": "^1.7.9",
"zod": "^3.24.1"
},
"devDependencies": {
"@types/node": "^22.10.5",
"typescript": "^5.7.3"
}
}
arxiv-server/tsconfig.json{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "build"]
}
4. Poi, l'implementazione principale del server con la funzionalità di ricerca su arXiv viene memorizzata in
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import axios from 'axios';
// Define types for arXiv API responses
interface ArxivEntry {
id: string;
title: string;
summary: string;
authors: Array<{ name: string }>;
published: string;
updated: string;
categories: string[];
primary_category: string;
links: Array<{ href: string; rel: string; type?: string }>;
}
interface ArxivSearchResult {
entries: ArxivEntry[];
totalResults: number;
startIndex: number;
itemsPerPage: number;
}
// Create an MCP server
const server = new McpServer({
name: "arxiv-server",
version: "0.1.0"
});
// Create axios instance for arXiv API
const arxivApi = axios.create({
baseURL: 'http://export.arxiv.org/api',
timeout: 30000,
});
/**
* Parse arXiv API XML response to JSON
*/
function parseArxivXML(xmlData: string): ArxivSearchResult {
const entries: ArxivEntry[] = [];
// Extract total results
const totalResultsMatch = xmlData.match(/<opensearch:totalResults[^>]*>(\d+)<\/opensearch:totalResults>/);
const totalResults = totalResultsMatch ? parseInt(totalResultsMatch[1]) : 0;
const startIndexMatch = xmlData.match(/<opensearch:startIndex[^>]*>(\d+)<\/opensearch:startIndex>/);
const startIndex = startIndexMatch ? parseInt(startIndexMatch[1]) : 0;
const itemsPerPageMatch = xmlData.match(/<opensearch:itemsPerPage[^>]*>(\d+)<\/opensearch:itemsPerPage>/);
const itemsPerPage = itemsPerPageMatch ? parseInt(itemsPerPageMatch[1]) : 0;
// Extract entries
const entryRegex = /<entry>([\s\S]*?)<\/entry>/g;
let entryMatch;
while ((entryMatch = entryRegex.exec(xmlData)) !== null) {
const entryXml = entryMatch[1];
// Extract ID
const idMatch = entryXml.match(/<id>([^<]+)<\/id>/);
const id = idMatch ? idMatch[1] : '';
// Extract title
const titleMatch = entryXml.match(/<title>([^<]+)<\/title>/);
const title = titleMatch ? titleMatch[1].trim().replace(/\s+/g, ' ') : '';
// Extract summary
const summaryMatch = entryXml.match(/<summary>([^<]+)<\/summary>/);
const summary = summaryMatch ? summaryMatch[1].trim().replace(/\s+/g, ' ') : '';
// Extract authors
const authors: Array<{ name: string }> = [];
const authorRegex = /<author>\s*<name>([^<]+)<\/name>/g;
let authorMatch;
while ((authorMatch = authorRegex.exec(entryXml)) !== null) {
authors.push({ name: authorMatch[1].trim() });
}
// Extract published date
const publishedMatch = entryXml.match(/<published>([^<]+)<\/published>/);
const published = publishedMatch ? publishedMatch[1] : '';
// Extract updated date
const updatedMatch = entryXml.match(/<updated>([^<]+)<\/updated>/);
const updated = updatedMatch ? updatedMatch[1] : '';
// Extract categories
const categories: string[] = [];
const categoryRegex = /<category[^>]+term="([^"]+)"/g;
let categoryMatch;
while ((categoryMatch = categoryRegex.exec(entryXml)) !== null) {
categories.push(categoryMatch[1]);
}
const primary_category = categories[0] || '';
// Extract links
const links: Array<{ href: string; rel: string; type?: string }> = [];
const linkRegex = /<link[^>]+href="([^"]+)"[^>]+rel="([^"]+)"(?:[^>]+type="([^"]+)")?/g;
let linkMatch;
while ((linkMatch = linkRegex.exec(entryXml)) !== null) {
links.push({
href: linkMatch[1],
rel: linkMatch[2],
type: linkMatch[3]
});
}
entries.push({
id,
title,
summary,
authors,
published,
updated,
categories,
primary_category,
links
});
}
return {
entries,
totalResults,
startIndex,
itemsPerPage
};
}
/**
* Format search results for display
*/
function formatSearchResults(result: ArxivSearchResult): string {
let output = `Found ${result.totalResults} results (showing ${result.entries.length})\n\n`;
result.entries.forEach((entry, index) => {
output += `${index + 1}. ${entry.title}\n`;
output += ` ID: ${entry.id}\n`;
output += ` Authors: ${entry.authors.map(a => a.name).join(', ')}\n`;
output += ` Published: ${entry.published}\n`;
output += ` Categories: ${entry.categories.join(', ')}\n`;
output += ` Abstract: ${entry.summary.substring(0, 300)}${entry.summary.length > 300 ? '...' : ''}\n`;
// Find abstract link (not PDF)
const abstractLink = entry.links.find(l => l.rel === 'alternate');
if (abstractLink) {
output += ` URL: ${abstractLink.href}\n`;
}
output += '\n';
});
return output;
}
// Add a tool for searching arXiv papers
server.tool(
"search_arxiv",
{
query: z.string().describe("Search query (supports arXiv query syntax)"),
max_results: z.number().min(1).max(50).optional().describe("Maximum number of results to return (1-50, default: 10)"),
start: z.number().min(0).optional().describe("Starting index for pagination (default: 0)"),
sort_by: z.enum(["relevance", "lastUpdatedDate", "submittedDate"]).optional().describe("Sort order (default: relevance)"),
sort_order: z.enum(["ascending", "descending"]).optional().describe("Sort direction (default: descending)")
},
async ({ query, max_results = 10, start = 0, sort_by = "relevance", sort_order = "descending" }) => {
try {
// Enforce reasonable limits
const limitedMaxResults = Math.min(max_results, 50);
const limitedStart = Math.max(start, 0);
// Build query parameters
const params: Record<string, string | number> = {
search_query: query,
start: limitedStart,
max_results: limitedMaxResults,
};
if (sort_by) {
params.sortBy = sort_by;
}
if (sort_order) {
params.sortOrder = sort_order;
}
const response = await arxivApi.get('/query', { params });
// Parse XML response
const result = parseArxivXML(response.data);
// Format results
const formattedResults = formatSearchResults(result);
return {
content: [
{
type: "text",
text: formattedResults,
},
],
};
} catch (error) {
if (axios.isAxiosError(error)) {
return {
content: [
{
type: "text",
text: `arXiv API error: ${error.response?.data?.message ?? error.message}`,
},
],
isError: true,
};
}
throw error;
}
}
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('arXiv MCP server running on stdio');
// Made with Bob
In questa fase, se il tuo server richiede chiavi API, Bob te le chiederà.
5. Come passo successivo, Bob installa le dipendenze all'interno della directory arxiv-server eseguendo il seguente comando.
mcp_settings.json.Bob/mcp.json{
"mcpServers": {}
"mcpServers": {
"arxiv": {
"command": "node",
"args": [ "/here/is/the/path/to/arxiv-server/build/index.js"
],
"disabled": false,
"alwaysAllow": [],
"disabledTools": []
}
}
}
Queste informazioni completano la serie di passaggi che Bob compie per configurare il server MCP.
Per completare la serie di attività "to-do list", Bob testa il server MCP. Come si vede nella schermata precedente, Bob interroga lo strumento
Dopo l'esecuzione riuscita, che puoi verificare facendo clic sulla freccia rivolta verso il basso per espandere la finestra, Bob ha eseguito un altro test. Questa volta, la query riguarda 2 articoli sul machine learning, ordinati in base alla data di invio in ordine decrescente. Anche con l'utilizzo di parametri diversi, questa chiamata allo strumento MCP è stata eseguita correttamente.
Dati i test riusciti, Bob ha ora completato tutte le sottoattività.
Bob ha già testato il server MCP per noi. Proviamo ora a eseguire alcune query direttamente dalla finestra della chat, per verificare se Bob è in grado di dedurre i termini di ricerca corretti e i parametri necessari.
Chiedi a Bob: "Quali sono gli ultimi articoli sul tracciamento degli agenti LLM?"
Da solo, Bob ha estratto correttamente la query dal nostro prompt e ha aggiunto alcune parole chiave per migliorare la ricerca. Bob ha inoltre impostato il numero massimo di risultati a 10 e ha ordinato gli articoli in base alla loro rilevanza. Ottimo.
Proviamo con un'altra query.
È interessante notare che Bob ha modificato automaticamente la query di ricerca dopo aver rilevato risultati indesiderati. Bob non si limita a eseguire le chiamate agli strumenti in modo automatico, ma collabora con l'utente comportandosi come un agente utile. Dopo due iterazioni di questo processo, Bob ha restituito diversi articoli che corrispondono alla nostra richiesta iniziale.
Molti server MCP open source includono anche una documentazione che permette ad altri utenti di iniziare a utilizzarli facilmente. Incolliamo questo prompt nella finestra della chat:
"In questa directory, crea un file README.md per documentare questo server MCP. Includi istruzioni di configurazione e utilizzo."
Con un semplice prompt, Bob ha creato un documento
Forse ti interessa creare un agente AI specializzato nella ricerca con watsonx Orchestrate in grado di accedere a questo server MCP? Bob può creare un agente con un semplice prompt. Per prima cosa, installa il server ADK di watsonx Orchestrate preconfigurato dal marketplace disponibile nel pannello delle impostazioni MCP che abbiamo esplorato nel passaggio 1. Invia quindi questo comando:
"Crea un agente watsonx Orchestrate che utilizzi questo server MCP arxiv."
Se il servizio watsonx Orchestrate è in esecuzione localmente, Bob eseguirà i comandi necessari per te. Se preferisci eseguire i comandi in un secondo momento, Bob scriverà gli script e documenterà tutti i comandi necessari.
Esaminiamo ogni file per capire meglio cosa ha generato Bob. Ecco il file toolkit-config.yaml
kind: mcp
name: arxiv-toolkit
description: Toolkit per la ricerca di articoli su arXiv. Fornisce l'accesso ai metadati degli articoli, agli abstract e alle informazioni di pubblicazione presenti nel database di arXiv.
package_root: /local/path/to/arxiv-server
language: node
command: node /local/path/to/arxiv-server/arxiv-server/build/index.js
tools:
- "*"
# Made with Bob
Ora apriamo il file research-assistant-agent.yaml
name: research-assistant
kind: native
description: Assistente IA per la ricerca che aiuta a trovare e riassumere articoli accademici da arXiv. È specializzato nella ricerca della letteratura scientifica, nella spiegazione dei risultati della ricerca e nella fornitura di citazioni bibliografiche.
title: Research Assistant
instructions: |
You are an expert research assistant specializing in academic literature search on arXiv.
## Your Capabilities
- Ricercare articoli su arXiv relativi a qualsiasi argomento scientifico - Riassumere in modo chiaro i risultati della ricerca a partire dagli abstract - Individuare gli autori principali e le tendenze della ricerca - Suggerire articoli e argomenti correlati - Fornire citazioni bibliografiche corrette con gli ID arXiv e gli URL.
## When Responding to Users
1. Fornisci sempre gli ID arXiv e gli URL diretti agli articoli
2. Riassumi gli abstract con un linguaggio semplice e accessibile
3. Evidenzia i contributi principali e i risultati più significativi
4. Suggerisci ricerche successive quando opportuno
5. Sii conciso ma informativo
## Using the search_arxiv Tool
AParametri disponibili:
- query (obbligatorio): query di ricerca che utilizza la sintassi di arXiv
- max_results (facoltativo): da 1 a 50 articoli, valore predefinito 10
- start (facoltativo): indice iniziale per la paginazione, valore predefinito 0
- sort_by (facoltativo): "relevance", "submittedDate" o "lastUpdatedDate"
- sort_order (facoltativo): "ascending" o "descending"
## Advanced Search Syntax
Puoi usare questi operatori nelle query:
- ti:keyword - Ricerca nel titolo
- au:author - Ricerca per nome dell'autore
- abs:keyword - Ricerca nell'abstract
- cat:category - Filtra per categoria (ad esempio cs.AI, quant-ph, math.CO)
- AND, OR, ANDNOT - Operatori booleani
Esempi:
- "ti:transformer AND cat:cs.LG" - Articoli sui transformer nel machine learning
- "au:Hinton" - Articoli di Geoffrey Hinton
- "quantum computing AND cat:quant-ph" - Quantum computing nella fisica quantistica
## Common Categories
- cs.AI - Intelligenza artificiale
- cs.LG - Machine Learning
- cs.CL - Elaborazione del linguaggio
- cs.CV - Computer Vision
- quant-ph - Fisica quantistica
- math.CO - Combinatoria
- stat.ML - Machine Learning (Statistica)
## Response Format
Quando presenti gli articoli, utilizza questo formato:
**"Titolo dell'articolo"**
- Autori: [Nomi degli autori]
- Pubblicato: [Data]
- Categorie: [Categorie]
- Riassunto: [Breve riassunto dell'abstract]
- [Visualizza l'articolo](URL di arXiv)
## Handling Edge Cases
- Se non vengono trovati risultati: suggerisci termini di ricerca alternativi o query più generiche
- Se vengono trovati troppi risultati: consiglia di restringere la ricerca utilizzando categorie o filtri per data
- Se l'utente richiede i PDF: spiega che fornisci solo i metadati, ma includi l'URL da cui è possibile accedere all'articolo
- Se la query non è chiara: poni domande di chiarimento sull'ambito della ricerca o sugli interessi specifici.
tools:
- search_arxiv
config:
hidden: false
enable_cot: true
tags:
- research
- academic
- papers
- arxiv
- literature-search
# Made with Bob
Questo file YAML configura il nostro assistente per la ricerca, un agente AI specializzato che semplifica la ricerca accademica effettuando ricerche su arXiv, riassumendo gli articoli e fornendo citazioni in un formato strutturato. Sono incluse istruzioni dettagliate che guidano il comportamento dell'agente, dalla sintassi delle query e dall'utilizzo degli strumenti fino alla formattazione delle risposte e alla gestione dei casi limite. Tutte queste informazioni sono descritte in dettaglio utilizzando lo strumento search_arxivsetup-instructions.md
In questo tutorial abbiamo utilizzato IBM Bob, un IDE AI-first e assistente di sviluppo, per semplificare l'integrazione di MCP nella ricerca accademica. Hai creato in modo efficiente un server MCP scalabile, in grado di cercare e recuperare articoli dal repository di arXiv.org. Ora la tua soluzione è pronta per l'uso in produzione, sia che tu scelga di renderla open source per la comunità della ricerca, sia che tu decida di distribuirla nelle applicazioni della tua azienda per migliorare la scoperta delle conoscenze.
La vera forza di IBM Bob risiede nella sua capacità di trasformare attività di sviluppo complesse in workflow intuitivi, guidati da prompt. Con pochi input strategici, Bob accelera la creazione di prototipi, riduce il codice boilerplate e suggerisce persino possibili ottimizzazioni, permettendoti di concentrarti sull'innovazione anziché sull'implementazione.
Continuando a esplorarne le funzionalità, scoprirai come Bob possa perfezionare ulteriormente il tuo server MCP. Tra i possibili benefici possiamo citare l'aggiunta di filtri avanzati, aggiornamenti in tempo reale e l'integrazione con altri database accademici, come PubMed o IEEE Xplore. Tutte queste possibilità, e molte altre ancora, sono a portata di pochi semplici prompt con IBM Bob.
Vuoi fare il passo successivo? Sperimenta personalizzando il tuo server MCP oppure approfondisci le funzionalità di Bob per sbloccare un potenziale di automazione ancora maggiore. Buona codifica!
Crea, implementa e gestisci assistenti e agenti AI potenti che automatizzano workflow e processi con l'AI generativa.
Costruisci il futuro della tua azienda con soluzioni AI di cui puoi fidarti.
I servizi di AI di IBM Consulting aiutano a reinventare il modo in cui le aziende lavorano con l'AI per la trasformazione.