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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,7 @@ coverage/
repomix-output*
mcp-servers.json
mcp-config.json

# AI Agents

.claude/
59 changes: 41 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,69 @@
# Use a specific Node.js version known to work, Alpine for smaller size
FROM node:23-alpine AS base
WORKDIR /usr/src/app
ENV NODE_ENV=production

# ---- Dependencies ----
# Install dependencies first to leverage Docker cache
FROM base AS deps
WORKDIR /usr/src/app
COPY package.json package-lock.json* ./
# Use npm ci for deterministic installs based on lock file
# Install only production dependencies in this stage for the final image
RUN npm ci --only=production
ENV MCP_TRANSPORT_TYPE=http
ARG MCP_HTTP_HOST=0.0.0.0
ENV MCP_HTTP_HOST=${MCP_HTTP_HOST}
ARG MCP_HTTP_PORT=3015
ENV MCP_HTTP_PORT=${MCP_HTTP_PORT}
ARG MCP_LOG_LEVEL=info
ENV MCP_LOG_LEVEL=${MCP_LOG_LEVEL}

# Force to log to console
ENV MCP_LOG_LEVEL=info

# ---- Builder ----
# Build the application
FROM base AS builder
WORKDIR /usr/src/app
# Copy dependency manifests and install *all* dependencies (including dev)
COPY package.json package-lock.json* ./
RUN npm ci
# Copy the rest of the source code
COPY . .

RUN npm ci
# Build the TypeScript project
RUN npm run build
RUN npm run postbuild

# ---- Production Dependencies ----
# Install only production dependencies for the final image
FROM base AS prod-deps
WORKDIR /usr/src/app
COPY package.json package-lock.json* ./
RUN npm ci --only=production

# ---- Runner ----
# Final stage with only production dependencies and built code
FROM base AS runner
WORKDIR /usr/src/app
# Copy production node_modules from the 'deps' stage
COPY --from=deps /usr/src/app/node_modules ./node_modules
# Copy production node_modules from the 'prod-deps' stage
COPY --from=prod-deps /usr/src/app/node_modules ./node_modules
# Copy built application from the 'builder' stage
COPY --from=builder /usr/src/app/dist ./dist
# Copy package.json (needed for potential runtime info, like version)
COPY package.json .

# Create a non-root user and switch to it
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# Add git to the container
RUN apk update
RUN apk add git

# Expose port if the application runs a server (adjust if needed)
# EXPOSE 3000
# This seems to need to exist, though we really just want to log to the console
RUN mkdir logs && chmod 777 logs

COPY ./scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

# In this base image "node" is 1000:1000. It doesn't matter what user is used to run the server;
# rather the user ID should match the uid/gid of the host user so that the server can
# read and write files in the volume mount.
RUN chmod 777 /home/node
ENV HOME=/home/node
USER node:node

ENV NODE_ENV=production
EXPOSE ${MCP_HTTP_PORT}

# Command to run the application
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["node", "dist/index.js"]
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ Add the following to your MCP client's configuration file (e.g., `cline_mcp_sett
npm install @cyanheads/git-mcp-server
```

### 3. Running the Server
##### Running the Server

- **Production (Stdio):**
```bash
Expand All @@ -139,6 +139,44 @@ npm install @cyanheads/git-mcp-server
npm run dev:http
```

### Installing with Docker

You can use the Dockerfile to create an image that hosts the mcp server. To build:

```sh
./scripts/build-docker.sh
```

Once complete, run the docker container. Refer to the example [docker-compose](./scripts/docker-compose.example.yaml) to create a docker compose file for your container. Once completed you can start the server with, for example, if you've put a file called `docker-compose.git-mcp.yaml` in your home directory;


```sh
docker compose -f ~/docker-compose.git-mcp.yaml up -d
```

#### Considerations when running with docker

Your local file system is made available to the server in Docker using a volume mount. This doesn't change the permissions; it appears inside the container
with the same uid/gid as your host machine.

##### Privileges to read/write files in the mount

The docker image MUST be built with the same uid/gid as your active user using the server. Otherwise, it may not be able to access the files on the mount. The build script should configure this correctly.

You need to add a volume that exposes the root of the git repos you plan to work with. The best strategy for this depends on the operating system

##### Linux/Mac/WSL

It's recommended that you configure the volume at the same path inside the container as the actual path on your computer. This way agents are likely to find your repositories easily since the path will be the same as from the host where it's making the request.

##### Windows

If you're using Windows, this won't work, since the paths may include drive letters or UNC paths.

- Repos in the WSL filesystem work the same way as linux/mac
- Repos in the windows filesystem will need to be accessed through the WSL mount, e.g. `/mnt/c` for the C drive. Since paths won't map the same way as the do in *nix type systems, I'd suggest making a volume called `/windows-code` or similar. Agents can be trained to map windows paths to this root when querying the server.


## ⚙️ Configuration

Configure the server using these environment variables (or a `.env` file):
Expand Down
6 changes: 6 additions & 0 deletions scripts/build-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
VERSION=$(grep -m 1 "^## v" CHANGELOG.md | sed 's/^## v\([0-9.]*\).*/\1/')
docker build --no-cache\
-t git-mcp-server:$VERSION \
-t git-mcp-server:latest \
.
22 changes: 22 additions & 0 deletions scripts/docker-compose.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
services:
git-mcp-server:
image: git-mcp-server
container_name: gitmcp
ports:
- "3015:3015"
# Configure to run with the same user ID as the host user
user: "1000:1000"
environment:
# Git user configuration - set these to your Git user details
- GIT_USER_NAME=Your Name
- [email protected]
# Optional: Override other MCP settings
# - MCP_LOG_LEVEL=debug
# - GIT_SIGN_COMMITS=true
volumes:
# Use to expose your code base to the service.
# Example mount for linux/wsl/mac, replace <username> with your actual username.
- /home/<username>/code:/home/<username>/code
# Example mount for windows, replace <username> with your actual username.
- /mnt/c/Users/<username>/code:/windows-code
restart: unless-stopped
13 changes: 13 additions & 0 deletions scripts/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

# Configure Git user settings if environment variables are provided
if [ -n "$GIT_USER_EMAIL" ] && [ -n "$GIT_USER_NAME" ]; then
echo "Configuring Git user: $GIT_USER_NAME <$GIT_USER_EMAIL>"
git config --global user.email "$GIT_USER_EMAIL"
git config --global user.name "$GIT_USER_NAME"
else
echo "Warning: GIT_USER_EMAIL and/or GIT_USER_NAME not set. Git operations may fail without proper user configuration."
fi

# Execute the main command
exec "$@"