Megosztás a következőn keresztül:


App Service-alkalmazás integrálása MCP-kiszolgálóként a GitHub Copilot Chathez (Node.js)

Ebben az oktatóanyagban megtanulhatja, hogyan teheti elérhetővé egy Express.js alkalmazás funkcióit a Model Context Protocol (MCP) használatával, hogyan adhat hozzá eszközt a GitHub Copilothoz, és hogyan használhatja az alkalmazást természetes nyelven a Copilot Csevegőügynök módban.

Képernyőkép az Azure App Service-ben üzemeltetett Todos MCP-kiszolgálót hívó GitHub Copilotról.

Ha a webalkalmazás már rendelkezik olyan hasznos funkciókkal, mint a vásárlás, a szállodai foglalás vagy az adatkezelés, könnyen elérhetővé teheti ezeket a képességeket a következő célokra:

Ha mcp-kiszolgálót ad hozzá a webalkalmazáshoz, lehetővé teszi az ügynök számára az alkalmazás képességeinek megértését és használatát, amikor az válaszol a felhasználói kérésekre. Ez azt jelenti, hogy amit az alkalmazás meg tud tenni, azt az ügynök is meg tudja tenni.

  • Adjon hozzá egy MCP-kiszolgálót a webalkalmazáshoz.
  • Tesztelje az MCP-kiszolgálót helyileg a GitHub Copilot Csevegőügynök módban.
  • Telepítse az MCP-kiszolgálót az Azure App Service-ben, és csatlakozzon hozzá a GitHub Copilot Chatben.

Prerequisites

Ez az oktatóanyag feltételezi, hogy az oktatóanyagban használt mintával dolgozik : Node.js + MongoDB-webalkalmazás üzembe helyezése az Azure-ban.

Legalább nyissa meg a mintaalkalmazást a GitHub Codespacesben, és futtassa azd upaz alkalmazást.

MCP-kiszolgáló hozzáadása a webalkalmazáshoz

  1. A kódtér termináljában adja hozzá a szükséges npm-csomagokat a projekthez:

    npm install @modelcontextprotocol/sdk@latest zod
    
    1. Útvonalak/index.jsmegnyitása. A forgatókönyv egyszerűsége érdekében itt adja hozzá az összes MCP-kiszolgálókódot.
  2. Az útvonalak/index.js tetején adja hozzá a következő szükséges elemeket:

    const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp.js');
    const { StreamableHTTPServerTransport } = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
    const { z } = require('zod');
    
  3. A fájl module.exports = router; alján adja hozzá az alábbi útvonalat az MCP-kiszolgálóhoz.

    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,
          });
        }
      }
    });
    

    Ez az útvonal beállítja az MCP-kiszolgáló végpontját az állapot nélküli mód mintájára <url>/api/mcp az MCP TypeScript SDK-ban.

    • server.registerTool() egy eszközt ad hozzá az MCP-kiszolgálóhoz annak implementálásával.
    • Az SDK a zodot használja a bemeneti ellenőrzéshez.
    • description A Konfigurációs Objektumbandescribe(), valamint inputSchema az eszközök és bemenetek ember által könnyen olvasható leírását biztosítja. Segítenek a hívóügynöknek megérteni az eszközök és paramétereik használatát.

    Ez az útvonal duplikálja a meglévő útvonalak létrehozás-olvasás-frissítés-törlés (CRUD) funkcióját, amely felesleges, de az egyszerűség érdekében megtartja majd. Ajánlott eljárás az alkalmazáslogika egy modulba való áthelyezése, majd a modul meghívása az összes útvonalról.

Az MCP-kiszolgáló helyi tesztelése

  1. A kódtér termináljában futtassa az alkalmazást a következővel npm start: .

  2. Válassza a Megnyitás böngészőben lehetőséget, majd adjon hozzá egy feladatot.

    Hagyja futni npm start . Az MCP-kiszolgáló jelenleg http://localhost:3000/api/mcp fut.

  3. A kódtérben nyissa meg a Copilot-csevegést, majd válassza az Ügynök mód lehetőséget a parancssorban.

  4. Válassza az Eszközök gombot, majd válassza a További eszközök hozzáadása... lehetőséget a legördülő menüben.

    Képernyőkép mcp-kiszolgáló hozzáadásáról a GitHub Copilot Csevegőügynök módban.

  5. Válassza az MCP-kiszolgáló hozzáadása lehetőséget.

  6. Válassza a HTTP (HTTP vagy Server-Sent események) lehetőséget.

  7. A Server URL bevitele mezőbe írja be a http://localhost:3000/api/mcp értéket.

  8. Az Enter Server ID mezőbe írja bea todos-mcp nevet vagy a kívánt nevet.

  9. Válassza a Munkaterület beállításai lehetőséget.

  10. Egy új Copilot-csevegési ablakban írja be a következőt: "Mutasd meg a todos".

  11. Alapértelmezés szerint a GitHub Copilot biztonsági megerősítést jelenít meg egy MCP-kiszolgáló meghívásakor. Válassza a Folytatáslehetőséget.

    Képernyőkép egy MCP-hívás alapértelmezett biztonsági üzenetéről a GitHub Copilot Chatben.

    Ekkor megjelenik egy válasz, amely azt jelzi, hogy az MCP-eszköz hívása sikeres.

    Képernyőkép, amely megmutatja az MCP-eszköz hívásának válaszát a GitHub Copilot csevegőablakában.

Az MCP-kiszolgáló üzembe helyezése az App Service-ben

  1. A kódtér termináljába visszatérve telepítse a módosításokat a módosítások véglegesítésével (GitHub Actions metódus) vagy futtassa azd up (Azure Developer CLI-metódus).

  2. Az AZD-kimenetben keresse meg az alkalmazás URL-címét. Az URL-cím így néz ki az AZD-kimenetben:

     Deploying services (azd deploy)
    
       (✓) Done: Deploying service web
       - Endpoint: <app-url>
     
  3. Miután azd up befejeződött, nyissa meg a .vscode/mcp.json. Módosítsa az URL-címet a következőre: <app-url>/api/mcp.

  4. A módosított MCP-kiszolgáló konfigurációja felett válassza a Start lehetőséget.

    Képernyőkép az MCP-kiszolgáló helyi mcp.json fájlból történő manuális indításáról.

  5. Hozzon létre egy új GitHub Copilot-csevegőablakot. A Copilot-ügynökben meg kell tudnia tekinteni, létrehozni, frissíteni és törölni a feladatokat.

Ajánlott biztonsági eljárások

Ha az MCP-kiszolgálót nagy nyelvi modellekkel (LLM) rendelkező ügynök hívja meg, vegye figyelembe a gyors injektálási támadásokat. Vegye figyelembe az alábbi ajánlott biztonsági eljárásokat:

  • Hitelesítés és engedélyezés: Az MCP-kiszolgáló védelme Microsoft Entra-hitelesítéssel annak biztosítása érdekében, hogy csak a jogosult felhasználók vagy ügynökök férhessenek hozzá az eszközeihez. Részletes útmutatót a Visual Studio Code-ból az Azure App Service-be irányuló Biztonságos modell környezeti protokoll hívásai a Microsoft Entra-hitelesítéssel című témakörben talál.
  • Bemenet-ellenőrzés és -tisztítás: Az oktatóanyagban szereplő példakód a zod értéket használja a bemeneti ellenőrzéshez, biztosítva, hogy a bejövő adatok megfeleljenek a várt sémának. További biztonság érdekében vegye figyelembe a következő szempontokat:
    • Az összes felhasználói bemenet ellenőrzése és megtisztítása feldolgozás előtt, különösen az adatbázis-lekérdezésekben vagy kimenetekben használt mezők esetében.
    • Ha az API-t böngészők használják, a kimenetet elkerülheti a válaszokban, hogy megakadályozza a helyek közötti szkriptelést (XSS).
    • Szigorú sémák és alapértelmezett értékek alkalmazása a modellekben a váratlan adatok elkerülése érdekében.
  • HTTPS: A minta az Azure App Service-ra támaszkodik, amely alapértelmezés szerint kényszeríti a HTTPS-t, és ingyenes TLS-/SSL-tanúsítványokat biztosít az átvitel közbeni adatok titkosításához.
  • Minimális jogosultság elve: Csak a használati esethez szükséges eszközöket és adatokat tegye elérhetővé. Ha szükséges, kerülje a bizalmas műveletek felfedését.
  • Sebességkorlátozás és szabályozás: Az API Management vagy az egyéni köztes szoftver használata a visszaélések és a szolgáltatásmegtagadásos támadások megelőzésére.
  • Naplózás és figyelés: Az MCP-végpontok naplóhozzáférése és használata naplózáshoz és anomáliadetektáláshoz. Gyanús tevékenységek figyelése.
  • CORS-konfiguráció: Ha az MCP-kiszolgáló böngészőkből érhető el, korlátozza a forrásközi kérelmeket megbízható tartományokra. További információ: CORS engedélyezése.
  • Rendszeres frissítések: A függőségek naprakészen tartása az ismert biztonsági rések csökkentése érdekében.

További erőforrások

AI integrálása az Azure App Service-alkalmazásokba