A remote Model Context Protocol (MCP) server built with Azure Functions and .NET 10 that exposes a weather tool powered by the free Open-Meteo API. No API key is required.
Use this template to quickly build, debug, and deploy your own remote MCP server to Azure. The server is secured by design with HTTPS and function keys, and supports optional network isolation via VNET.
π Based on the Remote MCP Functions collection β This project is one of the language-specific implementations from the Azure-Samples/remote-mcp-functions repository, which provides quickstart templates for building remote MCP servers on Azure Functions across multiple languages (Python, TypeScript, C#, Java). Visit the overview repo for the full catalog and additional resources.
The Model Context Protocol (MCP) enables AI assistants to securely call external tools and access data. While MCP servers are often run locally (via stdio), running them remotely unlocks key advantages:
- Shared access β A single deployed MCP server can serve multiple clients and users.
- Server-side secrets β API keys, database connections, and credentials stay on the server, never exposed to clients.
- Centralized updates β Update tool logic once; all connected clients get the change instantly.
- Enterprise security β Leverage Azure networking (VNET, Private Endpoints), managed identity, and API Management / Entra ID for authentication.
- Scalability β Azure Functions Flex Consumption plan scales to zero and up to 100 instances automatically.
The remote-mcp-functions collection demonstrates how to build these remote servers using two approaches: the MCP Extension for Azure Functions and self-hosted MCP SDK servers. This project uses the MCP Extension approach.
There are two distinct approaches to hosting MCP servers on Azure Functions. Understanding the trade-offs helps you choose the right one for your scenario.
flowchart TB
subgraph ExtApproach["MCP Extension for Azure Functions"]
direction TB
E1["Your code: tool logic only(McpToolTrigger attribute)"]
E2["MCP protocol handling: managed by Functions host"]
E3["Transport: built-in SSE + Streamable HTTP"]
E1 --> E2 --> E3
end
subgraph SDKApproach["Self-hosted MCP SDK"]
direction TB
S1["Your code: tool logic + server setup (MCP SDK)"]
S2["MCP protocol handling: your responsibility"]
S3["Transport: configured in your SDK setup"]
S1 --> S2 --> S3
end
ExtApproach -.- note1["β
This project uses this approach"]
style note1 fill:#d4edda,stroke:#28a745,color:#155724
style ExtApproach fill:#e7f3ff,stroke:#0078d4
style SDKApproach fill:#fff3e0,stroke:#f57c00
| MCP Extension (this project) | MCP SDK (self-hosted) | |
|---|---|---|
| Package | Microsoft.Azure.Functions.Worker.Extensions.Mcp |
ModelContextProtocol (official C# SDK) |
| How you define tools | Declarative β [McpToolTrigger] attribute on a function |
Programmatic β register tools with the MCP SDK server builder |
| Protocol handling | Fully managed by the Azure Functions host | You configure and manage the MCP server lifecycle |
| Transport | Built-in SSE + Streamable HTTP at /runtime/webhooks/mcp |
You set up transport (SSE, stdio, etc.) in code |
| Lines of code | Minimal β just write tool logic | More setup β server init, DI, transport config |
| Flexibility | Convention-based; great for standard tools | Full control over server behavior, middleware, resources |
| Best for | Rapid development, standard tool patterns, teams familiar with Azure Functions | Custom MCP features, complex server logic, non-Functions hosting |
| Example repos | C# Β· Python Β· TypeScript Β· Java | C# Β· Python Β· TypeScript |
This project uses the MCP Extension approach because:
- Minimal boilerplate β A single
[McpToolTrigger]attribute turns any function into an MCP tool. No server setup, transport config, or protocol plumbing needed. - Native Functions experience β Follows the same trigger/binding pattern as HTTP triggers, Timer triggers, etc. If you know Azure Functions, you already know how to build MCP tools.
- Production-ready infrastructure β The extension manages sessions, transport negotiation, and the
/runtime/webhooks/mcpendpoint automatically, so you can focus on tool logic.
- MCP Tool β
GetWeather: Returns current weather conditions (temperature, humidity, wind, condition) for any city name or zip code. - Built with the native Azure Functions MCP extension (
McpToolTrigger). - Uses Open-Meteo geocoding + weather APIs β no API key needed.
- Deployed on the Azure Functions Flex Consumption plan for cost-efficient, serverless scaling.
- Infrastructure as Code with Bicep and one-command deployment via Azure Developer CLI (
azd up). - Pre-configured VS Code MCP client config for local development.
flowchart LR
Client["π₯οΈ MCP Client\n(VS Code, Claude, etc.)"]
Functions["β‘ Azure Functions Host\n(.NET Isolated Worker)"]
Tool["π€οΈ GetWeather Tool\n(McpToolTrigger)"]
API["π Open-Meteo API\n(geocoding + weather)"]
Client -- "MCP (SSE / HTTP)\nJSON-RPC request" --> Functions
Functions -- "JSON-RPC response" --> Client
Functions --> Tool
Tool -- "HTTP GET" --> API
flowchart TB
subgraph Azure["βοΈ Azure Subscription"]
RG["π¦ Resource Group"]
subgraph RG
ASP["π App Service Plan\n(Flex Consumption FC1)"]
FA["β‘ Function App\n(dotnet-isolated v10)"]
MI["π Managed Identity"]
SA["πΎ Storage Account"]
AI["π Application Insights"]
LA["π Log Analytics"]
VNET["π Virtual Network\n(optional)"]
end
end
ASP --> FA
MI --> FA
MI --> SA
MI --> AI
FA --> SA
FA --> AI
AI --> LA
VNET -.-> FA
VNET -.-> SA
| Requirement | Install |
|---|---|
| .NET 10 SDK | Download |
| Azure Functions Core Tools v4 | Install |
Azure Developer CLI (azd) |
Install (v1.23+) |
| Node.js (for Azurite) | Download |
| Azure subscription | Free account |
βββ azure.yaml # Azure Developer CLI configuration
βββ infra/ # Bicep infrastructure-as-code
β βββ main.bicep # Main deployment (subscription scope)
β βββ main.parameters.json # Deployment parameters
β βββ abbreviations.json # Resource naming abbreviations
β βββ app/
β βββ api.bicep # Function App (Flex Consumption)
β βββ rbac.bicep # Managed identity role assignments
β βββ vnet.bicep # Virtual network (optional)
β βββ storage-PrivateEndpoint.bicep
βββ src/
β βββ McpWeatherServer.csproj # .NET project file
β βββ Program.cs # Functions host entry point
β βββ WeatherFunction.cs # MCP tool definition
β βββ WeatherService.cs # Open-Meteo API client
β βββ host.json # Functions host configuration
β βββ local.settings.json # Local dev settings
βββ .vscode/
βββ mcp.json # VS Code MCP client configuration
-
Install Azurite (local storage emulator):
npm install -g azurite
-
Start Azurite in a separate terminal:
azurite --silent
-
Start the Functions host:
cd src func start -
The MCP server is now running at:
Transport URL SSE http://localhost:7071/runtime/webhooks/mcp/sseStreamable HTTP http://localhost:7071/runtime/webhooks/mcp -
Connect from VS Code: The
.vscode/mcp.jsonis pre-configured β open Copilot Chat and ask something like "What's the weather in Seattle?".
-
Log in:
azd auth login
-
Provision and deploy (creates all resources and deploys code):
azd up
You'll be prompted for an environment name and Azure region. Deployment takes ~3β5 minutes.
-
Get the deployed endpoint:
azd env get-values
Look for
AZURE_FUNCTION_NAMEβ your remote MCP endpoint will be:https://<AZURE_FUNCTION_NAME>.azurewebsites.net/runtime/webhooks/mcp -
Retrieve the function key (required for remote access):
az functionapp keys list -n <AZURE_FUNCTION_NAME> -g <RESOURCE_GROUP> --query "systemKeys.mcp_extension" -o tsv
Append it as a query parameter:
?code=<KEY>.
Already configured in .vscode/mcp.json. Just run func start and use Copilot Chat.
Add a new entry to .vscode/mcp.json:
{
"servers": {
"remote-mcp-weather": {
"type": "http",
"url": "https://<FUNCTION_APP>.azurewebsites.net/runtime/webhooks/mcp/sse?code=<MCP_EXTENSION_KEY>"
}
}
}Add to your claude_desktop_config.json:
{
"mcpServers": {
"weather": {
"type": "sse",
"url": "https://<FUNCTION_APP>.azurewebsites.net/runtime/webhooks/mcp/sse?code=<MCP_EXTENSION_KEY>"
}
}
}Returns current weather conditions for a given location.
| Parameter | Type | Description |
|---|---|---|
location |
string |
City name or zip code (e.g., Seattle, 94568, New York) |
Example response:
{
"Location": "Dublin, California, United States",
"Condition": "Clear sky",
"TemperatureC": 16,
"TemperatureF": 62,
"HumidityPercent": 64,
"WindKph": 22,
"Wind": "22 km/h WNW",
"ReportedAtUtc": "2026-03-05 05:15:00Z",
"Source": "open-meteo"
}When deployed with azd up, the following resources are created:
| Resource | Purpose |
|---|---|
| Azure Functions (Flex Consumption FC1) | Hosts the MCP server |
| Storage Account | Function app state and deployment packages |
| Application Insights | Monitoring and logging |
| Log Analytics Workspace | Centralized logs |
| User-Assigned Managed Identity | Secure access to storage and monitoring |
| Virtual Network (optional) | Network isolation with private endpoints |
The Flex Consumption plan charges only for actual execution time. For development and low-traffic scenarios, costs are minimal. See Azure Functions pricing for details.
To remove all Azure resources:
azd downThis project is licensed under the MIT License β see LICENSE.md.