Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/cicd-stg.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: "CICD staging"

on:
pull_request:
branches:
- main
push:
branches:
- main
- zilliqa

jobs:
build:
permissions:
id-token: write
contents: write
runs-on: ubuntu-22.04
if: github.actor != 'dependabot[bot]'
name: "Build image"

env:
REGISTRY: ${{ secrets.REGISTRY }}
IMAGE_NAME: ${{ secrets.REGISTRY }}/${{ secrets.GCP_PROJECT_ID_STG }}/zilliqa-public/evm-mcp-server
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: 0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0

- name: Docker build and push in production
uses: Zilliqa/gh-actions-workflows/actions/ci-dockerized-app-build-push@v2
with:
context: .
push: ${{ github.ref_name == github.event.repository.default_branch || github.ref_name == 'zilliqa' }}
tag: ${{ env.IMAGE_NAME }}
tag-length: 8
tag-latest: false
registry: ${{ env.REGISTRY }}
workload-identity-provider: "${{ secrets.GCP_PRD_GITHUB_WIF }}"
service-account: "${{ secrets.GCP_STG_GITHUB_SA_DOCKER_REGISTRY }}"
cache-key: ${{ env.IMAGE_NAME }}-cache
51 changes: 51 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Use Bun as the base image (preferred runtime according to README)
FROM oven/bun:1.1.29-alpine AS base

# Set working directory
WORKDIR /app

# Copy package files for dependency installation
COPY package.json bun.lockb* ./

# Install dependencies (including dev dependencies for TypeScript compilation)
RUN bun install --frozen-lockfile

# Install curl for health checks
RUN apk add --no-cache curl

# Copy source code
COPY . .

# Build the project for production
RUN bun run build && bun run build:http

# Create a non-root user for security
RUN addgroup -g 1001 -S nodejs && \
adduser -S evm-mcp -u 1001

# Change ownership of the app directory
RUN chown -R evm-mcp:nodejs /app
USER evm-mcp

# Expose the HTTP server port (default: 3000)
EXPOSE 3000

# Health check for HTTP server with streaming endpoints
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1

# Run the HTTP server with streaming support
CMD ["bun", "start:http"]

# Multi-stage build for production optimization
FROM base AS production

# Labels for better container management
LABEL maintainer="EVM MCP Server"
LABEL description="HTTP MCP Server for EVM blockchain interactions with streaming support"
LABEL version="1.0.0"

# Environment variables for HTTP server configuration
ENV NODE_ENV=production
ENV PORT=3000
ENV HOST=0.0.0.0
116 changes: 116 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Makefile for EVM MCP Server Docker operations

# Variables
IMAGE_NAME = evm-mcp-server
IMAGE_TAG = latest
CONTAINER_NAME = evm-mcp-server
PORT = 3000

# Default target
.DEFAULT_GOAL := help

# Help target
.PHONY: help
help: ## Show this help message
@echo "Available commands:"
@echo ""
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

# Build targets
.PHONY: build
build: ## Build the Docker image
docker build -t $(IMAGE_NAME):$(IMAGE_TAG) .

.PHONY: build-no-cache
build-no-cache: ## Build the Docker image without cache
docker build --no-cache -t $(IMAGE_NAME):$(IMAGE_TAG) .

.PHONY: build-production
build-production: ## Build the production Docker image
docker build --target production -t $(IMAGE_NAME):$(IMAGE_TAG) .

# Run targets
.PHONY: run
run: ## Run the Docker container on port 3000
docker run -d --name $(CONTAINER_NAME) -p $(PORT):3000 $(IMAGE_NAME):$(IMAGE_TAG)

.PHONY: run-interactive
run-interactive: ## Run the Docker container interactively
docker run -it --rm -p $(PORT):3000 $(IMAGE_NAME):$(IMAGE_TAG)

.PHONY: run-detached
run-detached: ## Run the Docker container in detached mode
docker run -d --name $(CONTAINER_NAME) -p $(PORT):3000 $(IMAGE_NAME):$(IMAGE_TAG)

# Stop and clean targets
.PHONY: stop
stop: ## Stop the running container
docker stop $(CONTAINER_NAME) || true

.PHONY: remove
remove: ## Remove the container
docker rm $(CONTAINER_NAME) || true

.PHONY: clean
clean: ## Stop and remove the container
$(MAKE) stop
$(MAKE) remove

.PHONY: clean-images
clean-images: ## Remove Docker images
docker rmi $(IMAGE_NAME):$(IMAGE_TAG) || true

# Development targets
.PHONY: dev
dev: ## Build and run for development (interactive)
$(MAKE) build
$(MAKE) run-interactive

.PHONY: dev-detached
dev-detached: ## Build and run for development (detached)
$(MAKE) build
$(MAKE) run-detached

# Production targets
.PHONY: prod
prod: ## Build production image and run
$(MAKE) build-production
$(MAKE) run-detached

# Utility targets
.PHONY: logs
logs: ## Show container logs
docker logs -f $(CONTAINER_NAME)

.PHONY: shell
shell: ## Access container shell
docker exec -it $(CONTAINER_NAME) /bin/sh

.PHONY: status
status: ## Show container status
docker ps -a | grep $(CONTAINER_NAME) || echo "Container not found"

.PHONY: health
health: ## Check container health
curl -f http://localhost:$(PORT)/health || echo "Health check failed"

# Complete workflow targets
.PHONY: start
start: ## Complete workflow: build and run
$(MAKE) build
$(MAKE) run-detached
@echo "Container started on http://localhost:$(PORT) (HTTP/1.1 with HTTP/2 upgrade support)"
@echo "Health check: http://localhost:$(PORT)/health"
@echo "StreamableHTTP endpoint: http://localhost:$(PORT)/mcp"

.PHONY: restart
restart: ## Restart the container
$(MAKE) clean
$(MAKE) start

.PHONY: rebuild
rebuild: ## Rebuild and restart the container
$(MAKE) clean
$(MAKE) build-no-cache
$(MAKE) run-detached
@echo "Container rebuilt and started on http://localhost:$(PORT)"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ npm install
The server uses the following default configuration:

- **Default Chain ID**: 1 (Ethereum Mainnet)
- **Server Port**: 3001
- **Server Port**: 3000
- **Server Host**: 0.0.0.0 (accessible from any network interface)

These values are hardcoded in the application. If you need to modify them, you can edit the following files:
Expand Down Expand Up @@ -271,7 +271,7 @@ If you're developing a web application and want to connect to the HTTP server wi
{
"mcpServers": {
"evm-mcp-sse": {
"url": "http://localhost:3001/sse"
"url": "http://localhost:3000/sse"
}
}
}
Expand Down
Loading