Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In questa esercitazione si apprenderà come esporre le funzionalità di un'app Express.js tramite il protocollo MCP (Model Context Protocol), aggiungerlo come strumento a GitHub Copilot e interagire con l'app usando il linguaggio naturale in modalità agente di Chat Copilot.
Se l'applicazione Web dispone già di funzionalità utili, ad esempio shopping, prenotazione hotel o gestione dei dati, è facile rendere disponibili queste funzionalità per:
- Qualsiasi applicazione che supporta l'integrazione MCP, ad esempio la modalità agente di Chat di GitHub Copilot in Visual Studio Code o in GitHub Codespaces.
- Agente personalizzato che accede a strumenti remoti tramite un client MCP.
Aggiungendo un server MCP all'app Web, si abilita un agente per comprendere e usare le funzionalità dell'app quando risponde alle richieste degli utenti. Ciò significa che qualsiasi operazione che l'app può fare, anche l'agente può fare.
- Aggiungere un server MCP alla web app.
- Testare il server MCP in locale in modalità agente Chat di GitHub Copilot.
- Distribuire il server MCP nel servizio app di Azure e connetterlo in GitHub Copilot Chat.
Prerequisites
Questa esercitazione presuppone che si stia usando l'esempio usato in Esercitazione: Distribuire un'app Web Node.js + MongoDB in Azure.
Aprire almeno l'applicazione di esempio in GitHub Codespaces e distribuire l'app eseguendo azd up.
Aggiungere un server MCP all'app Web
Nel terminale codespace aggiungere i pacchetti npm necessari al progetto:
npm install @modelcontextprotocol/sdk@latest zod-
- Aprire route/index.js. Per semplicità dello scenario, si aggiungerà qui tutto il codice del server MCP.
All'inizio di routes/index.js, aggiungere le seguenti istruzioni richieste:
const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp.js'); const { StreamableHTTPServerTransport } = require('@modelcontextprotocol/sdk/server/streamableHttp.js'); const { z } = require('zod');Nella parte inferiore del file, sopra
module.exports = router;aggiungere la seguente route per il server MCP.router.post('/api/mcp', async function(req, res, next) { try { // Stateless server instance for each request const server = new McpServer({ name: "task-crud-server", version: "1.0.0" }); // Register tools server.registerTool( "create_task", { description: 'Create a new task', inputSchema: { taskName: z.string().describe('Name of the task to create') }, }, async ({ taskName }) => { const task = new Task({ taskName: taskName, createDate: new Date(), }); await task.save(); return { content: [ { type: 'text', text: `Task created: ${JSON.stringify(task)}` } ] }; } ); server.registerTool( "get_tasks", { description: 'Get all tasks' }, async () => { const tasks = await Task.find(); return { content: [ { type: 'text', text: `All tasks: ${JSON.stringify(tasks, null, 2)}` } ] }; } ); server.registerTool( "get_task", { description: 'Get a task by ID', inputSchema: { id: z.string().describe('Task ID') }, }, async ({ id }) => { try { const task = await Task.findById(id); if (!task) { throw new Error(); } return { content: [ { type: 'text', text: `Task: ${JSON.stringify(task)}` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Task not found with ID: ${id}` } ], isError: true }; } } ); server.registerTool( "update_task", { description: 'Update a task', inputSchema: { id: z.string().describe('Task ID'), taskName: z.string().optional().describe('New task name'), completed: z.boolean().optional().describe('Task completion status') }, }, async ({ id, taskName, completed }) => { try { const updateData = {}; if (taskName !== undefined) updateData.taskName = taskName; if (completed !== undefined) { updateData.completed = completed; if (completed === true) { updateData.completedDate = new Date(); } } const task = await Task.findByIdAndUpdate(id, updateData); if (!task) { throw new Error(); } return { content: [ { type: 'text', text: `Task updated: ${JSON.stringify(task)}` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Task not found with ID: ${id}` } ], isError: true }; } } ); server.registerTool( "delete_task", { description: 'Delete a task', inputSchema: { id: z.string().describe('Task ID to delete') }, }, async ({ id }) => { try { const task = await Task.findByIdAndDelete(id); if (!task) { throw new Error(); } return { content: [ { type: 'text', text: `Task deleted successfully: ${JSON.stringify(task)}` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Task not found with ID: ${id}` } ], isError: true }; } } ); // Create fresh transport for this request const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, }); // Clean up when request closes res.on('close', () => { transport.close(); server.close(); }); await server.connect(transport); await transport.handleRequest(req, res, req.body); } catch (error) { console.error('Error handling MCP request:', error); if (!res.headersSent) { res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: 'Internal server error', }, id: null, }); } } });Questa route imposta l'endpoint server MCP su
<url>/api/mcpe usa il modello di modalità senza stato in MCP TypeScript SDK.-
server.registerTool()aggiunge uno strumento al server MCP con la relativa implementazione. - L'SDK usa zod per la convalida dell'input.
-
descriptionnell'oggetto di configurazione edescribe()ininputSchemaforniscono descrizioni leggibili per gli strumenti e l'input. Consentono all'agente chiamante di comprendere come usare gli strumenti e i relativi parametri.
Questo percorso duplica la funzionalità create-read-update-delete (CRUD) dei percorsi esistenti, che non è necessaria, ma verrà mantenuto per semplicità. Una procedura consigliata consiste nello spostare la logica dell'app in un modulo, quindi chiamare il modulo da tutte le route.
-
Testare il server MCP in locale
Nel terminale codespace eseguire l'applicazione con
npm start.Selezionare Apri nel browser e quindi aggiungere un'attività.
Lasciare
npm startin esecuzione. Attualmente, il server MCP è in esecuzionehttp://localhost:3000/api/mcp.Nel codespace aprire Copilot Chat e quindi selezionare Modalità agente nella casella di richiesta.
Selezionare il pulsante Strumenti e quindi aggiungi altri strumenti nell'elenco a discesa.
Selezionare Aggiungi server MCP.
Selezionare HTTP (HTTP o Eventi inviati dal server).
In Immettere l'URL del server digitare http://localhost:3000/api/mcp.
In Immettere l'ID server digitare todos-mcp o qualsiasi nome desiderato.
Selezionare Impostazioni area di lavoro.
Nella nuova finestra di chat di Copilot, digita qualcosa come "Mostrami i 'todos'."
Per impostazione predefinita, GitHub Copilot mostra una conferma di sicurezza quando si richiama un server MCP. Seleziona Continua.
Verrà visualizzata una risposta che indica che la chiamata allo strumento MCP ha esito positivo.
Distribuire il server MCP su App Service
Tornare al terminale codespace, distribuire le modifiche eseguendo il commit delle modifiche (metodo GitHub Actions) o eseguendo
azd up(metodo dell'interfaccia della riga di comando per sviluppatori di Azure).Nell'output AZD trovare l'URL dell'app. L'URL è simile al seguente nell'output AZD:
Deploying services (azd deploy) (✓) Done: Deploying service web - Endpoint: <app-url>
Una volta completato
azd up, aprire .vscode/mcp.json. Modificare l'URL in<app-url>/api/mcp.Sopra la configurazione del server MCP modificata, selezionare Avvia.
Avviare una nuova finestra di Chat di GitHub Copilot. Dovrebbe essere possibile visualizzare, creare, aggiornare ed eliminare attività nell'agente Copilot.
Procedure consigliate per la sicurezza
Quando il server MCP viene chiamato da un agente basato su modelli linguistici di grandi dimensioni (LLM), prestare attenzione agli attacchi di prompt injection. Considerare le procedure consigliate per la sicurezza seguenti:
- Autenticazione e autorizzazione: proteggere il server MCP con l'autenticazione Microsoft Entra per garantire che solo gli utenti o gli agenti autorizzati possano accedere agli strumenti. Per una guida dettagliata, vedere Proteggere le chiamate MCP (Model Context Protocol) al Servizio app di Azure da Visual Studio Code con l'autenticazione di Microsoft Entra.
-
Convalida e purificazione dell'input: il codice di esempio di questa esercitazione usa zod per la convalida dell'input, assicurandosi che i dati in ingresso corrispondano allo schema previsto. Per maggiore sicurezza, prendere in considerazione:
- Convalida e purificazione di tutti gli input dell'utente prima dell'elaborazione, in particolare per i campi usati nelle query o nell'output del database.
- Escape dell'output nelle risposte per impedire lo scripting tra siti (XSS) se l'API viene usata dai browser.
- Applicazione di schemi rigorosi e valori predefiniti nei modelli per evitare dati imprevisti.
- HTTPS: L'esempio si basa sul servizio app di Azure, che applica HTTPS per impostazione predefinita e fornisce certificati TLS/SSL gratuiti per crittografare i dati in transito.
- Principio dei privilegi minimi: esporre solo gli strumenti e i dati necessari per il caso d'uso. Evitare di esporre operazioni sensibili, a meno che non sia necessario.
- Limitazione della velocità e regolazione: usare Gestione API o middleware personalizzato per evitare attacchi denial-of-service e abusi.
- Registrazione e monitoraggio: accesso e utilizzo dei log degli endpoint MCP per il controllo e il rilevamento delle anomalie. Monitorare l'attività sospetta.
- Configurazione CORS: limitare le richieste tra le origini ai domini attendibili se si accede al server MCP dai browser. Per altre informazioni, vedere Abilitare CORS.
- Aggiornamenti regolari: mantenere aggiornate le dipendenze per attenuare le vulnerabilità note.
Altre risorse
Integrare l'intelligenza artificiale nelle applicazioni del servizio app di Azure