Skip to content
Open
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
137 changes: 137 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Node.js
node_modules/
**/node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Build outputs (except what we need)
**/build/test/
**/build/**/test/
**/build/src/
coverage/
*.tgz
*.tar.gz

# Development files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# IDE and editor files
.vscode/
.idea/
*.swp
*.swo
*~

# OS files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Git
.git/
.gitignore

# Documentation
docs/
*.md
!README.md

# Test files
**/*.test.*
**/*.spec.*
**/test/
**/tests/

# Logs
logs/
*.log

# Runtime data
pids/
*.pid
*.seed
*.pid.lock

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history

# Dependency directories that might exist in subdirs
jspm_packages/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# next.js build output
.next

# nuxt.js build output
.nuxt

# rollup.js default build output
dist/

# Uncomment the public line in if your project uses Gatsby
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# Storybook build outputs
.out
.storybook-out

# Temporary folders
tmp/
temp/

# Docker files (avoid recursive copies)
Dockerfile*
docker-compose*
.dockerignore

# CI/CD
.github/
.gitlab-ci.yml
.travis.yml
.circleci/

# Package manager
package-lock.json
yarn.lock
# Keep pnpm-lock.yaml as it's needed for consistent builds

# Misc
*.orig
112 changes: 112 additions & 0 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Docker Build and Deploy

on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.6.2

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run tests
run: pnpm test

- name: Run linting
run: pnpm lint

build-and-deploy:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
type=sha,format=long

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
DOCKER_HASH=${{ github.sha }}

cleanup:
name: Cleanup old packages
needs: build-and-deploy
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
permissions:
contents: read
packages: write

steps:
- name: Delete old package versions
uses: actions/delete-package-versions@v5
with:
package-name: ${{ github.event.repository.name }}
package-type: container
min-versions-to-keep: 10
delete-only-untagged-versions: true
81 changes: 81 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# syntax=docker/dockerfile:1.4

# Build stage - multi-architecture support
FROM node:20-bullseye AS builder

# Add metadata
LABEL org.opencontainers.image.source="https://github.com/gleanwork/mcp-server"
LABEL org.opencontainers.image.description="Glean MCP Server - Multi-architecture build"
LABEL org.opencontainers.image.licenses="MIT"

# Install build dependencies
RUN apt-get update && apt-get install -y \
git \
build-essential \
python3 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Install pnpm globally
RUN npm install -g pnpm@10.6.2

# Copy workspace configuration and root package files
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./

# Copy all package.json files to enable proper dependency resolution
COPY packages/ ./packages/

# Install dependencies using pnpm (includes workspace packages)
# Use --no-frozen-lockfile in case lockfile is out of sync
RUN pnpm install --no-frozen-lockfile

# Copy source code
COPY . .

# Build all packages
RUN pnpm run build

# Production stage
FROM node:20-bullseye-slim

WORKDIR /app

# Set docker hash as environment variable
ARG DOCKER_HASH=unknown
ENV DOCKER_HASH=$DOCKER_HASH

# Install pnpm in production stage too
RUN npm install -g pnpm@10.6.2

# Copy workspace config and package files
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./

# Copy built packages from builder stage (includes package.json files)
COPY --from=builder /app/packages ./packages

# Install only production dependencies (skip prepare scripts)
RUN pnpm install --no-frozen-lockfile --prod --ignore-scripts && \
pnpm store prune

# Make the main server executable
RUN chmod +x packages/local-mcp-server/build/index.js

# Create non-root user and required directories
RUN groupadd -r mcp && useradd -r -g mcp -m mcp && \
mkdir -p /app/logs && \
mkdir -p /home/mcp/.local/state/glean && \
mkdir -p /home/mcp/.cache && \
chown -R mcp:mcp /app && \
chown -R mcp:mcp /home/mcp

# Copy and set up entrypoint
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

# Switch to non-root user
USER mcp

# Default command runs the local MCP server
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["packages/local-mcp-server/build/index.js"]
Loading