Condividi tramite


Guida introduttiva: Ospitare server creati con gli SDK MCP su Azure Functions

In questo avvio rapido, si apprenderà come distribuire server MCP (Model Context Protocol) sulle Funzioni di Azure, creati utilizzando gli SDK ufficiali MCP. L'hosting del piano di consumo flessibile consente di sfruttare la scalabilità serverless di Azure Functions, il modello di fatturazione pay-per-use e le funzionalità di sicurezza predefinite. È ideale per i server MCP che usano il trasporto http con flusso.

Questo articolo usa un progetto server MCP di esempio compilato usando gli SDK MCP ufficiali.

Suggerimento

Funzioni fornisce anche un'estensione MCP che consente di creare server MCP usando il modello di programmazione di Funzioni di Azure. Per altre informazioni, vedere Avvio rapido: Creare un server MCP remoto personalizzato usando Funzioni di Azure.

Poiché il nuovo server viene eseguito in un piano a consumo flessibile, che segue un modello di fatturazione con pagamento in base al consumo, il completamento di questa guida introduttiva comporta un costo ridotto di pochi centesimi o inferiore nell'account Azure.

Importante

Sebbene l'hosting dei server MCP che utilizzano gestori personalizzati sia supportato in tutti i linguaggi, questo scenario di avvio rapido attualmente include esempi solo per C#, Python e TypeScript. Per completare questa guida introduttiva, selezionare una di queste lingue supportate nella parte superiore dell'articolo.

Prerequisiti

  • Python 3.11 o versione successiva
  • uv per la gestione dei pacchetti Python

Annotazioni

Questo esempio richiede l'autorizzazione necessaria per creare un'app Microsoft Entra nella sottoscrizione di Azure usata.

Introduzione a un progetto di esempio

Il modo più semplice per iniziare consiste nel clonare un progetto di esempio server MCP compilato con gli SDK MCP ufficiali:

  1. In Visual Studio Code aprire una cartella o un'area di lavoro in cui si vuole creare il progetto.
  1. Nel terminale eseguire questo comando per inizializzare l'esempio .NET:

    azd init --template mcp-sdk-functions-hosting-dotnet -e mcpsdkserver-dotnet
    

    Questo comando esegue il pull dei file di progetto dal repository dei modelli e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Viene usato anche nei nomi delle risorse create in Azure.

  1. Nel terminale eseguire questo comando per inizializzare l'esempio TypeScript:

    azd init --template mcp-sdk-functions-hosting-node  -e mcpsdkserver-node
    

    Questo comando esegue il pull dei file di progetto dal repository dei modelli e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Viene usato anche nei nomi delle risorse create in Azure.

  1. Nel terminale eseguire questo comando per inizializzare l'esempio Python:

    azd init --template mcp-sdk-functions-hosting-python -e mcpsdkserver-python
    

    Questo comando esegue il pull dei file di progetto dal repository dei modelli e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Viene usato anche nei nomi delle risorse create in Azure.

Il modello di progetto di codice è destinato a un server MCP con strumenti che accedono alle API meteo pubbliche.

Eseguire il server MCP in locale

Visual Studio Code si integra con Azure Functions Core Tools per consentire l'esecuzione di questo progetto nel computer di sviluppo locale.

  1. Aprire Terminale nell'editor (Ctrl+Shift+` )
  1. Nella directory radice eseguire func start per avviare il server. Il pannello Terminale visualizza l'output di Core Tools.
  1. Nella directory radice eseguire npm install per installare le dipendenze, quindi eseguire npm run build.
  2. Per avviare il server, eseguire func start.
  1. Nella directory radice eseguire uv run func start per creare un ambiente virtuale, installare le dipendenze e avviare il server.

Testare il server con GitHub Copilot

Per verificare il server usando GitHub Copilot in Visual Studio Code, seguire questa procedura:

  1. Aprire il file mcp.json nella directory .vscode.

  2. Avviare il server selezionando il pulsante Start sopra la local-mcp-server configurazione.

  3. Nella finestra Chat di Copilot verificare che il modello agente sia selezionato, selezionare l'icona Configura strumenti e verificare che MCP Server:local-mcp-server sia abilitato nella chat.

  4. Eseguire questo comando nella chat.

    Return the weather forecast for New York City using #local-mcp-server
    

    Copilot dovrebbe chiamare uno degli strumenti meteo per rispondere a questa domanda. Quando viene richiesto di eseguire lo strumento, selezionare Consenti in questa area di lavoro in modo da non dover mantenere questa autorizzazione.

Dopo aver verificato la funzionalità dello strumento in locale, è possibile arrestare il server e distribuire il codice del progetto in Azure.

Distribuzione su Azure

Questo progetto è configurato per l'uso del comando azd up al fine di distribuire questo progetto in una nuova app per le funzioni in un piano a consumo Flex in Azure. Il progetto include un set di file Bicep che azd usano per creare una distribuzione sicura che segue le procedure consigliate.

  1. Accedere ad Azure:

    azd login
    
  2. Configurare Visual Studio Code come applicazione client pre-autorizzata:

    azd env set PRE_AUTHORIZED_CLIENT_IDS aebc6443-996d-45c2-90f0-388ff96faa56
    

    Un'applicazione pre-autorizzata può eseguire l'autenticazione e accedere al server MCP senza richiedere ulteriori richieste di consenso.

  3. In Visual Studio Code premere F1 per aprire il riquadro comandi. Cercare ed eseguire il comando Azure Developer CLI (azd): Package, Provision and Deploy (up). Accedere quindi usando l'account Azure.

  4. Quando richiesto, specificare questi parametri di distribuzione obbligatori:

    Parametro Description
    Sottoscrizione di Azure Sottoscrizione in cui vengono create le risorse.
    Località di Azure Area di Azure in cui creare il gruppo di risorse che contiene le nuove risorse di Azure. Vengono visualizzate solo le aree che attualmente supportano il piano a consumo Flex.

    Al termine del comando, vengono visualizzati i collegamenti alle risorse create e all'endpoint per il server MCP distribuito. Prendere nota del nome dell'app per le funzioni, necessario per la sezione successiva.

    Suggerimento

    Se si verifica un errore durante l'esecuzione del azd up comando, eseguire di nuovo il comando. È possibile eseguire azd up ripetutamente perché ignora la creazione di tutte le risorse già esistenti. È anche possibile chiamare azd up di nuovo quando si distribuiscono gli aggiornamenti al servizio.

Connettersi al server MCP remoto

Il server MCP è ora in esecuzione in Azure. Per connettere GitHub Copilot al server remoto, configurarlo nelle impostazioni dell'area di lavoro.

  1. Nel file mcp.json, passa al server remoto selezionando Arresta per la local-mcp-server configurazione e Avvia per la configurazione remote-mcp-server.

  2. Quando viene richiesto Il dominio dell'app per le funzioni, immettere il nome dell'app per le funzioni annotata nella sezione precedente. Quando viene richiesto di eseguire l'autenticazione a Microsoft, selezionare Consenti e quindi scegliere l'account Azure.

  3. Verificare il server remoto ponendo una domanda simile alla seguente:

    Return the weather forecast for Seattle using #remote-mcp-server.
    

    Copilot chiama uno degli strumenti meteo per rispondere alla domanda.

Suggerimento

È possibile visualizzare l'output di un server selezionando Altro...>Mostra output. L'output fornisce informazioni utili sui possibili errori di connessione. È anche possibile selezionare l'icona a forma di ingranaggio per modificare i livelli di log in Tracce per ottenere altri dettagli sulle interazioni tra il client (Visual Studio Code) e il server.

Esaminare il codice (facoltativo)

È possibile esaminare il codice che definisce il server MCP:

Il codice del server MCP è definito nella radice del progetto. Il server usa l'SDK MCP C# ufficiale per definire questi strumenti correlati al meteo:

using ModelContextProtocol;
using ModelContextProtocol.Server;
using System.ComponentModel;
using System.Globalization;
using System.Text.Json;

namespace QuickstartWeatherServer.Tools;

[McpServerToolType]
public sealed class WeatherTools
{
    [McpServerTool, Description("Get weather alerts for a US state.")]
    public static async Task<string> GetAlerts(
        HttpClient client,
        [Description("The US state to get alerts for. Use the 2 letter abbreviation for the state (e.g. NY).")] string state)
    {
        using var jsonDocument = await client.ReadJsonDocumentAsync($"/alerts/active/area/{state}");
        var jsonElement = jsonDocument.RootElement;
        var alerts = jsonElement.GetProperty("features").EnumerateArray();

        if (!alerts.Any())
        {
            return "No active alerts for this state.";
        }

        return string.Join("\n--\n", alerts.Select(alert =>
        {
            JsonElement properties = alert.GetProperty("properties");
            return $"""
                    Event: {properties.GetProperty("event").GetString()}
                    Area: {properties.GetProperty("areaDesc").GetString()}
                    Severity: {properties.GetProperty("severity").GetString()}
                    Description: {properties.GetProperty("description").GetString()}
                    Instruction: {properties.GetProperty("instruction").GetString()}
                    """;
        }));
    }

    [McpServerTool, Description("Get weather forecast for a location.")]
    public static async Task<string> GetForecast(
        HttpClient client,
        [Description("Latitude of the location.")] double latitude,
        [Description("Longitude of the location.")] double longitude)
    {
        var pointUrl = string.Create(CultureInfo.InvariantCulture, $"/points/{latitude},{longitude}");
        using var jsonDocument = await client.ReadJsonDocumentAsync(pointUrl);
        var forecastUrl = jsonDocument.RootElement.GetProperty("properties").GetProperty("forecast").GetString()
            ?? throw new Exception($"No forecast URL provided by {client.BaseAddress}points/{latitude},{longitude}");

        using var forecastDocument = await client.ReadJsonDocumentAsync(forecastUrl);
        var periods = forecastDocument.RootElement.GetProperty("properties").GetProperty("periods").EnumerateArray();

        return string.Join("\n---\n", periods.Select(period => $"""
                {period.GetProperty("name").GetString()}
                Temperature: {period.GetProperty("temperature").GetInt32()}°F
                Wind: {period.GetProperty("windSpeed").GetString()} {period.GetProperty("windDirection").GetString()}
                Forecast: {period.GetProperty("detailedForecast").GetString()}
                """));
    }
}

È possibile visualizzare il modello completo del progetto nel repository GitHub di hosting di Azure Functions .NET MCP SDK.

Il codice del server.py server MCP è definito nel file . Il server usa python MCP SDK ufficiale per definire gli strumenti correlati al meteo. Questa è la definizione dello get_forecast strumento:

import os
import sys
import warnings
import logging
from typing import Any
from pathlib import Path

import httpx
from azure.identity import OnBehalfOfCredential, ManagedIdentityCredential
from mcp.server.fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_request
from starlette.requests import Request
from starlette.responses import HTMLResponse

# Initialize FastMCP server
mcp = FastMCP("weather", stateless_http=True)

# Constants
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location.

    Args:
        latitude: Latitude of the location
        longitude: Longitude of the location
    """
    # First get the forecast grid endpoint
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "Unable to fetch forecast data for this location."

    # Get the forecast URL from the points response
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "Unable to fetch detailed forecast."

    # Format the periods into a readable forecast
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[:5]:  # Only show next 5 periods
        forecast = f"""
{period['name']}:
Temperature: {period['temperature']}°{period['temperatureUnit']}
Wind: {period['windSpeed']} {period['windDirection']}
Forecast: {period['detailedForecast']}
"""
        forecasts.append(forecast)

    return "\n---\n".join(forecasts)

È possibile visualizzare il modello di progetto completo nel repository GitHub per l'hosting del Python MCP SDK per Azure Functions.

Il codice del server MCP è definito nella src cartella . Il server usa il Node.js MCP SDK ufficiale per definire gli strumenti correlati al meteo. Questa è la definizione dello get-forecast strumento:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { ManagedIdentityCredential, OnBehalfOfCredential } from '@azure/identity';

const NWS_API_BASE = "https://api.weather.gov";
const USER_AGENT = "weather-app/1.0";

// Function to create a new server instance for each request (stateless)
export const createServer = () => {
  const server = new McpServer({
    name: "weather",
    version: "1.0.0",
  });
  server.registerTool(
    "get-forecast",
    {
      title: "Get Weather Forecast",
      description: "Get weather forecast for a location",
      inputSchema: {
        latitude: z.number().min(-90).max(90).describe("Latitude of the location"),
        longitude: z
          .number()
          .min(-180)
          .max(180)
          .describe("Longitude of the location"),
      },
      outputSchema: z.object({
        forecast: z.string(),
      }),
    },
    async ({ latitude, longitude }) => {
      // Get grid point data
      const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
      const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);

      if (!pointsData) {
        const output = { forecast: `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).` };
        return {
          content: [{ type: "text", text: JSON.stringify(output) }],
          structuredContent: output,
        };
      }

      const forecastUrl = pointsData.properties?.forecast;
      if (!forecastUrl) {
        const output = { forecast: "Failed to get forecast URL from grid point data" };
        return {
          content: [{ type: "text", text: JSON.stringify(output) }],
          structuredContent: output,
        };
      }

      // Get forecast data
      const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl);
      if (!forecastData) {
        const output = { forecast: "Failed to retrieve forecast data" };
        return {
          content: [{ type: "text", text: JSON.stringify(output) }],
          structuredContent: output,
        };
      }

      const periods = forecastData.properties?.periods || [];
      if (periods.length === 0) {
        const output = { forecast: "No forecast periods available" };
        return {
          content: [{ type: "text", text: JSON.stringify(output) }],
          structuredContent: output,
        };
      }

      // Format forecast periods
      const formattedForecast = periods.map((period: ForecastPeriod) =>
        [
          `${period.name || "Unknown"}:`,
          `Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`,
          `Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`,
          `${period.shortForecast || "No forecast available"}`,
          "---",
        ].join("\n"),
      );

      const forecastText = `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`;
      const output = { forecast: forecastText };

      return {
        content: [{ type: "text", text: forecastText }],
        structuredContent: output,
      };
    },
  );
  return server;
}

È possibile visualizzare il modello di progetto completo nel repository GitHub per l'hosting di Azure Functions TypeScript MCP SDK.

Pulire le risorse

Al termine dell'uso del server MCP e delle risorse correlate, usare questo comando per eliminare l'app per le funzioni e le relative risorse da Azure per evitare di incorrere in ulteriori costi:

azd down