Snabbstart: Skapa en anpassad MCP-fjärrserver med Hjälp av Azure Functions

I den här snabbstarten skapar du en anpassad MCP-server (Remote Model Context Protocol) från ett mallprojekt med hjälp av Azure Developer CLI (azd). MCP-servern använder Azure Functions MCP-servertillägget för att tillhandahålla verktyg för AI-modeller, agenter och assistenter. När du har kört projektet lokalt och verifierat koden med Hjälp av GitHub Copilot distribuerar du det till en ny serverlös funktionsapp i Azure Functions som följer gällande metodtips för säkra och skalbara distributioner.

Tips/Råd

Med Functions kan du också distribuera ett befintligt MCP-serverkodprojekt till en Flex Consumption-planapp utan att behöva göra ändringar i kodprojektet. Mer information finns i Snabbstart: Värd för befintliga MCP-servrar på Azure Functions.

Eftersom den nya appen körs på Flex Consumption-planen, som följer en faktureringsmodell betala för det du använder, medför slutförandet av den här kom igång-guiden en liten kostnad på några cent USD eller mindre i ditt Azure-konto.

Viktigt!

När du skapar anpassade MCP-servrar stöds det för alla Functions-språk, men det här snabbstartsscenariot har för närvarande bara exempel för C#, Python och TypeScript. Slutför den här snabbstarten genom att välja ett av de språk som stöds överst i artikeln.

Den här artikeln stöder version 4 av Node.js programmeringsmodellen för Azure Functions.

Den här artikeln stöder version 2 av Python-programmeringsmodellen för Azure Functions.

Förutsättningar

Initiera projektet

azd init Använd kommandot för att skapa ett lokalt Azure Functions-kodprojekt från en mall.

  1. Öppna en mapp eller arbetsyta i Visual Studio Code där du vill skapa projektet.
  1. Kör följande azd init kommando i terminalen:

    azd init --template remote-mcp-functions-dotnet -e mcpserver-dotnet
    

    Det här kommandot hämtar projektfilerna från malllagringsplatsen och initierar projektet i den aktuella mappen. Flaggan -e anger ett namn för den aktuella miljön. I azdbehåller miljön en unik distributionskontext för din app och du kan definiera mer än en. Den används också i namnet på den resursgrupp som du skapar i Azure.

  1. Kör det här azd init kommandot i den lokala terminalen eller kommandotolken:

    azd init --template remote-mcp-functions-java -e mcpserver-java 
    

    Det här kommandot hämtar projektfilerna från malllagringsplatsen och initierar projektet i den aktuella mappen. Flaggan -e anger ett namn för den aktuella miljön. I azdbehåller miljön en unik distributionskontext för din app och du kan definiera mer än en. Den används också i namnen på de resurser som du skapar i Azure.

  1. Kör det här azd init kommandot i den lokala terminalen eller kommandotolken:

    azd init --template remote-mcp-functions-typescript -e mcpserver-ts
    

    Det här kommandot hämtar projektfilerna från malllagringsplatsen och initierar projektet i den aktuella mappen. Flaggan -e anger ett namn för den aktuella miljön. I azdbehåller miljön en unik distributionskontext för din app och du kan definiera mer än en. Den används också i namnen på de resurser som du skapar i Azure.

  1. Kör det här azd init kommandot i den lokala terminalen eller kommandotolken:

    azd init --template remote-mcp-functions-python -e mcpserver-python
    

    Det här kommandot hämtar projektfilerna från malllagringsplatsen och initierar projektet i den aktuella mappen. Flaggan -e anger ett namn för den aktuella miljön. I azdbehåller miljön en unik distributionskontext för din app och du kan definiera mer än en. Den används också i namnen på de resurser som du skapar i Azure.

Starta lagringsemulatorn

Använd Azurite-emulatorn för att simulera en Azure Storage-kontoanslutning när du kör kodprojektet lokalt.

  1. Om du inte redan har gjort det installerar du Azurite.

  2. Tryck på F1. I kommandopaletten söker du efter och kör kommandot Azurite: Start för att starta den lokala lagringsemulatorn.

Kör MCP-servern lokalt

Visual Studio Code integreras med Azure Functions Core-verktyg så att du kan köra det här projektet på din lokala utvecklingsdator med hjälp av Azurite-emulatorn.

  1. Starta funktionen lokalt genom att trycka på F5 eller ikonen Kör och felsöka i aktivitetsfältet till vänster. Terminalpanelen visar utdata från Core Tools. Appen startar i terminalpanelen och du kan se namnet på de funktioner som körs lokalt.

  2. Anteckna den lokala MCP-serverslutpunkten (till exempel http://localhost:7071/runtime/webhooks/mcp), som du använder för att konfigurera GitHub Copilot i Visual Studio Code.

Verifiera med GitHub Copilot

Om du vill verifiera koden lägger du till det projekt som körs som en MCP-server för GitHub Copilot i Visual Studio Code:

  1. Tryck på F1. I kommandopaletten söker du efter och kör MCP: Lägg till server.

  2. Välj HTTP (Server-Sent händelser) som transporttyp.

  3. Ange URL:en för DEN MCP-slutpunkt som du kopierade i föregående steg.

  4. Använd det genererade server-ID:t och välj Arbetsyta för att spara MCP-serveranslutningen till inställningarna för arbetsytan.

  5. Öppna kommandopaletten och kör MCP: Visa en lista över servrar och kontrollera att servern som du har lagt till visas och körs.

  6. I Copilot-chatten väljer du Agentläge och kör den här uppmaningen:

    Say Hello
    

    När du uppmanas att köra verktyget väljer du Tillåt på den här arbetsytan så att du inte behöver fortsätta bevilja behörighet. Kommandotolken körs och returnerar ett Hello World svar och funktionens körningsinformation skrivs till loggarna.

  7. Välj nu kod i en av dina projektfiler och kör den här uppmaningen:

    Save this snippet as snippet1
    

    Copilot lagrar kodfragmentet och svarar på din begäran med information om hur du hämtar kodfragmentet getSnippets med hjälp av verktyget. Återigen kan du granska funktionskörningen i loggarna och kontrollera att saveSnippets funktionen kördes.

  8. Kör den här uppmaningen i Copilot-chatten:

    Retrieve snippet1 and apply to NewFile
    

    Copilot hämtar kodfragmenten, lägger till det i en fil med namnet NewFile, och gör det som krävs för att kodfragmentet ska fungera i projektet. Functions-loggarna visar att getSnippets slutpunkten anropades.

  9. När du är klar med testningen trycker du på Ctrl+C för att stoppa Functions-värden.

Granska koden (valfritt)

Du kan granska koden som definierar MCP-serververktygen:

Funktionskoden för MCP-serververktygen definieras i src mappen . Attributet McpToolTrigger exponerar funktionerna som MCP Server-verktyg:

[Function(nameof(SayHello))]
public string SayHello(
    [McpToolTrigger(HelloToolName, HelloToolDescription)] ToolInvocationContext context
)
{
    logger.LogInformation("Saying hello");
    return "Hello I am MCP Tool!";
}
    [Function(nameof(GetSnippet))]
    public object GetSnippet(
        [McpToolTrigger(GetSnippetToolName, GetSnippetToolDescription)]
            ToolInvocationContext context,
        [BlobInput(BlobPath)] string snippetContent
    )
    {
        return snippetContent;
    }

    [Function(nameof(SaveSnippet))]
    [BlobOutput(BlobPath)]
    public string SaveSnippet(
        [McpToolTrigger(SaveSnippetToolName, SaveSnippetToolDescription)]
            ToolInvocationContext context,
        [McpToolProperty(SnippetNamePropertyName, SnippetNamePropertyDescription, true)]
            string name,
        [McpToolProperty(SnippetPropertyName, SnippetPropertyDescription, true)]
            string snippet
    )
    {
        return snippet;
    }
}

Du kan visa den fullständiga projektmallen på GitHub-lagringsplatsen för Azure Functions .NET MCP Server .

Funktionskoden för MCP-serververktygen definieras i src/main/java/com/function/ mappen . Anteckningen @McpToolTrigger exponerar funktionerna som MCP Server-verktyg:

            description = "The messages to be logged.",
            isRequired = true,
            isArray = true)
        String messages,
        final ExecutionContext functionExecutionContext
) {
    functionExecutionContext.getLogger().info("Hello, World!");
    functionExecutionContext.getLogger().info("Tool Name: " + mcpToolInvocationContext.getName());
    functionExecutionContext.getLogger().info("Transport Type: " + mcpToolInvocationContext.getTransportType());
    
    // Handle different transport types
    if (mcpToolInvocationContext.isHttpStreamable()) {
        functionExecutionContext.getLogger().info("Session ID: " + mcpToolInvocationContext.getSessionid());
    } else if (mcpToolInvocationContext.isHttpSse()) {
        if (mcpToolInvocationContext.getClientinfo() != null) {
            functionExecutionContext.getLogger().info("Client: " + 
                mcpToolInvocationContext.getClientinfo().get("name").getAsString() + " v" +
    // Write the snippet content to the output blob
    outputBlob.setValue(snippet);
    
    return "Successfully saved snippet '" + snippetName + "' with " + snippet.length() + " characters.";
}

/**
 * Azure Function that handles retrieving a text snippet from Azure Blob Storage.
 * <p>
 * The function is triggered by an MCP Tool Trigger. The snippet name is provided
 * as an MCP tool property, and the snippet content is read from the blob at the 
 * path derived from the snippet name.
 *
 * @param mcpToolInvocationContext The JSON input from the MCP tool trigger.
 * @param snippetName   The name of the snippet to retrieve, provided as an MCP tool property.
 * @param inputBlob     The Azure Blob input binding that fetches the snippet content.
 * @param functionExecutionContext       The execution context for logging.
 */
@FunctionName("GetSnippets")
@StorageAccount("AzureWebJobsStorage")
public String getSnippet(
        @McpToolTrigger(
            name = "getSnippets",
            description = "Gets a text snippet from your snippets collection.")
        String mcpToolInvocationContext,
        @McpToolProperty(
            name = SNIPPET_NAME_PROPERTY_NAME,
            propertyType = "string",
            description = "The name of the snippet.",
            isRequired = true)
        String snippetName,
        @BlobInput(name = "inputBlob", path = BLOB_PATH)
        String inputBlob,
        final ExecutionContext functionExecutionContext
) {
    // Log the entire incoming JSON for debugging
    functionExecutionContext.getLogger().info(mcpToolInvocationContext);

    // Log the snippet name and the fetched snippet content from the blob

Du kan visa den fullständiga projektmallen på Azure Functions Java MCP Server GitHub-lagringsplats.

Funktionskoden för MCP-serververktygen definieras i src/function_app.py filen. MCP-funktionsanteckningar exponerar dessa funktioner som MCP Server-verktyg:

tool_properties_save_snippets_json = json.dumps([prop.to_dict() for prop in tool_properties_save_snippets_object])
tool_properties_get_snippets_json = json.dumps([prop.to_dict() for prop in tool_properties_get_snippets_object])


@app.generic_trigger(
    arg_name="context",
    type="mcpToolTrigger",
    toolName="hello_mcp",
    description="Hello world.",
    toolProperties="[]",
)
def hello_mcp(context) -> None:
    """

@app.generic_trigger(
    arg_name="context",
    type="mcpToolTrigger",
    toolName="save_snippet",
    description="Save a snippet with a name.",
    toolProperties=tool_properties_save_snippets_json,
)
@app.generic_output_binding(arg_name="file", type="blob", connection="AzureWebJobsStorage", path=_BLOB_PATH)
def save_snippet(file: func.Out[str], context) -> str:
    content = json.loads(context)
    snippet_name_from_args = content["arguments"][_SNIPPET_NAME_PROPERTY_NAME]
    snippet_content_from_args = content["arguments"][_SNIPPET_PROPERTY_NAME]

    if not snippet_name_from_args:
        return "No snippet name provided"

    if not snippet_content_from_args:
        return "No snippet content provided"

    file.set(snippet_content_from_args)
    logging.info(f"Saved snippet: {snippet_content_from_args}")
    return f"Snippet '{snippet_content_from_args}' saved successfully"

Du kan visa den fullständiga projektmallen på Azure Functions Python MCP Server GitHub-lagringsplatsen.

Funktionskoden för MCP-serververktygen definieras i src mappen . MCP-funktionsregistreringen exponerar dessa funktioner som MCP Server-verktyg:

export async function mcpToolHello(_toolArguments:unknown, context: InvocationContext): Promise<string> {
    console.log(_toolArguments);
    // Get name from the tool arguments
    const mcptoolargs = context.triggerMetadata.mcptoolargs as {
        name?: string;
    };
    const name = mcptoolargs?.name;

    console.info(`Hello ${name}, I am MCP Tool!`);
    
    return `Hello ${name || 'World'}, I am MCP Tool!`;
}

// Register the hello tool
app.mcpTool('hello', {
    toolName: 'hello',
    description: 'Simple hello world MCP Tool that responses with a hello message.',
    toolProperties:{
        name: arg.string().describe('Required property to identify the caller.').optional()
    },
    handler: mcpToolHello
});
// SaveSnippet function - saves a snippet with a name
export async function saveSnippet(
  _toolArguments: unknown,
  context: InvocationContext
): Promise<string> {
  console.info("Saving snippet");

  // Get snippet name and content from the tool arguments
  const mcptoolargs = context.triggerMetadata.mcptoolargs as {
    snippetname?: string;
    snippet?: string;
  };

  const snippetName = mcptoolargs?.snippetname;
  const snippet = mcptoolargs?.snippet;

  if (!snippetName) {
    return "No snippet name provided";
  }

  if (!snippet) {
    return "No snippet content provided";
  }

  // Save the snippet to blob storage using the output binding
  context.extraOutputs.set(blobOutputBinding, snippet);

  console.info(`Saved snippet: ${snippetName}`);
  return snippet;
}

Du kan visa den fullständiga projektmallen i Azure Functions TypeScript MCP Server GitHub-lagringsplatsen.

När du har verifierat MCP-serververktygen lokalt kan du publicera projektet till Azure.

Distribuera till Azure

Det här projektet är konfigurerat för att använda azd up kommandot för att distribuera projektet till en ny funktionsapp i en Flex Consumption-plan i Azure. Projektet innehåller en uppsättning Bicep-filer som azd använder för att skapa en säker distribution till en Flex-förbrukningsplan som följer bästa praxis.

  1. I Visual Studio Code trycker du på F1 för att öppna kommandopaletten. Sök efter och kör kommandot Azure Developer CLI (azd): Package, Provison and Deploy (up). Logga sedan in med ditt Azure-konto.

  2. Om du inte redan är inloggad autentiserar du med ditt Azure-konto.

  3. Ange följande nödvändiga distributionsparametrar när du uppmanas att göra det:

    Parameter Description
    Azure-prenumeration Prenumeration där dina resurser skapas.
    Azure-plats Azure-region där du kan skapa resursgruppen som innehåller de nya Azure-resurserna. Endast regioner som för närvarande stöder Flex Consumption-planen visas.

    När kommandot har slutförts visas länkar till de resurser som du har skapat.

Ansluta till din fjärranslutna MCP-server

McP-servern körs nu i Azure. När du kommer åt verktygen måste du inkludera en systemnyckel i din begäran. Den här nyckeln ger en viss åtkomstkontroll för klienter som har åtkomst till din fjärranslutna MCP-server. När du har fått den här nyckeln kan du ansluta GitHub Copilot till fjärrservern.

  1. Kör det här skriptet som använder azd och Azure CLI för att skriva ut både MCP-server-URL:en och systemnyckeln (mcp_extension) som krävs för att få åtkomst till verktygen:

    eval $(azd env get-values --output dotenv)
    MCP_EXTENSION_KEY=$(az functionapp keys list --resource-group $AZURE_RESOURCE_GROUP \
        --name $AZURE_FUNCTION_NAME --query "systemKeys.mcp_extension" -o tsv)
    printf "MCP Server URL: %s\n" "https://$SERVICE_API_NAME.azurewebsites.net/runtime/webhooks/mcp"
    printf "MCP Server key: %s\n" "$MCP_EXTENSION_KEY"
    
  2. I Visual Studio Code trycker du på F1 för att öppna kommandopaletten, söker efter och kör kommandot MCP: Open Workspace Folder MCP Configuraton, som öppnar konfigurationsfilen mcp.json .

  3. I konfigurationen mcp.json letar du upp den namngivna MCP-servern som du lade till tidigare, ändrar värdet till din fjärranslutna url MCP-server-URL och lägger till ett headers.x-functions-key element som innehåller din kopierade MCP-serveråtkomstnyckel, som i det här exemplet:

    {
        "servers": {
            "remote-mcp-function": {
                "type": "http",
                "url": "https://contoso.azurewebsites.net/runtime/webhooks/mcp",
                "headers": {
                    "x-functions-key": "A1bC2dE3fH4iJ5kL6mN7oP8qR9sT0u..."
                }
            }
        }
    }
    
  4. Välj startknappen ovanför servernamnet i öppningen mcp.json för att starta om den fjärranslutna MCP-servern, den här gången med hjälp av din distribuerade app.

Verifiera din distribution

Nu kan Du låta GitHub Copilot använda dina fjärranslutna MCP-verktyg precis som du gjorde lokalt, men nu körs koden säkert i Azure. Spela upp samma kommandon som du använde tidigare för att säkerställa att allt fungerar korrekt.

Rensa resurser

När du är klar med mcp-servern och relaterade resurser använder du det här kommandot för att ta bort funktionsappen och dess relaterade resurser från Azure för att undvika ytterligare kostnader:

azd down --no-prompt

Anmärkning

Alternativet --no-prompt instruerar azd dig att ta bort resursgruppen utan bekräftelse från dig. Det här kommandot påverkar inte ditt lokala kodprojekt.

Nästa steg