Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
In deze zelfstudie bouwt u een MCP-server (Model Context Protocol) die hulpprogramma's voor taakbeheer beschikbaar maakt met behulp van Express en de MCP TypeScript SDK. U implementeert de server in Azure Container Apps en maakt er verbinding mee vanuit GitHub Copilot Chat in VS Code.
In deze handleiding leert u:
- Een Express-app maken die MCP-hulpprogramma's beschikbaar maakt
- De MCP-server lokaal testen met GitHub Copilot
- De app containeriseren en implementeren in Azure Container Apps
- GitHub Copilot verbinden met de geïmplementeerde MCP-server
Vereiste voorwaarden
- Een Azure-account met een actief abonnement. Maak gratis een account.
- Azure CLI versie 2.62.0 of hoger.
- Node.js 20 LTS of hoger.
- Visual Studio Code met de GitHub Copilot-extensie .
- Docker Desktop (optioneel: alleen nodig om de container lokaal te testen).
De scaffold van de app maken
In deze sectie maakt u een nieuw Node.js project met Express en de MCP TypeScript SDK.
Maak de projectmap en initialiseer deze:
mkdir tasks-mcp-server && cd tasks-mcp-server npm init -yAfhankelijkheden installeren:
npm install @modelcontextprotocol/sdk express zod npm install -D typescript @types/node @types/express tsxMaken
tsconfig.json:{ "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "declaration": true }, "include": ["src/**/*"] }Deze configuratie is gericht op ES2022 met Node.js moduleresolutie, uitvoer gecompileerde bestanden naar
dist/en maakt strikte typecontrole mogelijk.Update
package.jsonvoor het inschakelen van ES-modules en het toevoegen van build- en startscripts. Voeg de velden toetypeof vervang dezescripts:{ "type": "module", "scripts": { "build": "tsc", "start": "node dist/index.js", "dev": "tsx watch src/index.ts" } }Belangrijk
Stel
"type": "module"in. De MCP-servercode maakt gebruik van het hoogste niveauawait, dat alleen wordt ondersteund in ES-modules.Maak
src/taskStore.tsvoor de gegevensopslag in het geheugen aan.export interface TaskItem { id: number; title: string; description: string; isComplete: boolean; createdAt: string; } class TaskStore { private tasks: TaskItem[] = [ { id: 1, title: "Buy groceries", description: "Milk, eggs, bread", isComplete: false, createdAt: new Date().toISOString(), }, { id: 2, title: "Write docs", description: "Draft the MCP tutorial", isComplete: true, createdAt: new Date(Date.now() - 86400000).toISOString(), }, ]; private nextId = 3; getAll(): TaskItem[] { return [...this.tasks]; } getById(id: number): TaskItem | undefined { return this.tasks.find((t) => t.id === id); } create(title: string, description: string): TaskItem { const task: TaskItem = { id: this.nextId++, title, description, isComplete: false, createdAt: new Date().toISOString(), }; this.tasks.push(task); return task; } toggleComplete(id: number): TaskItem | undefined { const task = this.tasks.find((t) => t.id === id); if (!task) return undefined; task.isComplete = !task.isComplete; return task; } delete(id: number): boolean { const index = this.tasks.findIndex((t) => t.id === id); if (index < 0) return false; this.tasks.splice(index, 1); return true; } } export const store = new TaskStore();De
TaskItem-interface definieert de vorm van de taakgegevens. DeTaskStoreklasse beheert een in-memory matrix die vooraf is ingevuld met voorbeeldgegevens en biedt methoden voor het weergeven, zoeken, maken, in- en uitschakelen van taken. Een singleton op moduleniveau wordt geëxporteerd voor gebruik door de MCP-hulpprogramma's.
Definieer de MCP-hulpprogramma's
Vervolgens definieert u de MCP-server met hulpprogrammaregistraties waarmee het taakarchief beschikbaar wordt gesteld aan AI-clients.
Maken
src/index.ts:import express, { Request, Response } from "express"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { z } from "zod"; import { store } from "./taskStore.js"; const app = express(); app.use(express.json()); // Health endpoint for Container Apps probes app.get("/health", (_req: Request, res: Response) => { res.json({ status: "healthy" }); }); // Create the MCP server const mcpServer = new McpServer({ name: "TasksMCP", version: "1.0.0", }); // Register tools mcpServer.tool("list_tasks", "List all tasks with their ID, title, description, and completion status.", {}, async () => { return { content: [{ type: "text", text: JSON.stringify(store.getAll(), null, 2) }], }; }); mcpServer.tool( "get_task", "Get a single task by its numeric ID.", { task_id: z.number().describe("The numeric ID of the task to retrieve") }, async ({ task_id }) => { const task = store.getById(task_id); return { content: [ { type: "text", text: task ? JSON.stringify(task, null, 2) : `Task with ID ${task_id} not found.`, }, ], }; } ); mcpServer.tool( "create_task", "Create a new task with the given title and description. Returns the created task.", { title: z.string().describe("A short title for the task"), description: z.string().describe("A detailed description of what the task involves"), }, async ({ title, description }) => { const task = store.create(title, description); return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }], }; } ); mcpServer.tool( "toggle_task_complete", "Toggle a task's completion status between complete and incomplete.", { task_id: z.number().describe("The numeric ID of the task to toggle") }, async ({ task_id }) => { const task = store.toggleComplete(task_id); const msg = task ? `Task ${task.id} is now ${task.isComplete ? "complete" : "incomplete"}.` : `Task with ID ${task_id} not found.`; return { content: [{ type: "text", text: msg }] }; } ); mcpServer.tool( "delete_task", "Delete a task by its numeric ID.", { task_id: z.number().describe("The numeric ID of the task to delete") }, async ({ task_id }) => { const deleted = store.delete(task_id); const msg = deleted ? `Task ${task_id} deleted.` : `Task with ID ${task_id} not found.`; return { content: [{ type: "text", text: msg }] }; } ); // Mount the MCP streamable HTTP transport const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }); app.post("/mcp", async (req: Request, res: Response) => { await transport.handleRequest(req, res, req.body); }); app.get("/mcp", async (req: Request, res: Response) => { await transport.handleRequest(req, res); }); app.delete("/mcp", async (req: Request, res: Response) => { await transport.handleRequest(req, res); }); // Connect the transport to the MCP server await mcpServer.connect(transport); // Start the Express server const PORT = parseInt(process.env.PORT || "3000", 10); app.listen(PORT, () => { console.log(`MCP server running on http://localhost:${PORT}/mcp`); });Belangrijke punten:
-
McpServerdefinieert de MCP-server met registraties van tools vanuit de TypeScript SDK. -
StreamableHTTPServerTransportverwerkt het HTTP-protocol dat kan worden gestreamd met MCP. Door de instellingsessionIdGenerator: undefineddraait de server in stateless-modus. - Hulpprogramma's gebruiken Zod-schema's om invoerparameters met beschrijvingen te definiëren.
- Er is een afzonderlijk
/healtheindpunt vereist voor gezondheidscontroles van Container Apps.
-
De MCP-server lokaal testen
Voordat u implementeert in Azure, controleert u of de MCP-server werkt door deze lokaal uit te voeren en verbinding te maken vanuit GitHub Copilot.
Start de ontwikkelserver:
npx tsx src/index.tsOpen VS Code, open Copilot Chat en selecteer agentmodus .
Selecteer de knop Extra en selecteer vervolgens Meer hulpprogramma's toevoegen...>MCP-server toevoegen.
Selecteer HTTP (HTTP of Server-Sent-gebeurtenissen).
Voer de server-URL in:
http://localhost:3000/mcpOpmerking
De lokale ontwikkelserver wordt standaard ingesteld op poort 3000. Wanneer de container is geplaatst, stelt het Dockerfile de
PORTomgevingsvariabele in op 8080 zodat deze overeenkomt met de doelpoort van Container Apps.Voer een server-id in:
tasks-mcpSelecteer Werkruimte-instellingen.
Test met een prompt: 'Toon alle taken'
Selecteer Doorgaan wanneer Copilot om bevestiging van de aanroep van het hulpprogramma vraagt.
U zou moeten zien dat Copilot de lijst met taken uit uw in-memory opslag retourneert.
Aanbeveling
Probeer andere prompts zoals 'Creëer een taak om de PR te controleren', 'Taak 1 markeren als voltooid' of 'Taak 2 verwijderen'.
De toepassing in een container plaatsen
Verpak de toepassing als een Docker-container, zodat u deze lokaal kunt testen voordat u implementeert in Azure.
Maak een
Dockerfile:FROM node:20-slim AS build WORKDIR /app COPY package*.json . RUN npm ci COPY tsconfig.json . COPY src/ src/ RUN npm run build FROM node:20-slim WORKDIR /app COPY package*.json . RUN npm ci --omit=dev COPY --from=build /app/dist ./dist ENV PORT=8080 EXPOSE 8080 CMD ["node", "dist/index.js"]De build met meerdere fasen compileert TypeScript in de eerste fase en maakt vervolgens een productie-installatiekopie met alleen runtime-afhankelijkheden en de gecompileerde JavaScript-uitvoer. De
PORTomgevingsvariabele is ingesteld op 8080 zodat deze overeenkomt met de doelpoort van Container Apps.Lokaal verifiëren:
docker build -t tasks-mcp-server . docker run -p 8080:8080 tasks-mcp-serverBevestigen:
curl http://localhost:8080/health
Implementeren in Azure Container Apps
Nadat u de toepassing in een container hebt geplaatst, implementeert u deze in Azure Container Apps met behulp van Azure CLI. De opdracht az containerapp up bouwt de containerafbeelding in de cloud, zodat u Docker niet nodig hebt op uw machine voor deze stap.
Omgevingsvariabelen instellen:
RESOURCE_GROUP="mcp-tutorial-rg" LOCATION="eastus" ENVIRONMENT_NAME="mcp-env" APP_NAME="tasks-mcp-server-node"Een resourcegroep maken:
az group create --name $RESOURCE_GROUP --location $LOCATIONEen Container Apps-omgeving maken:
az containerapp env create \ --name $ENVIRONMENT_NAME \ --resource-group $RESOURCE_GROUP \ --location $LOCATIONDe container-app implementeren:
az containerapp up \ --name $APP_NAME \ --resource-group $RESOURCE_GROUP \ --environment $ENVIRONMENT_NAME \ --source . \ --ingress external \ --target-port 8080CONFIGUREER CORS om GitHub Copilot-aanvragen toe te staan:
az containerapp ingress cors enable \ --name $APP_NAME \ --resource-group $RESOURCE_GROUP \ --allowed-origins "*" \ --allowed-methods "GET,POST,DELETE,OPTIONS" \ --allowed-headers "*"Opmerking
Vervang tijdens de productiefase de jokertekens
*door specifieke vertrouwde bronnen. Zie Beveiligde MCP-servers in Container Apps voor hulp.Controleer de implementatie:
APP_URL=$(az containerapp show \ --name $APP_NAME \ --resource-group $RESOURCE_GROUP \ --query "properties.configuration.ingress.fqdn" -o tsv) curl https://$APP_URL/health
GitHub Copilot verbinden met de geïmplementeerde server
Nu de MCP-server wordt uitgevoerd in Azure, configureert u VS Code om GitHub Copilot te verbinden met het geïmplementeerde eindpunt.
Maak of werk
.vscode/mcp.jsonhet volgende bij in uw project:{ "servers": { "tasks-mcp-server": { "type": "http", "url": "https://<your-app-fqdn>/mcp" } } }Vervang
<your-app-fqdn>door de FQDN uit de implementatie-uitvoer.Open Copilot Chat in Agent modus in VS Code.
Als de server niet automatisch wordt weergegeven, selecteert u de knop Extra en verifieert u of
tasks-mcp-serverwordt weergegeven. Selecteer indien nodig Start.Test met een prompt zoals 'Al mijn taken vermelden' om te bevestigen dat de geïmplementeerde MCP-server reageert.
Configureer schaling voor interactief gebruik
Azure Container Apps kan standaard worden geschaald naar nul replica's. Voor MCP-servers die interactieve clients zoals Copilot bedienen, leidt koud starten tot merkbare vertragingen. Stel een minimumaantal replica's in om ten minste één exemplaar actief te houden:
az containerapp update \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--min-replicas 1
Beveiligingsoverwegingen
In deze zelfstudie wordt gebruikgemaakt van een niet-geverifieerde MCP-server voor het gemak. Voordat u een MCP-server in productie draait, bekijk de volgende aanbevelingen. Wanneer een agent aangedreven door grote taalmodellen (LLM's) uw MCP-server aanroept, houd rekening met promptinjectie-aanvallen.
- Verificatie en autorisatie: beveilig uw MCP-server met behulp van Microsoft Entra-id. Zie Beveiligde MCP-servers in Container Apps.
- Invoervalidatie: Zod-schema's bieden typeveiligheid, maar voeg bedrijfsregelvalidatie toe voor hulpprogrammaparameters. Overweeg bibliotheken zoals zod-express-middleware voor validatie op aanvraagniveau.
- HTTPS: Azure Container Apps dwingt HTTPS standaard af met automatische TLS-certificaten.
- Minimale bevoegdheid: alleen de hulpprogramma's beschikbaar maken die uw use-case vereist. Vermijd hulpprogramma's die destructieve bewerkingen uitvoeren zonder bevestiging.
- CORS: Toegestane oorsprongen beperken tot vertrouwde domeinen in productie.
- Logboekregistratie en bewaking: MCP-hulpprogramma-aanroepen loggen voor auditing. Gebruik Azure Monitor en Log Analytics.
De hulpbronnen opschonen
Als u niet van plan bent om deze toepassing te blijven gebruiken, verwijdert u de resourcegroep om alle resources te verwijderen die u in deze zelfstudie hebt gemaakt:
az group delete --resource-group $RESOURCE_GROUP --yes --no-wait