KodachiQube/AzureFunctionMCPTemplate
If you are the rightful owner of AzureFunctionMCPTemplate and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
This document provides a comprehensive overview of a Model Context Protocol (MCP) server template designed for Azure Functions in .NET 8, highlighting its features, tools, resources, and usage across different platforms.
get_customer
Get customer information by ID
create_customer
Create a new customer
Azure Function MCP Server Template
A standardized template for building Azure Functions with MCP (Model Context Protocol) server capabilities in .NET 8.
Features
- Azure OpenAI integration: Built-in adapters for GPT-4 and GPT-3.5 models
- Dual-mode operation: Run as Azure Function or standalone MCP server
- Clean architecture: Separated Core, Services, Functions, and Tests projects
- MCP Protocol implementation: Complete JSON-RPC based MCP server
- HTTP resilience: Built-in retry and circuit breaker policies
- Comprehensive testing: Unit and integration test infrastructure
- Configuration management: Environment-based configuration with Options pattern
- Logging: Structured logging with console and Application Insights support
Project Structure
AzureFunctionMCPTemplate/
āāā src/
ā āāā Template.Core/ # Domain models and interfaces
ā āāā Template.Functions/ # Azure Functions and MCP server
ā āāā Template.Services/ # Business logic and external clients
ā āāā Template.Tests/ # Unit and integration tests
āāā scripts/
ā āāā run-mcp-server.sh # Run as MCP server
ā āāā run-azure-function.sh # Run as Azure Function
ā āāā test-mcp-server.sh # Test MCP protocol
āāā docs/ # Additional documentation
āāā Template.sln # Solution file
Prerequisites
š Converting Template to Your MCP Application
Follow these steps to transform this template into your own MCP application:
Step 1: Clone and Rename
# Clone the template
cp -r ~/DevProjects/AzureFunctionMCPTemplate ~/DevProjects/YourAppMCP
# Navigate to your new project
cd ~/DevProjects/YourAppMCP
# Rename solution file
mv Template.sln YourApp.sln
Step 2: Update Project Names
- Rename project directories and files:
# Rename directories
mv src/Template.Core src/YourApp.Core
mv src/Template.Functions src/YourApp.Functions
mv src/Template.Services src/YourApp.Services
mv src/Template.Tests src/YourApp.Tests
# Rename project files
mv src/YourApp.Core/Template.Core.csproj src/YourApp.Core/YourApp.Core.csproj
mv src/YourApp.Functions/Template.Functions.csproj src/YourApp.Functions/YourApp.Functions.csproj
mv src/YourApp.Services/Template.Services.csproj src/YourApp.Services/YourApp.Services.csproj
mv src/YourApp.Tests/Template.Tests.csproj src/YourApp.Tests/YourApp.Tests.csproj
- Update namespaces in all C# files:
# On macOS/Linux
find . -name "*.cs" -type f -exec sed -i '' 's/Template\.Core/YourApp.Core/g' {} +
find . -name "*.cs" -type f -exec sed -i '' 's/Template\.Functions/YourApp.Functions/g' {} +
find . -name "*.cs" -type f -exec sed -i '' 's/Template\.Services/YourApp.Services/g' {} +
find . -name "*.cs" -type f -exec sed -i '' 's/Template\.Tests/YourApp.Tests/g' {} +
# Update project references
find . -name "*.csproj" -type f -exec sed -i '' 's/Template\./YourApp./g' {} +
- Update solution file:
sed -i '' 's/Template/YourApp/g' YourApp.sln
Step 3: Define Your Domain
- Create your domain models in
src/YourApp.Core/Models/
:
// src/YourApp.Core/Models/YourDomainModels.cs
namespace YourApp.Core.Models;
public class Customer
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
// Add your properties
}
- Define your service interfaces in
src/YourApp.Core/Interfaces/
:
// src/YourApp.Core/Interfaces/ICustomerService.cs
namespace YourApp.Core.Interfaces;
public interface ICustomerService
{
Task<Customer> GetCustomerAsync(string id);
Task<string> CreateCustomerAsync(Customer customer);
Task<bool> UpdateCustomerAsync(string id, Customer customer);
Task<bool> DeleteCustomerAsync(string id);
}
Step 4: Implement Your MCP Tools
- Update the MCP server in
src/YourApp.Functions/MCP/McpServer.cs
:
private readonly List<Tool> _tools = new()
{
new Tool
{
Name = "get_customer",
Description = "Get customer information by ID",
InputSchema = new
{
type = "object",
properties = new
{
customerId = new { type = "string", description = "The customer ID" }
},
required = new[] { "customerId" }
}
},
new Tool
{
Name = "create_customer",
Description = "Create a new customer",
InputSchema = new
{
type = "object",
properties = new
{
name = new { type = "string", description = "Customer name" },
email = new { type = "string", description = "Customer email" }
},
required = new[] { "name", "email" }
}
}
// Add more tools as needed
};
- Implement tool handlers:
[JsonRpcMethod("tools/call")]
public async Task<object> CallToolAsync(ToolCallParams toolParams)
{
var result = toolParams.Name switch
{
"get_customer" => await HandleGetCustomerAsync(toolParams.Arguments),
"create_customer" => await HandleCreateCustomerAsync(toolParams.Arguments),
// Add more tool handlers
_ => throw new Exception($"Unknown tool: {toolParams.Name}")
};
// Return result...
}
private async Task<object> HandleGetCustomerAsync(Dictionary<string, object>? arguments)
{
var customerId = arguments?["customerId"]?.ToString();
var customer = await _customerService.GetCustomerAsync(customerId);
return new { success = true, customer };
}
Step 5: Implement Your Services
- Create service implementations in
src/YourApp.Services/Services/
:
// src/YourApp.Services/Services/CustomerService.cs
using YourApp.Core.Interfaces;
using YourApp.Core.Models;
namespace YourApp.Services.Services;
public class CustomerService : ICustomerService
{
private readonly ILogger<CustomerService> _logger;
private readonly IApiClient _apiClient;
public CustomerService(ILogger<CustomerService> logger, IApiClient apiClient)
{
_logger = logger;
_apiClient = apiClient;
}
public async Task<Customer> GetCustomerAsync(string id)
{
// Implement your business logic
return await _apiClient.GetAsync<Customer>($"/customers/{id}");
}
// Implement other methods...
}
Step 6: Configure Your Application
- Update configuration in
src/YourApp.Functions/Configuration/AppConfiguration.cs
:
public class YourAppConfiguration
{
public string ApiUrl { get; set; } = "https://your-api.com";
public string ApiKey { get; set; } = string.Empty;
public string DatabaseConnection { get; set; } = string.Empty;
// Add your configuration properties
}
- Update local settings in
src/YourApp.Functions/local.settings.json
:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
"YourApp__ApiUrl": "https://your-api.com",
"YourApp__ApiKey": "your-api-key",
"YourApp__DatabaseConnection": "your-connection-string"
}
}
Step 7: Register Dependencies
Update Program.cs
to register your services:
private static void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
// Register your configuration
services.Configure<YourAppConfiguration>(context.Configuration.GetSection("YourApp"));
// Register your services
services.AddScoped<ICustomerService, CustomerService>();
services.AddScoped<IOrderService, OrderService>();
// Add more service registrations
// Register MCP server with your services
services.AddScoped<McpServer>();
// Existing registrations...
}
Step 8: Add Azure Functions (Optional)
Create HTTP-triggered functions in src/YourApp.Functions/Functions/
:
public class CustomerFunction
{
private readonly ICustomerService _customerService;
public CustomerFunction(ICustomerService customerService)
{
_customerService = customerService;
}
[Function("GetCustomer")]
public async Task<HttpResponseData> GetCustomer(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "customers/{id}")]
HttpRequestData req,
string id)
{
var customer = await _customerService.GetCustomerAsync(id);
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(customer);
return response;
}
}
Step 9: Test Your MCP Application
- Build the solution:
dotnet build
- Run as MCP server:
./scripts/run-mcp-server.sh
- Test with sample requests:
# Initialize
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"0.1.0"}}' | \
dotnet run --project src/YourApp.Functions -- --mcp
# List tools
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | \
dotnet run --project src/YourApp.Functions -- --mcp
# Call a tool
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_customer","arguments":{"customerId":"123"}}}' | \
dotnet run --project src/YourApp.Functions -- --mcp
Step 10: Configure MCP Client
Add to Claude Desktop's config (~/Library/Application Support/Claude/claude_desktop_config.json
):
{
"mcpServers": {
"yourapp-server": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/YourApp.Functions", "--", "--mcp"],
"env": {
"YourApp__ApiUrl": "https://your-api.com",
"YourApp__ApiKey": "your-api-key"
}
}
}
}
Quick Start Guide
From Template to Working App in 10 Minutes
- Copy template and rename:
cp -r AzureFunctionMCPTemplate MyAwesomeMCP
cd MyAwesomeMCP
- Run the renaming script (create this helper):
#!/bin/bash
OLD_NAME="Template"
NEW_NAME="$1"
# Rename files and directories
find . -depth -name "*${OLD_NAME}*" | while read file; do
mv "$file" "${file//${OLD_NAME}/${NEW_NAME}}"
done
# Replace in files
find . -type f \( -name "*.cs" -o -name "*.csproj" -o -name "*.sln" -o -name "*.json" \) \
-exec sed -i '' "s/${OLD_NAME}/${NEW_NAME}/g" {} +
- Define your first tool in McpServer.cs
- Implement the tool handler
- Run and test:
./scripts/run-mcp-server.sh
Development Guide
Adding New MCP Tools
- Define the tool in
McpServer.cs
:
new Tool
{
Name = "your_tool",
Description = "Tool description",
InputSchema = new
{
type = "object",
properties = new
{
param1 = new { type = "string", description = "Parameter description" }
},
required = new[] { "param1" }
}
}
- Add the handler method:
private async Task<object> HandleYourToolAsync(Dictionary<string, object>? arguments)
{
// Tool implementation
}
- Register in the switch statement:
"your_tool" => await HandleYourToolAsync(toolParams.Arguments),
Adding New Azure Functions
Create a new class in src/Template.Functions/Functions/
:
public class YourFunction
{
private readonly ILogger<YourFunction> _logger;
private readonly IYourService _service;
public YourFunction(ILogger<YourFunction> logger, IYourService service)
{
_logger = logger;
_service = service;
}
[Function("YourFunction")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "your-route")]
HttpRequestData req)
{
// Function implementation
}
}
Adding Services
- Define interface in
Template.Core/Interfaces/
:
public interface IYourService
{
Task<YourResult> DoSomethingAsync(YourRequest request);
}
- Implement in
Template.Services/Services/
:
public class YourService : IYourService
{
// Implementation
}
- Register in
Program.cs
:
services.AddScoped<IYourService, YourService>();
Testing
Run All Tests
dotnet test
Run with Coverage
dotnet test --collect:"XPlat Code Coverage"
Test MCP Server
./scripts/test-mcp-server.sh
Deployment
Azure Deployment
- Create Azure Function App:
az functionapp create --resource-group myResourceGroup \
--consumption-plan-location westus \
--runtime dotnet-isolated \
--runtime-version 8 \
--functions-version 4 \
--name myFunctionApp \
--storage-account mystorageaccount
- Deploy:
cd src/Template.Functions
func azure functionapp publish myFunctionApp
Docker Deployment
Create a Dockerfile
:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish "src/Template.Functions/Template.Functions.csproj" -c Release -o /app/publish
FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0
WORKDIR /home/site/wwwroot
COPY /app/publish .
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
AI Model Support
This template supports multiple AI models through different adapters:
Claude (via MCP Protocol)
- Native MCP support through claude_desktop_config.json
- Direct tool integration
- Streaming support
Azure OpenAI (via HTTP Adapters)
- GPT-4 models (gpt-4, gpt-4-32k, gpt-4-turbo, gpt-4o)
- GPT-3.5 models (gpt-35-turbo, gpt-35-turbo-16k)
- Function calling support
- Vision capabilities (gpt-4-turbo, gpt-4o)
Other AI Services
- Generic HTTP endpoints for any AI service
- OpenAPI/Swagger compatible
- Batch tool execution
For detailed Azure OpenAI integration instructions, see .
MCP Client Configuration
Claude Desktop
Add to claude_desktop_config.json
:
{
"mcpServers": {
"template-server": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/Template.Functions", "--", "--mcp"],
"env": {
"App__ApiUrl": "https://your-api.com",
"App__ApiKey": "your-api-key"
}
}
}
}
Troubleshooting
Common Issues
- Build errors: Ensure .NET 8.0 SDK is installed
- Function runtime errors: Check Azure Functions Core Tools version
- MCP connection issues: Verify JSON-RPC format and tool names
- HTTP client errors: Check API configuration and network connectivity
Debug MCP Server
Enable detailed logging:
services.AddLogging(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Debug);
});
Debug Azure Functions
Use Visual Studio or VS Code debugging features with launch.json
configuration.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
This template is provided as-is for use in your projects. Customize the license as needed.