Production-Ready Settings
Production-Ready Settings
This guide outlines the essential configuration and deployment settings required to run the MCP Weather Server in production environments.
Configuration Management
Environment Variables
The application supports flexible configuration through environment variables and appsettings.json:
# Weather service configuration
WEATHER_CHOICES="sunny,cloudy,rainy,stormy,snowy,windy,foggy"
# Logging configuration
ASPNETCORE_ENVIRONMENT=Production
Logging__LogLevel__Default=Information
Logging__LogLevel__Microsoft=Warning
Application Settings
Create an appsettings.Production.json for production-specific settings:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"Console": {
"LogToStandardErrorThreshold": "Error"
}
},
"WeatherChoices": "sunny,partly-cloudy,cloudy,overcast,light-rain,heavy-rain,thunderstorm,snow,fog,windy",
"RandomNumber": {
"DefaultMin": 0,
"DefaultMax": 100
}
}
Docker Configuration
Multi-Stage Dockerfile
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["SampleMcpServer.csproj", "./"]
RUN dotnet restore "SampleMcpServer.csproj"
COPY . .
RUN dotnet build "SampleMcpServer.csproj" -c Release -o /app/build
# Test stage
FROM build AS test
RUN dotnet test --no-build --verbosity normal --collect:"XPlat Code Coverage"
# Publish stage
FROM build AS publish
RUN dotnet publish "SampleMcpServer.csproj" -c Release -o /app/publish /p:UseAppHost=false
# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS final
WORKDIR /app
COPY --from=publish /app/publish .
# Create non-root user
RUN adduser -D -s /bin/sh appuser
USER appuser
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD dotnet SampleMcpServer.dll --health-check || exit 1
ENTRYPOINT ["dotnet", "SampleMcpServer.dll"]
Docker Compose for Production
version: '3.8'
services:
mcp-server:
build:
context: .
dockerfile: Dockerfile
target: final
image: mcp-server:latest
container_name: mcp-server-prod
restart: unless-stopped
environment:
- ASPNETCORE_ENVIRONMENT=Production
- WEATHER_CHOICES=sunny,cloudy,rainy,stormy,snowy,windy,foggy,clear,overcast
- Logging__LogLevel__Default=Information
volumes:
- ./logs:/app/logs:rw
networks:
- mcp-network
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.25'
memory: 128M
networks:
mcp-network:
driver: bridge
Security Considerations
Application Security
Input Validation
public string GetCityWeather(string city) { ArgumentException.ThrowIfNullOrWhiteSpace(city, nameof(city)); // Additional validation if (city.Length > 100) throw new ArgumentException("City name too long", nameof(city)); // Sanitize input city = city.Trim(); return _weatherService.GetCityWeather(city); }Configuration Security
{ "AllowedHosts": "*", "Kestrel": { "Limits": { "MaxConcurrentConnections": 100, "MaxRequestBodySize": 1048576 } } }
Container Security
# Use specific tags, not 'latest'
FROM mcr.microsoft.com/dotnet/aspnet:8.0.0-alpine
# Run as non-root user
RUN adduser -D -s /bin/sh appuser
USER appuser
# Remove unnecessary packages
RUN apk del --purge curl wget
# Set read-only root filesystem
VOLUME ["/tmp", "/app/logs"]
Performance Optimization
Startup Configuration
var builder = Host.CreateApplicationBuilder(args);
// Configure logging for production
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options =>
{
options.LogToStandardErrorThreshold = LogLevel.Error;
options.TimestampFormat = "[yyyy-MM-dd HH:mm:ss] ";
});
// Configure services for better performance
builder.Services.Configure<HostOptions>(options =>
{
options.ShutdownTimeout = TimeSpan.FromSeconds(30);
});
// Register services as singletons for better performance
builder.Services.AddApplicationServices();
Memory Management
// In ServiceCollectionExtensions
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
// Use singletons for stateless services
services.AddSingleton<IRandomNumberService, RandomNumberService>();
services.AddSingleton<IWeatherService, WeatherService>();
// Configure memory limits
services.Configure<GCSettings>(options =>
{
// Enable server GC for better throughput
options.IsServerGC = true;
});
return services;
}
Monitoring and Observability
Structured Logging
services.AddLogging(builder =>
{
builder.AddConsole(options =>
{
options.FormatterName = "json";
});
builder.AddJsonConsole(options =>
{
options.JsonWriterOptions = new JsonWriterOptions
{
Indented = false
};
});
});
Health Checks
public static class HealthCheckExtensions
{
public static IServiceCollection AddApplicationHealthChecks(
this IServiceCollection services)
{
services.AddHealthChecks()
.AddCheck<RandomNumberServiceHealthCheck>("random-service")
.AddCheck<WeatherServiceHealthCheck>("weather-service");
return services;
}
}
public class WeatherServiceHealthCheck : IHealthCheck
{
private readonly IWeatherService _weatherService;
public WeatherServiceHealthCheck(IWeatherService weatherService)
{
_weatherService = weatherService;
}
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
var result = _weatherService.GetCityWeather("HealthCheck");
return Task.FromResult(HealthCheckResult.Healthy());
}
catch (Exception ex)
{
return Task.FromResult(HealthCheckResult.Unhealthy(ex.Message));
}
}
}
Deployment Strategies
Blue-Green Deployment
# docker-compose.blue-green.yml
version: '3.8'
services:
mcp-server-blue:
image: mcp-server:${BLUE_VERSION}
environment:
- DEPLOYMENT_SLOT=blue
ports:
- "8080:8080"
mcp-server-green:
image: mcp-server:${GREEN_VERSION}
environment:
- DEPLOYMENT_SLOT=green
ports:
- "8081:8080"
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- mcp-server-blue
- mcp-server-green
Rolling Updates
#!/bin/bash
# rolling-update.sh
# Update containers one by one
docker-compose up -d --scale mcp-server=2
sleep 30
# Health check new containers
curl -f http://localhost:8080/health || exit 1
# Scale down old containers
docker-compose up -d --scale mcp-server=1 --no-recreate
Resource Limits and Scaling
Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
spec:
replicas: 3
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
spec:
containers:
- name: mcp-server
image: mcp-server:latest
ports:
- containerPort: 8080
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Backup and Recovery
Configuration Backup
#!/bin/bash
# backup-config.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/config/$DATE"
mkdir -p "$BACKUP_DIR"
# Backup configuration files
cp appsettings.Production.json "$BACKUP_DIR/"
cp docker-compose.prod.yml "$BACKUP_DIR/"
# Backup environment variables
printenv | grep -E '^(WEATHER_|ASPNETCORE_|Logging__)' > "$BACKUP_DIR/environment.vars"
echo "Configuration backed up to $BACKUP_DIR"
Disaster Recovery
# disaster-recovery.yml
version: '3.8'
services:
mcp-server-primary:
image: mcp-server:latest
deploy:
placement:
constraints:
- node.labels.zone == primary
mcp-server-secondary:
image: mcp-server:latest
deploy:
placement:
constraints:
- node.labels.zone == secondary
replicas: 0 # Scaled up during failover
Next Steps
- Review Architecture Documentation for system design details
- Explore CI/CD Maintainability for deployment automation
- Check Testing Integration for quality assurance processes