mcp-functions

mjeewani/mcp-functions

3.2

If you are the rightful owner of mcp-functions and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.

This document provides a comprehensive overview of a Model Context Protocol (MCP) server implemented using Azure Functions, designed to manage code snippets efficiently.

Tools
3
Resources
0
Prompts
0

Snippets MCP Server - Azure Functions<!--


A clean and simple Azure Functions-based MCP (Model Context Protocol) server for managing code snippets.name: Remote MCP with Azure Functions (.NET/C#)

description: Run a remote MCP server on Azure functions.

Featurespage_type: sample

languages:

  • List Snippets: Get all available snippets with metadata- csharp

  • Get Snippet: Retrieve a specific snippet by name- bicep

  • Save Snippet: Store a new snippet or update an existing one- azdeveloper

products:

API Endpoints- azure-functions

  • azure

  • GET /api/snippets - List all snippetsurlFragment: remote-mcp-functions-dotnet

  • GET /api/snippets/{name} - Get a specific snippet---

  • POST /api/snippets/{name} - Save a snippet-->

Storage# Getting Started with Remote MCP Servers using Azure Functions (.NET/C#)

  • Local Development: Uses Azurite storage emulatorThis is a quickstart template to easily build and deploy a custom remote MCP server to the cloud using Azure functions. You can clone/restore/run on your local machine with debugging, and azd up to have it in the cloud in a couple minutes. The MCP server is secured by design using keys and HTTPs, and allows more options for OAuth using EasyAuth and/or API Management as well as network isolation using VNET.

  • Azure Environment: Uses Azure Blob Storage with Managed Identity

Watch the video overview

Quick Start

Local Development

  1. Install Azurite:

    
    npm install -g azurite
    
    ```[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/Azure-Samples/remote-mcp-functions-dotnet)
    
    
    
    
  2. Start Azurite:## Prerequisites

    
    azurite --silent --location c:\azurite --debug c:\azurite\debug.log+ [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)
    
    ```+ [Azure Functions Core Tools](https://learn.microsoft.com/azure/azure-functions/functions-run-local?pivots=programming-language-csharp#install-the-azure-functions-core-tools) >= `4.0.7030`
    
    
  1. Build and Run:+ To use Visual Studio to run and debug locally:

    
    cd src  + Make sure to select the **Azure development** workload during installation.
    
    dotnet build+ To use Visual Studio Code to run and debug locally:
    
    func start  + [Visual Studio Code](https://code.visualstudio.com/)
    
    ```  + [Azure Functions extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions)
    
    
    
    
  2. Test the API:Below is the architecture diagram for the Remote MCP Server using Azure Functions:

    
    # List snippets![Architecture Diagram](architecture-diagram.png)
    
    curl http://localhost:7071/api/snippets
    
    ## Prepare your local environment
    
    # Save a snippet
    
    curl -X POST http://localhost:7071/api/snippets/test -d '{"title":"Test","content":"Hello World"}'An Azure Storage Emulator is needed for this particular sample because we will save and get snippets from blob storage. 
    
    
    
    # Get a snippet1. Start Azurite
    
    curl http://localhost:7071/api/snippets/test
    
    ```    ```shell
    
     docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 \
    

Azure Deployment mcr.microsoft.com/azure-storage/azurite

```
  1. Deploy with Azure Developer CLI:

    ```powershell>Note if you use Azurite coming from VS Code extension you need to run Azurite: Start now or you will see errors.

    azd up

    
    
    
    
  2. Test the deployed API:1. From the src folder, run this command to start the Functions host locally:

    
    curl https://your-function-app.azurewebsites.net/api/snippets    ```shell
    
    ```    cd src
    
     func start
    

Configuration ```

Local Settings (local.settings.json)Note by default this will use the webhooks route: /runtime/webhooks/mcp. Later we will use this in Azure to set the key on client/host calls: /runtime/webhooks/mcp?code=<system_key>


{## Connect to the *local* MCP server from within a client/host

  "IsEncrypted": false,

  "Values": {### VS Code - Copilot Edits

    "AzureWebJobsStorage": "UseDevelopmentStorage=true",

    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"1. **Add MCP Server** from command palette and add URL to your running Function app's MCP endpoint:

  }    ```shell

}    http://localhost:7071/runtime/webhooks/mcp

```    ```

1. **List MCP Servers** from command palette and start the server

### Azure Environment Variables1. In Copilot chat agent mode enter a prompt to trigger the tool, e.g., select some code and enter this prompt

- `AZURE_STORAGE_ACCOUNT_NAME`: Name of the Azure Storage Account

- Managed Identity permissions for Blob Storage access    ```plaintext

    Say Hello 

## Project Structure    ```



```    ```plaintext

src/    Save this snippet as snippet1 

├── Program.cs           # Application entry point    ```

├── SnippetsTool.cs      # Main snippets functionality

├── FunctionsMcpTool.csproj  # Project dependencies    ```plaintext

├── host.json            # Functions host configuration    Retrieve snippet1 and apply to NewFile.cs

└── local.settings.json  # Local development settings    ```

```1. When prompted to run the tool, consent by clicking **Continue**



## Dependencies1. When you're done, press Ctrl+C in the terminal window to stop the `func.exe` host process.



- Microsoft.Azure.Functions.Worker 2.0.0### MCP Inspector

- Azure.Storage.Blobs 12.22.1

- Azure.Identity 1.12.11. In a **new terminal window**, install and run MCP Inspector

- Application Insights for monitoring

    ```shell

## Notes    npx @modelcontextprotocol/inspector node build/index.js

    ```

- All endpoints use `AuthorizationLevel.Anonymous` for easy testing

- Snippets are stored in a `snippets` container in Blob Storage1. CTRL click to load the MCP Inspector web app from the URL displayed by the app (e.g. http://0.0.0.0:5173/#resources)

- Automatic container creation on first use1. Set the transport type to `Streamable HTTP` 

- JSON content type for all snippet data1. Set the URL to your running Function app's MCP endpoint and **Connect**:
    ```shell
    http://0.0.0.0:7071/runtime/webhooks/mcp
    ```
1. **List Tools**.  Click on a tool and **Run Tool**.  

## Verify local blob storage in Azurite

After testing the snippet save functionality locally, you can verify that blobs are being stored correctly in your local Azurite storage emulator.

### Using Azure Storage Explorer

1. Open Azure Storage Explorer
1. In the left panel, expand **Emulator & Attached** → **Storage Accounts** → **(Emulator - Default Ports) (Key)**
1. Navigate to **Blob Containers** → **snippets**
1. You should see any saved snippets as blob files in this container
1. Double-click on any blob to view its contents and verify the snippet data was saved correctly

### Using Azure CLI (Alternative)

If you prefer using the command line, you can also verify blobs using Azure CLI with the storage emulator:

```shell
# List blobs in the snippets container
az storage blob list --container-name snippets --connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
# Download a specific blob to view its contents
az storage blob download --container-name snippets --name <blob-name> --file <local-file-path> --connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"

This verification step ensures your MCP server is correctly interacting with the local storage emulator and that the blob storage functionality is working as expected before deploying to Azure.

Deploy to Azure for Remote MCP

Run this azd command to provision the function app, with any required Azure resources, and deploy your code:

azd up

You can opt-in to a VNet being used in the sample. To do so, do this before azd up

azd env set VNET_ENABLED true

Additionally, can be used for improved security and policies over your MCP Server, and App Service built-in authentication can be used to set up your favorite OAuth provider including Entra.

Connect to your *remote() MCP server function app from a client

Your client will need a key in order to invoke the new hosted MCP endpoint, which will be of the form https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp. The hosted function requires a system key by default which can be obtained from the portal or the CLI (az functionapp keys list --resource-group <resource_group> --name <function_app_name>). Obtain the system key named mcp_extension.

Connect to remote MCP server in MCP Inspector

For MCP Inspector, you can include the key in the URL:

https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp?code=<your-mcp-extension-system-key>

Connect to remote MCP server in VS Code - GitHub Copilot

For GitHub Copilot within VS Code, you should instead set the key as the x-functions-key header in mcp.json, and you would just use https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp for the URL. The following example uses an input and will prompt you to provide the key when you start the server from VS Code. Note has already been included in this repo and will be picked up by VS Code. Click Start on the server to be prompted for values including functionapp-name (in your /.azure/*/.env file) and functions-mcp-extension-system-key which can be obtained from CLI command above or API Keys in the portal for the Function App.

{
    "inputs": [
        {
            "type": "promptString",
            "id": "functions-mcp-extension-system-key",
            "description": "Azure Functions MCP Extension System Key",
            "password": true
        },
        {
            "type": "promptString",
            "id": "functionapp-name",
            "description": "Azure Functions App Name"
        }
    ],
    "servers": {
        "remote-mcp-function": {
            "type": "http",
            "url": "https://${input:functionapp-name}.azurewebsites.net/runtime/webhooks/mcp",
            "headers": {
                "x-functions-key": "${input:functions-mcp-extension-system-key}"
            }
        },
        "local-mcp-function": {
            "type": "http",
            "url": "http://0.0.0.0:7071/runtime/webhooks/mcp"
        }
    }
}

Click Start on the server to be prompted for values including functionapp-name (in your /.azure/*/.env file) and functions-mcp-extension-system-key which can be obtained from CLI command above or API Keys in the portal for the Function App.

Redeploy your code

You can run the azd up command as many times as you need to both provision your Azure resources and deploy code updates to your function app.

[!NOTE] Deployed code files are always overwritten by the latest deployment package.

Clean up resources

When you're done working with your function app and related resources, you can use this command to delete the function app and its related resources from Azure and avoid incurring any further costs:

azd down

Source Code

The function code for the GetSnippet and SaveSnippet endpoints are defined in . The McpToolsTrigger attribute applied to the async Run method exposes the code function as an MCP Server.

This shows the code for a few MCP server examples (get string, get object, save object):

[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, PropertyType, SnippetNamePropertyDescription)] string name,
    [McpToolProperty(SnippetPropertyName, PropertyType, SnippetPropertyDescription)] string snippet)
{
    return snippet;
}

Next Steps