Platform Engineering
Treat MCP servers as infrastructure APIs — provision, monitor, gate deployments, and orchestrate from scripts and pipelines.
MCP as an Infrastructure API
MCP servers can wrap any backend: cloud APIs, databases, CI/CD systems, monitoring stacks. mcp2cli gives you a CLI layer over all of them — no SDK, no client library, just shell commands with JSON output.
graph TB
subgraph "Automation Layer"
SCRIPTS["Bash / CI pipelines"]
CRON["Cron / Systemd timers"]
HOOKS["Git hooks"]
end
subgraph "mcp2cli"
CLI["mcp2cli --json"]
end
subgraph "MCP Servers (Infrastructure)"
K8S["Kubernetes MCP Server"]
AWS["Cloud Provider MCP Server"]
DB["Database MCP Server"]
MON["Monitoring MCP Server"]
end
SCRIPTS --> CLI
CRON --> CLI
HOOKS --> CLI
CLI --> K8S
CLI --> AWS
CLI --> DB
CLI --> MON
Setup: One Alias Per Infrastructure Service
# Kubernetes cluster managementmcp2cli config init --name k8s --transport streamable_http \ --endpoint http://k8s-mcp.internal:3001/mcpmcp2cli link create --name k8s
# Cloud operationsmcp2cli config init --name cloud --transport streamable_http \ --endpoint http://cloud-mcp.internal:3001/mcpmcp2cli link create --name cloud
# Databasemcp2cli config init --name db --transport stdio \ --stdio-command ./db-mcp-server --stdio-args '--config=prod.yaml'mcp2cli link create --name db
# Monitoringmcp2cli config init --name mon --transport streamable_http \ --endpoint http://monitoring-mcp.internal:3001/mcpmcp2cli link create --name monPattern: Deployment Gate
Gate releases on health checks and capacity:
#!/bin/bashset -euo pipefailVERSION="$1"
echo "=== Pre-deployment checks ==="
# 1. Cluster has capacityNODES=$(k8s --json get-nodes | jq '[.data.items[] | select(.status == "ready")] | length')if [ "$NODES" -lt 3 ]; then echo "❌ Only $NODES healthy nodes (need 3+)" exit 1fiecho "✅ $NODES healthy nodes"
# 2. No ongoing incidentsINCIDENTS=$(mon --json active-incidents | jq '.data.incidents | length')if [ "$INCIDENTS" -gt 0 ]; then echo "❌ $INCIDENTS active incidents — deploy blocked" exit 1fiecho "✅ No active incidents"
# 3. Database migrations cleanPENDING=$(db --json migration-status | jq '.data.pending | length')if [ "$PENDING" -gt 0 ]; then echo "⚠️ $PENDING pending migrations — running..." db migrate --version "$VERSION"fiecho "✅ Database schema current"
# 4. Deployecho "=== Deploying v$VERSION ==="k8s deploy --image "registry.internal/app:$VERSION" --strategy rolling
# 5. Post-deploy verificationsleep 10HEALTHY=$(k8s --json get-pods --label "version=$VERSION" | jq '[.data.items[] | select(.status == "running")] | length')echo "✅ $HEALTHY pods running v$VERSION"Pattern: Infrastructure Health Dashboard
A script that generates a health report from multiple MCP servers:
#!/bin/bash# infra-status.sh — run every 5 minutes via cron
REPORT=""
add() { REPORT+="$1\n"; }
add "# Infrastructure Status — $(date -Iseconds)"add ""
# Kubernetesif k8s --timeout 5 ping >/dev/null 2>&1; then NODE_COUNT=$(k8s --json get-nodes | jq '.data.items | length') POD_COUNT=$(k8s --json get-pods | jq '.data.items | length') add "## Kubernetes: ✅ UP" add "- Nodes: $NODE_COUNT" add "- Pods: $POD_COUNT"else add "## Kubernetes: ❌ DOWN"fiadd ""
# Databaseif db --timeout 5 ping >/dev/null 2>&1; then CONN=$(db --json pool-status | jq '.data.active_connections') add "## Database: ✅ UP" add "- Active connections: $CONN"else add "## Database: ❌ DOWN"fiadd ""
# Monitoringif mon --timeout 5 ping >/dev/null 2>&1; then ALERTS=$(mon --json active-alerts | jq '.data.alerts | length') add "## Monitoring: ✅ UP" add "- Active alerts: $ALERTS"else add "## Monitoring: ❌ DOWN"fi
echo -e "$REPORT" > /var/www/status/index.mdecho -e "$REPORT" # Also to stdout for cron mailPattern: Automated Scaling
#!/bin/bash# auto-scale.sh — triggered by monitoring alert
SERVICE="$1"DIRECTION="$2" # up or down
CURRENT=$(k8s --json get-deployment --name "$SERVICE" | jq '.data.replicas')
case "$DIRECTION" in up) TARGET=$((CURRENT * 2)) ;; down) TARGET=$((CURRENT / 2)); [ "$TARGET" -lt 1 ] && TARGET=1 ;; *) echo "Usage: $0 <service> <up|down>"; exit 1 ;;esac
echo "Scaling $SERVICE: $CURRENT → $TARGET replicas"k8s scale --deployment "$SERVICE" --replicas "$TARGET"
# Notifymon --json create-annotation \ --dashboard infrastructure \ --text "Auto-scaled $SERVICE: $CURRENT → $TARGET" \ --tags '["autoscale","'$SERVICE'"]'Pattern: Database Operations Pipeline
#!/bin/bash# db-maintenance.sh — weekly maintenance
echo "=== Weekly Database Maintenance ==="
# 1. Create backupecho "Creating backup..."BACKUP=$(db --json backup --format pg_dump --compress)BACKUP_ID=$(echo "$BACKUP" | jq -r '.data.backup_id')echo "Backup: $BACKUP_ID"
# 2. Run VACUUMecho "Running VACUUM ANALYZE..."db --json vacuum --analyze --timeout 0
# 3. Check for bloatBLOAT=$(db --json table-stats | jq '[.data.tables[] | select(.bloat_ratio > 0.3)] | length')if [ "$BLOAT" -gt 0 ]; then echo "⚠️ $BLOAT tables with >30% bloat" db --json table-stats | jq '.data.tables[] | select(.bloat_ratio > 0.3) | {name, bloat_ratio}'fi
# 4. Reportecho "✅ Maintenance complete (backup: $BACKUP_ID)"Pattern: GitOps Sync Verification
Verify that your deployed state matches your git config:
#!/bin/bashecho "=== GitOps State Verification ==="
DIFFS=0
# Check each servicefor svc in api worker scheduler; do EXPECTED_VERSION=$(yq ".services.$svc.image" deploy/config.yaml | grep -oP ':\K.*') ACTUAL_VERSION=$(k8s --json get-deployment --name "$svc" | jq -r '.data.image_tag')
if [ "$EXPECTED_VERSION" = "$ACTUAL_VERSION" ]; then echo " ✅ $svc: $ACTUAL_VERSION" else echo " ❌ $svc: expected $EXPECTED_VERSION, got $ACTUAL_VERSION" ((DIFFS++)) fidone
# Check config mapsfor cm in app-config feature-flags; do LOCAL_HASH=$(sha256sum "deploy/$cm.yaml" | cut -d' ' -f1) REMOTE_HASH=$(k8s --json get-configmap --name "$cm" | jq -r '.data.hash')
if [ "$LOCAL_HASH" = "$REMOTE_HASH" ]; then echo " ✅ configmap/$cm: in sync" else echo " ❌ configmap/$cm: drift detected" ((DIFFS++)) fidone
if [ "$DIFFS" -gt 0 ]; then echo "" echo "❌ $DIFFS drift(s) detected" exit 1fiecho "✅ All services in sync with git"Event-Driven Infrastructure
Use mcp2cli’s event sinks to trigger automation:
# k8s config with event routingevents: command: | if [ "$MCP_EVENT_TYPE" = "list_changed" ]; then # Capabilities changed — re-sync discovery k8s ls > /dev/null fi http_endpoint: "http://alertmanager:9093/api/v1/alerts"Multi-Environment Configuration
# configs/k8s-dev.yaml, k8s-staging.yaml, k8s-prod.yamlfor env in dev staging prod; do mcp2cli config init --name "k8s-$env" --transport streamable_http \ --endpoint "http://k8s-mcp-$env.internal:3001/mcp" mcp2cli link create --name "k8s-$env"done
# Now:k8s-dev get-podsk8s-staging deploy --image app:v2k8s-prod get-podsDaemon for Hot Paths
For scripts that make many sequential calls:
# Start daemons for all infrastructure servicesfor svc in k8s cloud db mon; do mcp2cli daemon start "$svc"done
# Run your pipeline (each call ~50ms instead of ~2s)./deploy-pipeline.sh
# Clean upfor svc in k8s cloud db mon; do mcp2cli daemon stop "$svc"doneSee Also
- Multi-Server Workflows — orchestrating across servers
- Shell Scripting with MCP — foundational bash patterns
- From Zero to Production — end-to-end setup
- Background Jobs — long-running infrastructure operations
- Event System — event-driven automation