Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu öğreticide Express ve MCP TypeScript SDK'sını kullanarak görev yönetimi araçlarını kullanıma sunan bir Model Bağlam Protokolü (MCP) sunucusu oluşturacaksınız. Sunucuyu Azure Container Apps'e dağıtır ve VS Code'da GitHub Copilot Sohbeti'nden bu sunucuya bağlanırsınız.
Bu eğitimde, siz:
- MCP araçlarını kullanıma sunan bir Express uygulaması oluşturma
- MCP sunucusunu GitHub Copilot ile yerel olarak test etme
- Uygulamayı kapsayıcıya alma ve Azure Container Apps'e dağıtma
- GitHub Copilot'ı dağıtılan MCP sunucusuna bağlama
Önkoşullar
- Aktif bir aboneliğe sahip bir Azure hesabı. Ücretsiz bir tane oluşturun.
- Azure CLI sürüm 2.62.0 veya üzeri.
- Node.js 20 LTS veya üzeri.
- GitHub Copilot uzantısına sahip Visual Studio Code.
- Docker Desktop (isteğe bağlı - yalnızca kapsayıcıyı yerel olarak test etmek için gereklidir).
Uygulama iskelesini oluşturma
Bu bölümde Express ve MCP TypeScript SDK'sı ile yeni bir Node.js projesi oluşturacaksınız.
Proje dizinini oluşturun ve başlatın:
mkdir tasks-mcp-server && cd tasks-mcp-server npm init -yBağımlılıkları yükleyin:
npm install @modelcontextprotocol/sdk express zod npm install -D typescript @types/node @types/express tsxOluştur
tsconfig.json:{ "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "declaration": true }, "include": ["src/**/*"] }Bu yapılandırma, Node.js modül çözümleme ile ES2022'yi hedefler, derlenmiş dosyaları
dist/konumuna çıkartır ve sıkı tür denetimini etkinleştirir.ES modüllerini etkinleştirmek ve derleme ve başlatma betiklerini eklemek için
package.jsongüncelleyin.typevescriptsalanlarını ekleyin veya değiştirin.{ "type": "module", "scripts": { "build": "tsc", "start": "node dist/index.js", "dev": "tsx watch src/index.ts" } }Önemli
"type": "module"ayarlayın. MCP sunucu kodu yalnızca ES modüllerinde desteklenen üst düzeyawaitkullanır.Bellek içi veri deposu için oluşturun
src/taskStore.ts: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();Arabirim,
TaskItemgörev verileri şeklini tanımlar.TaskStoresınıfı, örnek verilerle önceden doldurulmuş bir bellek içi diziyi yönetir ve görevleri listelemek, bulmak, oluşturmak, geçiş yapmak ve silmek için yöntemler sağlar. Modül düzeyinde bir singleton, MCP araçları tarafından kullanılmak üzere dışa aktarılır.
MCP araçlarını tanımlama
Ardından mcp sunucusunu, görev depoyu yapay zeka istemcilerinin kullanıma sunan araç kayıtlarıyla tanımlarsınız.
Oluştur
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`); });Önemli noktalar:
-
McpServerTypeScript SDK'sından MCP sunucusunu araç kayıtlarıyla tanımlar. -
StreamableHTTPServerTransportMCP akışla aktarılabilir HTTP protokollerini işler. AyarsessionIdGenerator: undefined, sunucuyu durum bilgisi olmayan modda çalıştırır. - Araçlar, açıklamalarla giriş parametrelerini tanımlamak için Zod şemalarını kullanır.
- Container Apps sistem durumu yoklamaları için ayrı
/healthbir uç nokta gereklidir.
-
MCP sunucusunu yerel olarak test edin
Azure'a dağıtmadan önce MCP sunucusunun yerel olarak çalıştırıp GitHub Copilot'tan bağlanarak çalıştığını doğrulayın.
Geliştirme sunucusunu başlatın:
npx tsx src/index.tsVS Code'ı açın, Copilot Sohbet'i açın ve Aracı modu'nu seçin.
Araçlar düğmesini ve ardından Daha Fazla Araç Ekle... öğesini seçin.>MCP Sunucusu ekleyin.
HTTP (HTTP veya Server-Sent Olayları) öğesini seçin.
Sunucu URL'sini girin:
http://localhost:3000/mcpUyarı
Yerel geliştirme sunucusu varsayılan olarak 3000 numaralı bağlantı noktasıdır. Kapsayıcıya aldığınızda, Dockerfile ortam değişkenini
PORTContainer Apps hedef bağlantı noktasıyla eşleşecek şekilde 8080 olarak ayarlar.Bir sunucu kimliği girin:
tasks-mcpÇalışma Alanı Ayarları'nı seçin.
Bir istemle test edin: "Tüm görevleri göster"
Copilot araç çağırma onayı istediğinde Devam'ı seçin.
Copilot'un bellek içi deponuzdan görev listesini döndürdiğini görmeniz gerekir.
Tavsiye
"PR'yi gözden geçirmek için bir görev oluştur", "Görev 1'i tamamlanmış olarak işaretle" veya "Görev 2'yi sil" gibi diğer istemleri deneyin.
Uygulamayı kapsayıcılı hale getirme
Uygulamayı Docker kapsayıcısı olarak paketleyerek Azure'a dağıtmadan önce yerel olarak test edebilirsiniz.
DockerfileOluşturFROM 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"]Çok aşamalı derleme ilk aşamada TypeScript'i derler, ardından yalnızca çalışma zamanı bağımlılıkları ve derlenmiş JavaScript çıkışı içeren bir üretim görüntüsü oluşturur. Ortam
PORTdeğişkeni, Container Apps hedef bağlantı noktasıyla eşleşecek şekilde 8080 olarak ayarlanır.Yerel olarak doğrula:
docker build -t tasks-mcp-server . docker run -p 8080:8080 tasks-mcp-serverOnayla:
curl http://localhost:8080/health
Azure Container Apps'a dağıtım
Uygulamayı kapsayıcıya aldıktan sonra Azure CLI kullanarak Azure Container Apps'e dağıtın. komutu az containerapp up kapsayıcı görüntüsünü bulutta oluşturur, bu nedenle bu adım için makinenizde Docker'a ihtiyacınız yoktur.
Ortam değişkenlerini ayarlama:
RESOURCE_GROUP="mcp-tutorial-rg" LOCATION="eastus" ENVIRONMENT_NAME="mcp-env" APP_NAME="tasks-mcp-server-node"Kaynak grubu oluşturma:
az group create --name $RESOURCE_GROUP --location $LOCATIONContainer Apps ortamı oluşturun:
az containerapp env create \ --name $ENVIRONMENT_NAME \ --resource-group $RESOURCE_GROUP \ --location $LOCATIONKapsayıcı uygulamasını dağıtma:
az containerapp up \ --name $APP_NAME \ --resource-group $RESOURCE_GROUP \ --environment $ENVIRONMENT_NAME \ --source . \ --ingress external \ --target-port 8080CORS'yi GitHub Copilot isteklerine izin verecek şekilde yapılandırın:
az containerapp ingress cors enable \ --name $APP_NAME \ --resource-group $RESOURCE_GROUP \ --allowed-origins "*" \ --allowed-methods "GET,POST,DELETE,OPTIONS" \ --allowed-headers "*"Uyarı
Üretim için joker karakter
*kaynaklarını belirli güvenilen kaynaklarla değiştirin. Yönergeler için bkz. Container Apps'te MCP sunucularının güvenliğini sağlama.Dağıtımı doğrulayın:
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'ı dağıtılan sunucuya bağlama
MCP sunucusu Azure'da çalıştığına göre VS Code'u GitHub Copilot'ı dağıtılan uç noktaya bağlamak için yapılandırın.
Projenizde oluşturun veya güncelleştirin
.vscode/mcp.json:{ "servers": { "tasks-mcp-server": { "type": "http", "url": "https://<your-app-fqdn>/mcp" } } }<your-app-fqdn>değerini dağıtım çıktısından FQDN ile değiştirin.VS Code'da Aracı modunda Copilot Sohbet'i açın.
Sunucu otomatik olarak görünmüyorsa Araçlar düğmesini seçin ve listelendiğini doğrulayın
tasks-mcp-server. Gerekirse Başlat'ı seçin.Dağıtılan MCP sunucusunun yanıt verdiğini onaylamak için "Tüm görevlerimi listele" gibi bir istemle test edin.
Etkileşimli kullanım için ölçeklendirmeyi yapılandırma
Azure Container Apps, varsayılan olarak sıfır kopyaya ölçeklendirilebilir. Copilot gibi etkileşimli istemcilere hizmet veren MCP sunucuları için soğuk başlatmalar fark edilebilir gecikmelere neden olur. En az bir örneğin çalışmasını sağlamak için en düşük çoğaltma sayısını ayarlayın:
az containerapp update \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--min-replicas 1
Güvenlik konuları
Bu öğreticide basitlik için kimliği doğrulanmamış bir MCP sunucusu kullanılır. Üretimde bir MCP sunucusu çalıştırmadan önce aşağıdaki önerileri gözden geçirin. Büyük dil modelleri (LLM) tarafından desteklenen bir aracı MCP sunucunuzu aradığında, istem ekleme saldırılarına dikkat edin.
- Kimlik doğrulaması ve yetkilendirme: Microsoft Entra Id kullanarak MCP sunucunuzun güvenliğini sağlayın. Bkz . Container Apps'te MCP sunucularının güvenliğini sağlama.
- Giriş doğrulaması: Zod şemaları tür güvenliği sağlar, ancak araç parametreleri için iş kuralı doğrulaması ekler. İstek düzeyi doğrulama için zod-express-middleware gibi kitaplıkları göz önünde bulundurun.
- HTTPS: Azure Container Apps, otomatik TLS sertifikaları ile varsayılan olarak HTTPS'nin zorunlu kılınmasını sağlar.
- En az ayrıcalık: Yalnızca kullanım örneğinizin gerektirdiği araçları kullanıma sunma. Onay olmadan yıkıcı işlemler gerçekleştiren araçlardan kaçının.
- CORS: İzin verilen çıkış noktalarını üretimdeki güvenilen etki alanlarıyla kısıtlayın.
- Günlük kaydı ve izleme: Denetim amaçlı MCP aracı çağrılarını günlüğe kaydetme. Azure İzleyici ve Log Analytics'i kullanın.
Kaynakları temizle
Bu uygulamayı kullanmaya devam etmek istemiyorsanız, bu öğreticide oluşturduğunuz tüm kaynakları kaldırmak için kaynak grubunu silin:
az group delete --resource-group $RESOURCE_GROUP --yes --no-wait