Install
$ agentstack add mcp-ovnecron-mcp-azure-container-apps-demo ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
MCP Server on Azure Container Apps with C# and .NET
This sample shows how to build an MCP server from zero with the official C# SDK, run it locally over Streamable HTTP, containerize it, deploy it to Azure Container Apps, and call it from a C# MCP client.
Accompanying blog post: Build and deploy an MCP server with .NET and Azure Container Apps
The server exposes three read-only tools:
echo: returns a caller-provided message.add: adds two integers with checked overflow behavior.server_time: returns server time for a supplied time zone.
Prerequisites
- .NET 10 SDK
- Docker, for local container verification
- Azure CLI, for Azure Container Apps deployment
- An Azure subscription
- Optional: Node.js for the MCP Inspector
Project Layout
McpAzureContainerAppsDemo/
McpAzureContainerAppsDemo.slnx
Directory.Build.props
Directory.Packages.props
Dockerfile
src/
McpAzureContainerAppsDemo.Server/
Program.cs
Configuration/
Security/
Services/
Tools/
McpAzureContainerAppsDemo.Client/
Program.cs
Configuration/
Rendering/
tests/
McpAzureContainerAppsDemo.Server.Tests/
Create the Project from Zero
These are the core commands used to create the project shape:
mkdir McpAzureContainerAppsDemo
cd McpAzureContainerAppsDemo
dotnet new sln -n McpAzureContainerAppsDemo
mkdir -p src tests
dotnet new web -n McpAzureContainerAppsDemo.Server -o src/McpAzureContainerAppsDemo.Server --framework net10.0
dotnet new console -n McpAzureContainerAppsDemo.Client -o src/McpAzureContainerAppsDemo.Client --framework net10.0
dotnet new xunit -n McpAzureContainerAppsDemo.Server.Tests -o tests/McpAzureContainerAppsDemo.Server.Tests --framework net10.0
dotnet sln add \
src/McpAzureContainerAppsDemo.Server/McpAzureContainerAppsDemo.Server.csproj \
src/McpAzureContainerAppsDemo.Client/McpAzureContainerAppsDemo.Client.csproj \
tests/McpAzureContainerAppsDemo.Server.Tests/McpAzureContainerAppsDemo.Server.Tests.csproj
dotnet add src/McpAzureContainerAppsDemo.Server/McpAzureContainerAppsDemo.Server.csproj package ModelContextProtocol.AspNetCore
dotnet add src/McpAzureContainerAppsDemo.Client/McpAzureContainerAppsDemo.Client.csproj package ModelContextProtocol
dotnet add tests/McpAzureContainerAppsDemo.Server.Tests/McpAzureContainerAppsDemo.Server.Tests.csproj reference src/McpAzureContainerAppsDemo.Server/McpAzureContainerAppsDemo.Server.csproj
This repository then adds:
- Central package management in
Directory.Packages.props. - Shared build quality settings in
Directory.Build.props. - Attribute-discovered MCP tools in
Tools/DemoTools.cs. - Testable domain services in
Services/. - Optional API-key protection for
/mcp. - A multi-stage Dockerfile.
Run Locally
Start the MCP server:
dotnet run --project src/McpAzureContainerAppsDemo.Server/McpAzureContainerAppsDemo.Server.csproj --launch-profile http
The server listens on:
http://localhost:8080
Health check:
curl http://localhost:8080/health
Call the MCP server with the included client:
dotnet run --project src/McpAzureContainerAppsDemo.Client/McpAzureContainerAppsDemo.Client.csproj -- \
--url http://localhost:8080/mcp \
--time-zone Europe/Berlin
The client lists the available tools, calls add, and calls server_time.
Add Local API-Key Protection
The server only requires an API key when McpServer__ApiKey is configured.
McpServer__ApiKey=local-dev-key \
dotnet run --project src/McpAzureContainerAppsDemo.Server/McpAzureContainerAppsDemo.Server.csproj --launch-profile http
Then call it with:
dotnet run --project src/McpAzureContainerAppsDemo.Client/McpAzureContainerAppsDemo.Client.csproj -- \
--url http://localhost:8080/mcp \
--api-key local-dev-key
The client sends the key with the X-Api-Key header.
Inspect with MCP Inspector
Start the server, then run:
npx @modelcontextprotocol/inspector
Use the Streamable HTTP transport and connect to:
http://localhost:8080/mcp
If API-key protection is enabled, add:
X-Api-Key: local-dev-key
Test and Build
dotnet restore
dotnet build --no-restore
dotnet test --no-restore
The sample enables nullable reference types and treats warnings as errors for project code.
Build and Run the Container Locally
Build from the repository root of this sample:
docker build -t mcp-aca-demo .
Run without API-key protection:
docker run --rm -p 8080:8080 mcp-aca-demo
Run with API-key protection:
docker run --rm -p 8080:8080 \
-e McpServer__ApiKey=local-dev-key \
mcp-aca-demo
Then call:
dotnet run --project src/McpAzureContainerAppsDemo.Client/McpAzureContainerAppsDemo.Client.csproj -- \
--url http://localhost:8080/mcp \
--api-key local-dev-key
Deploy to Azure Container Apps
Run these commands from the repository root because --source . deploys the current directory and uses the root Dockerfile.
Login and configure variables:
az login
export RESOURCE_GROUP=mcp-aca-demo-rg
export LOCATION=westeurope
export APP_NAME=mcp-aca-demo-$RANDOM
export ENVIRONMENT_NAME=mcp-aca-demo-env
export MCP_API_KEY="$(openssl rand -base64 32)"
If this is the first time your subscription uses these services, register the required resource providers:
az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights
az provider register --namespace Microsoft.ContainerRegistry
Wait for Azure Container Registry registration to finish before deploying:
az provider show \
--namespace Microsoft.ContainerRegistry \
--query registrationState \
--output tsv
Continue when the command prints Registered.
Create the resource group:
az group create \
--name "$RESOURCE_GROUP" \
--location "$LOCATION"
Deploy the container app from local source:
az containerapp up \
--name "$APP_NAME" \
--resource-group "$RESOURCE_GROUP" \
--location "$LOCATION" \
--environment "$ENVIRONMENT_NAME" \
--source . \
--ingress external \
--target-port 8080 \
--env-vars McpServer__ApiKey="$MCP_API_KEY"
Get the public URL:
export MCP_FQDN="$(az containerapp show \
--name "$APP_NAME" \
--resource-group "$RESOURCE_GROUP" \
--query properties.configuration.ingress.fqdn \
--output tsv)"
echo "https://$MCP_FQDN/mcp"
Call the deployed MCP server:
dotnet run --project src/McpAzureContainerAppsDemo.Client/McpAzureContainerAppsDemo.Client.csproj -- \
--url "https://$MCP_FQDN/mcp" \
--api-key "$MCP_API_KEY" \
--time-zone Europe/Berlin
Call with Environment Variables
The client also supports environment variables:
export MCP_SERVER_URL="https://$MCP_FQDN/mcp"
export MCP_API_KEY="$MCP_API_KEY"
export MCP_TIME_ZONE="Europe/Berlin"
dotnet run --project src/McpAzureContainerAppsDemo.Client/McpAzureContainerAppsDemo.Client.csproj
Cleanup
az group delete \
--name "$RESOURCE_GROUP" \
--yes \
--no-wait
Security Notes
- This sample uses Streamable HTTP because Azure Container Apps hosts long-running HTTP services, not stdio child processes.
- The server is configured as stateless, which works well for scale-out and container restarts.
- The API-key middleware protects only
/mcp;/healthremains unauthenticated for platform health checks. - The Azure Container Apps walkthrough sets
McpServer__ApiKeyduring deployment. - For production, prefer Microsoft Entra ID or another managed identity-aware authentication layer over a static API key.
- For production, keep secrets in Azure Container Apps secrets or Key Vault. Do not bake secrets into the image.
- Restrict ingress, CORS, logging, and tool capabilities according to the data your real tools can access.
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ovnecron
- Source: ovnecron/mcp-azure-container-apps-demo
- License: MIT
- Homepage: https://www.lukaswalter.dev/posts/mcp-server-dotnet-aca/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.