1+ name : Build and Deploy MCP to GKE
2+
3+ on :
4+ push :
5+ branches :
6+ - master
7+ workflow_dispatch :
8+ inputs :
9+ deployment_name :
10+ description : ' Deployment Name'
11+ required : true
12+ default : ' mcp-git-commands'
13+
14+ env :
15+ PROJECT_ID : ${{ secrets.GKE_PROJECT }}
16+ GKE_CLUSTER : ruh-ai-dev-cluster # Add your cluster name here
17+ GKE_ZONE : us-central1 # Add your cluster zone here
18+ DEPLOYMENT_NAME : ${{ github.event.inputs.deployment_name || 'mcp-server' }}
19+ MCP_IMAGE_NAME : mcp-git-commands
20+ REPOSITORY : mcp-server # Artifact Registry repository name
21+ REGION : us-central1 # Artifact Registry region
22+
23+ jobs :
24+ setup-build-publish-deploy :
25+ name : Setup, Build, Publish, and Deploy
26+ runs-on : ubuntu-latest
27+ environment : production
28+
29+ permissions :
30+ contents : ' read'
31+ id-token : ' write'
32+
33+ steps :
34+ - name : Checkout
35+ uses : actions/checkout@v4
36+
37+ # Setup gcloud CLI
38+ - name : Authenticate to Google Cloud
39+ uses : google-github-actions/auth@v2
40+ with :
41+ credentials_json : ${{ secrets.GKE_SA_KEY }}
42+
43+ # # Create Artifact Registry repository if it doesn't exist
44+ # - name: Create Artifact Registry Repository
45+ # run: |-
46+ # gcloud artifacts repositories create $REPOSITORY \
47+ # --repository-format=docker \
48+ # --location=$REGION \
49+ # --description="MCP Server images repository" \
50+ # --quiet || true
51+
52+ # Configure Docker to use the gcloud command-line tool as a credential helper for Artifact Registry
53+ - run : |-
54+ gcloud --quiet auth configure-docker $REGION-docker.pkg.dev
55+
56+ # Get the GKE credentials so we can deploy to the cluster
57+ - name : Get GKE Credentials
58+ uses : google-github-actions/get-gke-credentials@v2
59+ with :
60+ cluster_name : ${{ env.GKE_CLUSTER }}
61+ location : ${{ env.GKE_ZONE }}
62+
63+ # Build the Docker image for MCP server
64+ - name : Build MCP Server Image
65+ run : |-
66+ docker build \
67+ --no-cache \
68+ --tag "$REGION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$MCP_IMAGE_NAME:${GITHUB_REF_NAME}-${GITHUB_SHA::7}" \
69+ --build-arg GITHUB_SHA="$GITHUB_SHA" \
70+ --build-arg GITHUB_REF="$GITHUB_REF" \
71+ .
72+
73+ # Push the Docker image to Google Artifact Registry
74+ - name : Publish MCP Server Image
75+ run : |-
76+ docker push "$REGION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$MCP_IMAGE_NAME:${GITHUB_REF_NAME}-${GITHUB_SHA::7}"
77+
78+ # Create deployment manifest
79+ - name : Create deployment manifest
80+ run : |
81+ cat > k8s-manifest.yaml << 'EOF'
82+ apiVersion: apps/v1
83+ kind: Deployment
84+ metadata:
85+ name: ${{ env.DEPLOYMENT_NAME }}
86+ labels:
87+ app: ${{ env.DEPLOYMENT_NAME }}
88+ spec:
89+ replicas: 1
90+ selector:
91+ matchLabels:
92+ app: ${{ env.DEPLOYMENT_NAME }}
93+ template:
94+ metadata:
95+ labels:
96+ app: ${{ env.DEPLOYMENT_NAME }}
97+ spec:
98+ containers:
99+ # MCP Server (stdio) - using the image we just built and pushed to GCR
100+ - name: mcp-server
101+ image: ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.MCP_IMAGE_NAME }}:$GITHUB_REF_NAME-${GITHUB_SHA::7}
102+ # Keep their original command/entrypoint
103+ # The container runs normally with stdio
104+ env:
105+ - name: GITHUB_TOKEN
106+ valueFrom:
107+ secretKeyRef:
108+ name: mcp-secrets
109+ key: github-token
110+ optional: true
111+ resources:
112+ requests:
113+ memory: "256Mi"
114+ cpu: "250m"
115+ limits:
116+ memory: "512Mi"
117+ cpu: "500m"
118+
119+ # MCP Proxy Sidecar - bridges stdio to HTTP
120+ - name: mcp-proxy
121+ image: ghcr.io/sparfenyuk/mcp-proxy:latest
122+ ports:
123+ - containerPort: 8080
124+ name: http
125+ command:
126+ - mcp-proxy
127+ - stdio-to-sse
128+ - http://0.0.0.0:8080
129+ - --allow-origin=*
130+ - --command
131+ - node
132+ - --args
133+ - src/index.js
134+ resources:
135+ requests:
136+ memory: "128Mi"
137+ cpu: "100m"
138+ limits:
139+ memory: "256Mi"
140+ cpu: "200m"
141+ ---
142+ apiVersion: v1
143+ kind: Service
144+ metadata:
145+ name: ${{ env.DEPLOYMENT_NAME }}-service
146+ spec:
147+ selector:
148+ app: ${{ env.DEPLOYMENT_NAME }}
149+ ports:
150+ - name: http
151+ port: 80
152+ targetPort: 8080
153+ type: LoadBalancer
154+ EOF
155+
156+
157+ # Deploy to GKE
158+ - name : Deploy
159+ run : |-
160+ kubectl apply -f k8s-manifest.yaml
161+ kubectl rollout status deployment/${{ env.DEPLOYMENT_NAME }}
162+ kubectl get services -o wide
0 commit comments