MCP Server with Azure Functions: Part 1

Mustahid AhmedMustahid Ahmed
5 min read

Today, I will talk about how to deploy a recent MCP server using Azure Functions. If you are unfamiliar with MCP servers, please refer to the official documentation of Model Context Protocol.

There are two main steps to deploy an MCP server on Azure Function:

  1. Setting up Azure Function on Azure

  2. Deploying the MCP server code to the configured Azure Function


Setting Up Azure Function on Azure

I won't go into detail with images, but here is a list of setup steps. Please search online (e.g., Google) for how to perform each specific configuration in the Azure Portal.

  1. Select the Plan type as Flex Consumption and set the Instance Memory to 512MB (for example). The Flex Consumption plan is more convenient in Linux environments.

  2. Don't forget to add Azure Storage to your Azure Function. Create an empty container in Blob Storage, as we will later deploy the zipped Azure Function code there.

  3. If possible, also add an Application Insights resource. This can be done easily via the Azure portal.

  4. Confirm that the following environment variables have been added under Configuration > Environment Variables:

    Environment Variables Image

  5. Give your Azure Function an appropriate name.

  6. After completing the settings, check the Overview page. You should see the domain name <your-function-name>.azurewebsites.net and confirm the operating system is Linux.

  7. Regarding networking, you could restrict public access, but we'll skip this for now.


Deploying the MCP Server Code to the Configured Azure Function

Let’s first look at the basic directory structure of an Azure Function project:

<project-root>/  
│  
├── .venv/                     # Python virtual environment (optional but recommended)  
│  
├── .gitignore                 # Git ignore file  
├── host.json                  # Configuration file for Azure Functions host  
├── local.settings.json        # Local app settings or secrets (not deployed)  
├── requirements.txt           # Python dependencies  
├── function_app.py            # V2 programming model: defines routes and triggers  
├── .funcignore                # Files not to upload to Azure  
│   
└── README.md                  # Optional documentation

The five most important files are:

  1. requirements.txt

  2. host.json

  3. local.settings.json

  4. function_app.py

  5. .funcignore

host.json

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle.Experimental",
    "version": "[4.*, 5.0.0)"
  }
}

For debug logging:

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    },
    "logLevel": {
          "default": "Debug"
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle.Experimental",
    "version": "[4.*, 5.0.0)"
  }
}

Official Azure reference for host.json: link

local.settings.json

{
    "IsEncrypted": false,
    "Values": {
      "FUNCTIONS_WORKER_RUNTIME": "python",
      "AzureWebJobsStorage": "UseDevelopmentStorage=true"
    }
}

More details: link


Deploying the MCP Server Code Locally

Start the Virtual Storage

Since Azure Function needs Azure Storage, we need to start a virtual storage locally.

We’ll use Podman for this. For installation instructions, see this article.

  1. Start Podman machine:
podman machine start
  1. Pull and run Azurite image:
podman run -d --name azurite \
-p 10000:10000 \
-p 10001:10001 \
-p 10002:10002 \
mcr.microsoft.com/azure-storage/azurite
  1. Verify the running container:
podman ps -a

You should see the azurite container running.


Set Up Python Environment

We’ll use the uv tool for virtual environments. Install it from here, then run the following commands inside your project directory:

uv init
uv venv
source .venv/bin/activate
uv add azure-functions

Install MCP Inspector

Follow this guide to install Node.js and npm.

Install npx globally:

npm install -g npx

Start the MCP Inspector:

npx @modelcontextprotocol/inspector

You should see output like this in the terminal:

Starting MCP inspector...
⚙️ Proxy server listening on port 6277
🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀

Add the hello_mcp Tool

Add the following function to function_app.py:

# Import Azure Functions SDK
import azure.functions as func

# Initialize the function app with FUNCTION-level authentication
app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)


# Define a generic trigger with a custom type "mcpToolTrigger"
@app.generic_trigger(
    arg_name="context",          # Argument name containing trigger info
    type="mcpToolTrigger",       # Trigger type name
    toolName="hello_mcp",        # Tool name to call
    description="Hello world.",  # Tool description
    toolProperties="[]"          # No parameters required
)
def hello_mcp(context) -> str:
    """
    A simple function that returns a greeting message.

    Args:
        context: Trigger context (not used here)

    Returns:
        str: A greeting string
    """
    return "Hello I am MCPTool!"

Run Azure Function Locally

Make sure the azurite container is running.

In your project directory:

source .venv/bin/activate
func start

You should see output similar to this:

Found Python version 3.12.8 (python3).

Azure Functions Core Tools
Core Tools Version:       4.0.7030 Commit hash: N/A +bb4c949899cd5659d6bfe8b92cc923453a2e8f88 (64-bit)
Function Runtime Version: 4.1037.0.23568

[2025-05-23T09:58:29.911Z] MCP server SSE endpoint: http://localhost:7071/runtime/webhooks/mcp/sse
[2025-05-23T09:58:29.956Z] Worker process started and initialized.

Functions:

    hello_mcp: mcpToolTrigger

This means your MCP server is running at http://localhost:7071/runtime/webhooks/mcp/sse.


Check with MCP Inspector

  1. Access the URL shown above (http://127.0.0.1:6274) and enter http://localhost:7071/runtime/webhooks/mcp/sse in the input field, then click Connect.

  2. Click List Tools, and you should see hello_mcp.

  3. Click hello_mcp, then click Run Tool — you should see something like this:

    Screenshot of running hello_mcp

Now you've confirmed that the Azure Function MCP server is running locally.


Deploy to Azure Function (Cloud)

Install the Azure CLI using these instructions.

Create a zip file of your deployment files:

zip -r testFunc.zip .  -x "./.venv/*" -x "*.git*" -x ./.vscode -x .env -x "*__pycache__/*" -x "*/__pycache__/*"

Log in to Azure CLI:

az login

Upload the zip file:

az functionapp deployment source config-zip --src testFunc.zip --name your-function --resource-group your-group --build-remote true

Check if the deployment was successful by navigating to the Functions section in the Overview page of your function app in the Azure Portal.


Test the Cloud MCP Server

From the Azure Portal sidebar, go to Functions > App keys and retrieve the key labeled mcp_extension.

MCP Extension Key

Your function's domain is <your-function-name>.azurewebsites.net, so the full MCP server URL becomes:

https://<your-function-name>.azurewebsites.net/runtime/webhooks/mcp/sse?code=<mcp_extension_key>

Enter this URL into the MCP Inspector and you should be able to use the hello_mcp tool just as before.


Conclusion

In this article, we’ve created a simple MCP tool. In the next blog post, we'll introduce more advanced tools. Stay tuned!

0
Subscribe to my newsletter

Read articles from Mustahid Ahmed directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mustahid Ahmed
Mustahid Ahmed