Sdílet prostřednictvím


Rychlý start: Hostování serverů využitím SDK MCP ve službě Azure Functions

V tomto rychlém návodu se dozvíte, jak hostovat na serverech s protokolem Model Context (MCP) v rámci Azure Functions, které vytvoříte pomocí oficiálního MCP SDK. Hostování plánů Flex Consumption umožňuje využívat bezserverové škálování azure Functions, model fakturace s průběžnou platbou za co používáte a integrované funkce zabezpečení. Je ideální pro MCP servery, které používají streamovací přenos HTTP.

Tento článek používá ukázkový projekt serveru MCP vytvořený pomocí oficiálních sad SDK MCP.

Návod

Functions také poskytuje rozšíření MCP, které umožňuje vytvářet servery MCP pomocí programovacího modelu Azure Functions. Další informace najdete v tématu Rychlý start: Vytvoření vlastního vzdáleného serveru MCP pomocí Azure Functions.

Vzhledem k tomu, že nový server běží v plánu Flex Consumption, který se řídí fakturačním modelem platba za skutečné použití, dokončení tohoto úvodního průvodce způsobí malé náklady v řádu několika centů nebo méně na vašem účtu Azure.

Důležité

Zatímco hostování serverů MCP pomocí vlastních obslužných rutin se podporuje pro všechny jazyky, tento scénář rychlého startu v současné době obsahuje pouze příklady pro C#, Python a TypeScript. K dokončení tohoto rychlého startu vyberte jeden z těchto podporovaných jazyků v horní části článku.

Požadavky

Poznámka:

Tato ukázka vyžaduje, abyste měli oprávnění k vytvoření aplikace Microsoft Entra v předplatném Azure, které používáte.

Začínáme s ukázkovým projektem

Nejjednodušší způsob, jak začít, je naklonovat ukázkový projekt serveru MCP vytvořený s oficiálními sadami MCP SDK:

  1. V editoru Visual Studio Code otevřete složku nebo pracovní prostor, ve kterém chcete vytvořit projekt.
  1. V terminálu spusťte tento příkaz pro inicializaci ukázky .NET:

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

    Tento příkaz načte soubory projektu z úložiště šablony a inicializuje projekt v aktuální složce. Příznak -e nastaví název aktuálního prostředí. V azdprostředí udržuje jedinečný kontext nasazení pro vaši aplikaci a můžete definovat více než jeden. Používá se také v názvech prostředků, které vytvoříte v Azure.

  1. V terminálu spusťte tento příkaz pro inicializaci ukázky TypeScriptu:

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

    Tento příkaz načte soubory projektu z úložiště šablony a inicializuje projekt v aktuální složce. Příznak -e nastaví název aktuálního prostředí. V azdprostředí udržuje jedinečný kontext nasazení pro vaši aplikaci a můžete definovat více než jeden. Používá se také v názvech prostředků, které vytvoříte v Azure.

  1. V terminálu spusťte tento příkaz pro inicializaci ukázky Pythonu:

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

    Tento příkaz načte soubory projektu z úložiště šablony a inicializuje projekt v aktuální složce. Příznak -e nastaví název aktuálního prostředí. V azdprostředí udržuje jedinečný kontext nasazení pro vaši aplikaci a můžete definovat více než jeden. Používá se také v názvech prostředků, které vytvoříte v Azure.

Šablona projektu kódu je určená pro server MCP s nástroji, které přistupují k rozhraním API pro veřejné počasí.

Místní spuštění serveru MCP

Visual Studio Code se integruje s nástroji Azure Functions Core Tools , abyste mohli tento projekt spustit na místním vývojovém počítači.

  1. Otevření terminálu v editoru (Ctrl+Shift+` )
  1. V kořenovém adresáři spusťte func start server. Na panelu Terminálu se zobrazí výstup nástrojů Core Tools.
  1. V kořenovém adresáři spusťte npm install ke spuštění instalace závislostí, a poté spusťte npm run build příkaz.
  2. Chcete-li spustit server, spusťte func startpříkaz .
  1. V kořenovém adresáři spusťte uv run func start vytvoření virtuálního prostředí, instalaci závislostí a spuštění serveru.

Testování serveru pomocí GitHub Copilotu

Pokud chcete ověřit server pomocí GitHub Copilotu v editoru Visual Studio Code, postupujte takto:

  1. Otevřete soubor mcp.json v adresáři .vscode.

  2. Spusťte server výběrem tlačítka Start nad local-mcp-server konfigurací.

  3. V okně chatu Copilot se ujistěte, že je vybraný model agenta , vyberte ikonu Konfigurovat nástroje a ověřte, že MCP Server:local-mcp-server je v chatu povolená.

  4. Spusťte tuto výzvu v chatu:

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

    Copilot by měl použít jeden z nástrojů pro počasí, aby pomohl odpovědět na tuto otázku. Po zobrazení výzvy ke spuštění nástroje vyberte Povolit v tomto pracovním prostoru , abyste toto oprávnění nemuseli dál upravovat.

Po místním ověření funkčnosti nástroje můžete server zastavit a nasadit kód projektu do Azure.

Nasazení do Azure

Tento projekt je nakonfigurovaný tak, aby pomocí azd up příkazu nasadil tento projekt do nové aplikace funkcí v plánu Flex Consumption v Azure. Projekt obsahuje sadu souborů Bicep, pomocí kterých azd vytváří zabezpečené nasazení, které dodržuje osvědčené postupy.

  1. Přihlaste se k Azure:

    azd login
    
  2. Nakonfigurujte Visual Studio Code jako předem autorizovanou klientskou aplikaci:

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

    Předem ověřená aplikace se může ověřit a získat přístup k serveru MCP, aniž by vyžadovala další výzvy k vyjádření souhlasu.

  3. V editoru Visual Studio Code stisknutím klávesy F1 otevřete paletu příkazů. Vyhledejte a spusťte příkaz Azure Developer CLI (azd): Package, Provision and Deploy (up). Pak se přihlaste pomocí svého účtu Azure.

  4. Po zobrazení výzvy zadejte tyto požadované parametry nasazení:

    Parameter Description
    Předplatné Azure Předplatné, ve kterém se vaše prostředky vytvářejí.
    Umístění Azure Oblast Azure, ve které se má vytvořit skupina prostředků, která obsahuje nové prostředky Azure. Zobrazí se pouze oblasti, které aktuálně podporují plán Flex Consumption.

    Po úspěšném dokončení příkazu se zobrazí odkazy na prostředky, které jste vytvořili, a koncový bod pro nasazený server MCP. Poznamenejte si název aplikace funkcí, který potřebujete pro další část.

    Návod

    Pokud při spuštění azd up příkazu dojde k chybě, stačí příkaz spustit znovu. Můžete spustit azd up opakovaně, protože přeskočí vytváření všech prostředků, které už existují. Můžete také volat azd up znovu při nasazování aktualizací do služby.

Připojení ke vzdálenému serveru MCP

Váš server MCP je teď spuštěný v Azure. Pokud chcete připojit GitHub Copilot ke vzdálenému serveru, nakonfigurujte ho v nastavení pracovního prostoru.

  1. V souboru mcp.json přepněte na vzdálený server výběrem možnosti Zastavit pro local-mcp-server konfiguraci a Spusťte naremote-mcp-server konfiguraci.

  2. Po zobrazení výzvy k zadání domény aplikace funkcí zadejte název aplikace funkcí, kterou jste si poznamenali v předchozí části. Po zobrazení výzvy k ověření v Microsoftu vyberte Povolit a pak zvolte svůj účet Azure.

  3. Ověřte vzdálený server tak, že položíte otázku, například:

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

    Copilot volá jeden z nástrojů pro počasí, aby odpověděl na dotaz.

Návod

Výstup serveru zobrazíte tak, že vyberete Další...>Zobrazit výstup Výstup poskytuje užitečné informace o možných selháních připojení. Můžete také vybrat ikonu ozubeného kola a změnit úroveň protokolu na Traces, abyste získali další podrobnosti o interakcích mezi klientem (Visual Studio Code) a serverem.

Kontrola kódu (volitelné)

Můžete si projít kód, který definuje server MCP:

Kód serveru MCP je definován v kořenovém adresáři projektu. Server používá oficiální sadu C# MCP SDK k definování těchto nástrojů souvisejících s počasím:

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()}
                """));
    }
}

Kompletní šablonu projektu můžete zobrazit v repozitáři GitHub Azure Functions .NET MCP SDK hosting.

Kód serveru MCP je definován v server.py souboru. Server používá oficiální sadu Python MCP SDK k definování nástrojů souvisejících s počasím. Toto je definice get_forecast nástroje:

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)

Kompletní šablonu projektu můžete zobrazit v úložišti GitHub pro hostovaní Azure Functions Python MCP SDK.

Kód serveru MCP je definován ve src složce. Server používá oficiální sadu Node.js MCP SDK k definování nástrojů souvisejících s počasím. Toto je definice get-forecast nástroje:

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

Kompletní šablonu projektu můžete zobrazit v úložišti GitHub Azure Functions TypeScript MCP SDK hostovaném na.

Vyčistěte zdroje

Po dokončení práce se serverem MCP a souvisejícími prostředky pomocí tohoto příkazu odstraňte aplikaci funkcí a související prostředky z Azure, abyste se vyhnuli dalším nákladům:

azd down