feat: add Docker support for cross-platform easy setup

Implements comprehensive Docker support to eliminate Python version and dependency concerns.
Users can now run the MCP server in a container with automatic path translation between
host and container filesystems.

Key features:
- Dockerfile with multi-architecture support (amd64/arm64)
- Automatic path translation using WORKSPACE_ROOT environment variable
- Setup scripts for all platforms (Bash, CMD, PowerShell)
- GitHub Actions workflow for automated Docker Hub publishing
- Secure non-root container execution
- Read-only volume mounts by default

The setup process is now simplified to:
1. Run setup-docker-env script to generate .env and Claude config
2. Build the Docker image
3. Copy generated config to Claude Desktop

No Python installation or virtual environment management required.

Fixes #3

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Fahad
2025-06-09 22:25:06 +04:00
parent ed587f27d5
commit 6b03088eee
9 changed files with 651 additions and 18 deletions

72
.dockerignore Normal file
View File

@@ -0,0 +1,72 @@
# Git
.git
.gitignore
# Python
__pycache__
*.pyc
*.pyo
*.pyd
.Python
*.egg
*.egg-info/
dist/
build/
*.so
.coverage
.pytest_cache/
htmlcov/
.tox/
.mypy_cache/
.ruff_cache/
# Virtual environments
venv/
env/
ENV/
.venv/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# Docker
.dockerignore
Dockerfile
docker-compose*.yml
# Environment files (contain secrets)
.env
.env.*
*.env
# Documentation
*.md
docs/
examples/
# Tests
tests/
test_*.py
*_test.py
# CI/CD
.github/
.gitlab-ci.yml
.travis.yml
# Logs
*.log
logs/
# Temporary files
tmp/
temp/
*.tmp
# OS specific
Thumbs.db

15
.env.example Normal file
View File

@@ -0,0 +1,15 @@
# Example .env file for Gemini MCP Server Docker setup
# Copy this to .env and update with your actual values
# Your Gemini API key (required)
# Get one from: https://makersuite.google.com/app/apikey
GEMINI_API_KEY=your-gemini-api-key-here
# The absolute path to your project directory on the host machine
# This will be mounted to /workspace in the container
# Example: /Users/username/my-project (macOS/Linux)
# Example: C:\Users\username\my-project (Windows)
WORKSPACE_ROOT=/path/to/your/project
# Optional: Logging level (DEBUG, INFO, WARNING, ERROR)
# LOG_LEVEL=INFO

82
.github/workflows/docker-publish.yml vendored Normal file
View File

@@ -0,0 +1,82 @@
name: Build and Publish Docker Images
on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
workflow_dispatch:
env:
REGISTRY: docker.io
IMAGE_NAME: beehiveinnovations/gemini-mcp-server
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
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: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_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}}
- 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
test-image:
needs: build-and-push
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
strategy:
matrix:
platform: [linux/amd64, linux/arm64]
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Test Docker image
run: |
docker run --rm --platform ${{ matrix.platform }} \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name == 'main' && 'latest' || github.ref_name }} \
python -c "import mcp, google.genai; print('Dependencies loaded successfully')"

29
Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
# Use Python 3.11 slim image for smaller size and consistent environment
FROM python:3.11-slim
# Set working directory inside the container
WORKDIR /app
# Install git (required for some Python packages that may need it)
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements first to leverage Docker layer caching
COPY requirements.txt .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application
COPY . .
# Create a non-root user to run the application (security best practice)
RUN useradd -m -u 1000 mcpuser && \
chown -R mcpuser:mcpuser /app
# Switch to non-root user
USER mcpuser
# Set the entrypoint to run the server
ENTRYPOINT ["python", "server.py"]

227
README.md
View File

@@ -8,6 +8,34 @@
The ultimate development partner for Claude - a Model Context Protocol server that gives Claude access to Google's Gemini 2.5 Pro for extended thinking, code analysis, and problem-solving. **Automatically reads files and directories, passing their contents to Gemini for analysis within its 1M token context.**
## Quick Navigation
- **Getting Started**
- [Quickstart](#quickstart-5-minutes) - Get running in 5 minutes
- [Docker Setup](#docker-setup-recommended) - Recommended approach
- [Traditional Setup](#option-b-traditional-setup) - Python-based setup
- [Available Tools](#available-tools) - Overview of all tools
- **Tools Reference**
- [`chat`](#1-chat---general-development-chat--collaborative-thinking) - Collaborative thinking
- [`think_deeper`](#2-think_deeper---extended-reasoning-partner) - Extended reasoning
- [`review_code`](#3-review_code---professional-code-review) - Code review
- [`review_changes`](#4-review_changes---pre-commit-validation) - Pre-commit validation
- [`debug_issue`](#5-debug_issue---expert-debugging-assistant) - Debugging help
- [`analyze`](#6-analyze---smart-file-analysis) - File analysis
- **Advanced Topics**
- [Thinking Modes](#thinking-modes---managing-token-costs--quality) - Control depth vs cost
- [Collaborative Workflows](#collaborative-workflows) - Multi-tool patterns
- [Tool Parameters](#tool-parameters) - Detailed parameter reference
- [Docker Architecture](#docker-architecture) - How Docker integration works
- **Resources**
- [Windows Setup](#windows-setup-guide) - Windows-specific instructions
- [Troubleshooting](#troubleshooting) - Common issues and solutions
- [Contributing](#contributing) - How to contribute
- [Testing](#testing) - Running tests
## Why This Server?
Claude is brilliant, but sometimes you need:
@@ -33,6 +61,14 @@ All tools accept both individual files and entire directories. The server:
## Quickstart (5 minutes)
### Prerequisites
Choose one of the following options:
**Option A: Docker (Recommended - No Python Required!)**
- Docker Desktop installed ([Download here](https://www.docker.com/products/docker-desktop/))
- Git
**Option B: Traditional Setup**
- **Python 3.10 or higher** (required by the `mcp` package)
- Git
@@ -40,14 +76,42 @@ All tools accept both individual files and entire directories. The server:
Visit [Google AI Studio](https://makersuite.google.com/app/apikey) and generate an API key. For best results with Gemini 2.5 Pro, use a paid API key as the free tier has limited access to the latest models.
### 2. Clone and Set Up the Repository
Clone this repository to a location on your computer and install dependencies:
```bash
# Example: Clone to your home directory
cd ~
# Clone to your preferred location
git clone https://github.com/BeehiveInnovations/gemini-mcp-server.git
cd gemini-mcp-server
```
Now choose your setup method:
#### Option A: Docker Setup (Recommended)
```bash
# 1. Generate the .env file with your current directory as workspace
# macOS/Linux:
./setup-docker-env.sh
# Windows (Command Prompt):
setup-docker-env.bat
# Windows (PowerShell):
.\setup-docker-env.ps1
# 2. Edit .env and add your Gemini API key
# The .env file will contain:
# WORKSPACE_ROOT=/your/current/directory (automatically set)
# GEMINI_API_KEY=your-gemini-api-key-here (you need to update this)
# 3. Build the Docker image
docker build -t gemini-mcp-server .
```
**That's it!** Docker handles all Python dependencies and environment setup for you.
#### Option B: Traditional Setup
```bash
# Run the setup script to install dependencies
# macOS/Linux:
./setup.sh
@@ -71,16 +135,89 @@ If you encounter any issues during setup, see the [Troubleshooting](#troubleshoo
### 3. Configure Claude Desktop
Add the server to your `claude_desktop_config.json`:
**Option A: Edit the config file directly**
**Find your config file:**
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
**Option B: Use Claude Desktop UI (macOS)**
**Or use Claude Desktop UI (macOS):**
- Open Claude Desktop
- Go to **Settings****Developer****Edit Config**
- This will open the `claude_desktop_config.json` file in your default editor
**Add this configuration** (replace with YOUR actual paths):
Choose your configuration based on your setup method:
#### Option A: Docker Configuration (Recommended)
**How it works:** Claude Desktop launches Docker, which runs the MCP server in a container. The communication happens through stdin/stdout, just like running a regular command.
**All Platforms (macOS/Linux/Windows):**
```json
{
"mcpServers": {
"gemini": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"--env-file", "/path/to/gemini-mcp-server/.env",
"-v", "/path/to/your/project:/workspace:ro",
"gemini-mcp-server:latest"
]
}
}
}
```
**Important for Docker setup:**
- Replace `/path/to/gemini-mcp-server/.env` with the full path to your .env file
- Replace `/path/to/your/project` with the directory containing code you want to analyze
- The container runs temporarily when Claude needs it (no persistent Docker containers)
- Communication happens via stdio - Docker's `-i` flag connects the container's stdin/stdout to Claude
**Path Format Notes:**
- **Windows users**: Use forward slashes `/` in Docker paths (e.g., `C:/Users/john/project`)
- Docker on Windows automatically handles both forward slashes and backslashes
- The setup scripts generate the correct format for your platform
**Example for macOS/Linux:**
```json
{
"mcpServers": {
"gemini": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"--env-file", "/Users/john/gemini-mcp-server/.env",
"-v", "/Users/john/my-project:/workspace:ro",
"gemini-mcp-server:latest"
]
}
}
}
```
**Example for Windows:**
```json
{
"mcpServers": {
"gemini": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"--env-file", "C:/Users/john/gemini-mcp-server/.env",
"-v", "C:/Users/john/my-project:/workspace:ro",
"gemini-mcp-server:latest"
]
}
}
}
```
#### Option B: Traditional Configuration
**macOS/Linux:**
```json
@@ -111,7 +248,6 @@ Add the server to your `claude_desktop_config.json`:
```
**Windows (Using WSL):**
If your development environment is in WSL, use `wsl.exe` as a bridge:
```json
{
"mcpServers": {
@@ -126,14 +262,6 @@ If your development environment is in WSL, use `wsl.exe` as a bridge:
}
```
**Important**:
- Replace `YOUR_USERNAME` with your actual Windows username
- Replace `YOUR_WSL_USERNAME` with your WSL username
- Use the full absolute path where you cloned the repository
- Windows native: Note the double backslashes `\\` in the path
- WSL: Use Linux-style paths starting with `/`
- See `examples/` folder for complete configuration examples
### 4. Restart Claude Desktop
Completely quit and restart Claude Desktop for the changes to take effect.
@@ -168,6 +296,73 @@ Just ask Claude naturally:
**Pro Tip:** You can control the depth of Gemini's analysis with thinking modes to manage token costs. For quick tasks use "minimal" or "low" to save tokens, for complex problems use "high" or "max" when quality matters more than cost. [Learn more about thinking modes](#thinking-modes---managing-token-costs--quality)
## Docker Setup (Recommended)
The Docker setup provides a consistent, hassle-free experience across all platforms without worrying about Python versions or dependencies.
### Why Docker?
- **Zero Python Setup**: No need to install Python or manage virtual environments
- **Consistent Environment**: Same behavior across Windows, macOS, and Linux
- **Easy Updates**: Just pull the latest image or rebuild
- **Isolated Dependencies**: No conflicts with your system Python packages
### How It Works
1. **Path Translation**: The server automatically translates file paths between your host system and the Docker container
2. **Workspace Mounting**: Your project directory is mounted to `/workspace` inside the container
3. **Environment Variables**: API keys and settings are managed via `.env` file
4. **stdio Communication**: Docker preserves the stdin/stdout communication required by MCP
### Docker Architecture
```
Your Machine Docker Container
----------- ----------------
Claude Desktop --stdio--> Docker CLI --stdio--> MCP Server
| | |
v v v
/your/project <--mount--> /workspace <--access--> File Analysis
```
### Testing Docker Setup
You can test your Docker setup before configuring Claude:
```bash
# Test that the image builds successfully
docker build -t gemini-mcp-server .
# Test that the server starts correctly
docker run --rm -i --env-file .env -v "$(pwd):/workspace:ro" gemini-mcp-server:latest
# You should see "INFO:__main__:Gemini API key found"
# The server will then wait for MCP commands (no further output)
# Press Ctrl+C to exit
```
### Quick Docker Commands
```bash
# Build the image
docker build -t gemini-mcp-server .
# Update to latest version
git pull && docker build -t gemini-mcp-server .
# Test the server manually (replace paths as needed)
docker run --rm -i --env-file .env -v "$(pwd):/workspace:ro" gemini-mcp-server:latest
```
### Publishing to Docker Hub
Once stable, we'll publish pre-built images to Docker Hub, eliminating the build step:
```bash
# Future: Just pull and run
docker pull beehiveinnovations/gemini-mcp-server:latest
```
## Windows Setup Guide
### Option 1: Native Windows (Recommended)

61
setup-docker-env.bat Normal file
View File

@@ -0,0 +1,61 @@
@echo off
REM Helper script to set up .env file for Docker usage on Windows
echo Setting up .env file for Gemini MCP Server Docker...
REM Get the current working directory (absolute path)
set CURRENT_DIR=%CD%
REM Check if .env already exists
if exist .env (
echo Warning: .env file already exists! Skipping creation.
echo.
) else (
REM Create the .env file
(
echo # Gemini MCP Server Docker Environment Configuration
echo # Generated on %DATE% %TIME%
echo.
echo # The absolute path to your project root on the host machine
echo # This should be the directory containing your code that you want to analyze
echo WORKSPACE_ROOT=%CURRENT_DIR%
echo.
echo # Your Gemini API key ^(get one from https://makersuite.google.com/app/apikey^)
echo # IMPORTANT: Replace this with your actual API key
echo GEMINI_API_KEY=your-gemini-api-key-here
echo.
echo # Optional: Set logging level ^(DEBUG, INFO, WARNING, ERROR^)
echo # LOG_LEVEL=INFO
) > .env
echo.
echo Created .env file
echo.
)
echo Next steps:
echo 1. Edit .env and replace 'your-gemini-api-key-here' with your actual Gemini API key
echo 2. Run 'docker build -t gemini-mcp-server .' to build the Docker image
echo 3. Copy this configuration to your Claude Desktop config:
echo.
echo ===== COPY BELOW THIS LINE =====
echo {
echo "mcpServers": {
echo "gemini": {
echo "command": "docker",
echo "args": [
echo "run",
echo "--rm",
echo "-i",
echo "--env-file", "%CURRENT_DIR%\.env",
echo "-v", "%CURRENT_DIR%:/workspace:ro",
echo "gemini-mcp-server:latest"
echo ]
echo }
echo }
echo }
echo ===== COPY ABOVE THIS LINE =====
echo.
echo Config file location:
echo Windows: %%APPDATA%%\Claude\claude_desktop_config.json
echo.
echo Note: The configuration above mounts the current directory ^(%CURRENT_DIR%^)
echo as the workspace. You can change this path to any project directory you want to analyze.

64
setup-docker-env.ps1 Normal file
View File

@@ -0,0 +1,64 @@
# PowerShell script to set up .env file for Docker usage on Windows
Write-Host "Setting up .env file for Gemini MCP Server Docker..."
# Get the current working directory (absolute path)
$CurrentDir = Get-Location
# Check if .env already exists
if (Test-Path .env) {
Write-Host "Warning: .env file already exists! Skipping creation." -ForegroundColor Yellow
Write-Host ""
} else {
# Create the .env file
@"
# Gemini MCP Server Docker Environment Configuration
# Generated on $(Get-Date)
# The absolute path to your project root on the host machine
# This should be the directory containing your code that you want to analyze
WORKSPACE_ROOT=$CurrentDir
# Your Gemini API key (get one from https://makersuite.google.com/app/apikey)
# IMPORTANT: Replace this with your actual API key
GEMINI_API_KEY=your-gemini-api-key-here
# Optional: Set logging level (DEBUG, INFO, WARNING, ERROR)
# LOG_LEVEL=INFO
"@ | Out-File -FilePath .env -Encoding utf8
Write-Host "Created .env file" -ForegroundColor Green
Write-Host ""
}
Write-Host "Next steps:"
Write-Host "1. Edit .env and replace 'your-gemini-api-key-here' with your actual Gemini API key"
Write-Host "2. Run 'docker build -t gemini-mcp-server .' to build the Docker image"
Write-Host "3. Copy this configuration to your Claude Desktop config:"
Write-Host ""
Write-Host "===== COPY BELOW THIS LINE =====" -ForegroundColor Cyan
Write-Host @"
{
"mcpServers": {
"gemini": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"--env-file", "$CurrentDir\.env",
"-v", "${CurrentDir}:/workspace:ro",
"gemini-mcp-server:latest"
]
}
}
}
"@
Write-Host "===== COPY ABOVE THIS LINE =====" -ForegroundColor Cyan
Write-Host ""
Write-Host "Config file location:"
Write-Host " Windows: %APPDATA%\Claude\claude_desktop_config.json"
Write-Host ""
Write-Host "Note: The configuration above mounts the current directory ($CurrentDir)"
Write-Host "as the workspace. You can change this path to any project directory you want to analyze."
Write-Host "Docker on Windows accepts both forward slashes and backslashes in paths."

62
setup-docker-env.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/bash
# Helper script to set up .env file for Docker usage
echo "Setting up .env file for Gemini MCP Server Docker..."
# Get the current working directory (absolute path)
CURRENT_DIR=$(pwd)
# Check if .env already exists
if [ -f .env ]; then
echo "⚠️ .env file already exists! Skipping creation."
echo ""
else
# Create the .env file
cat > .env << EOF
# Gemini MCP Server Docker Environment Configuration
# Generated on $(date)
# The absolute path to your project root on the host machine
# This should be the directory containing your code that you want to analyze
WORKSPACE_ROOT=$CURRENT_DIR
# Your Gemini API key (get one from https://makersuite.google.com/app/apikey)
# IMPORTANT: Replace this with your actual API key
GEMINI_API_KEY=your-gemini-api-key-here
# Optional: Set logging level (DEBUG, INFO, WARNING, ERROR)
# LOG_LEVEL=INFO
EOF
echo "✅ Created .env file"
echo ""
fi
echo "Next steps:"
echo "1. Edit .env and replace 'your-gemini-api-key-here' with your actual Gemini API key"
echo "2. Run 'docker build -t gemini-mcp-server .' to build the Docker image"
echo "3. Copy this configuration to your Claude Desktop config:"
echo ""
echo "===== COPY BELOW THIS LINE ====="
echo "{"
echo " \"mcpServers\": {"
echo " \"gemini\": {"
echo " \"command\": \"docker\","
echo " \"args\": ["
echo " \"run\","
echo " \"--rm\","
echo " \"-i\","
echo " \"--env-file\", \"$CURRENT_DIR/.env\","
echo " \"-v\", \"$CURRENT_DIR:/workspace:ro\","
echo " \"gemini-mcp-server:latest\""
echo " ]"
echo " }"
echo " }"
echo "}"
echo "===== COPY ABOVE THIS LINE ====="
echo ""
echo "Config file location:"
echo " macOS: ~/Library/Application Support/Claude/claude_desktop_config.json"
echo " Windows: %APPDATA%\\Claude\\claude_desktop_config.json"
echo ""
echo "Note: The configuration above mounts the current directory ($CURRENT_DIR)"
echo "as the workspace. You can change this path to any project directory you want to analyze."

View File

@@ -24,18 +24,29 @@ from typing import List, Optional, Tuple, Set
from .token_utils import estimate_tokens, MAX_CONTEXT_TOKENS
# Get workspace root for Docker path translation
# When running in Docker with a mounted workspace, WORKSPACE_ROOT contains
# the host path that corresponds to /workspace in the container
WORKSPACE_ROOT = os.environ.get("WORKSPACE_ROOT")
CONTAINER_WORKSPACE = Path("/workspace")
# Get project root from environment or use current directory
# This defines the sandbox directory where file access is allowed
#
# Security model:
# 1. If MCP_PROJECT_ROOT is explicitly set, use it as a sandbox
# 2. If not set, allow access to user's home directory and below
# 3. Never allow access to system directories outside home
# 2. If not set and in Docker (WORKSPACE_ROOT exists), use /workspace
# 3. Otherwise, allow access to user's home directory and below
# 4. Never allow access to system directories outside home
env_root = os.environ.get("MCP_PROJECT_ROOT")
if env_root:
# If explicitly set, use it as sandbox
PROJECT_ROOT = Path(env_root).resolve()
SANDBOX_MODE = True
elif WORKSPACE_ROOT and CONTAINER_WORKSPACE.exists():
# Running in Docker with workspace mounted
PROJECT_ROOT = CONTAINER_WORKSPACE
SANDBOX_MODE = True
else:
# If not set, default to home directory for safety
# This allows access to any file under the user's home directory
@@ -130,6 +141,45 @@ CODE_EXTENSIONS = {
}
def translate_docker_path(path_str: str) -> str:
"""
Translate host paths to container paths when running in Docker.
When running in Docker with WORKSPACE_ROOT set, this function translates
absolute paths from the host filesystem to their equivalent paths inside
the container. This enables seamless operation where Claude sends host
paths but the server runs in a container.
Args:
path_str: Original path string from the client
Returns:
Translated path string (unchanged if not in Docker mode)
"""
if not WORKSPACE_ROOT or not CONTAINER_WORKSPACE.exists():
# Not running in Docker mode, return path unchanged
return path_str
try:
# Resolve both paths to handle different path formats (forward/backslashes)
workspace_root_path = Path(WORKSPACE_ROOT).resolve()
host_path = Path(path_str).resolve()
# Get the relative path from workspace root
relative_path = host_path.relative_to(workspace_root_path)
# Construct container path using forward slashes (Linux format in container)
container_path = CONTAINER_WORKSPACE / relative_path
return container_path.as_posix()
except ValueError:
# Path is not within the workspace root, return unchanged
return path_str
except Exception:
# Any other error (invalid path, etc.), return unchanged
return path_str
def resolve_and_validate_path(path_str: str) -> Path:
"""
Validates that a path is absolute and resolves it.
@@ -149,6 +199,9 @@ def resolve_and_validate_path(path_str: str) -> Path:
ValueError: If path is not absolute
PermissionError: If path is outside allowed directory
"""
# Translate Docker paths if necessary
path_str = translate_docker_path(path_str)
# Create a Path object from the user-provided path
user_path = Path(path_str)