gitaiflow / MCP / gitaiflow MCP — Docker Verification
DocsgitaiflowMCPgitaiflow MCP — Docker Verification

gitaiflow MCP — Docker Verification

This is the canonical Docker verification procedure for v1.1.3.

6 min readApplies to v1.1.3Added in 1.1.3
On this page ▾
  1. 1. What Docker is proving
  2. 2. Confirm Docker architecture
  3. 3. Resolve the host repository workspace
  4. 4. Build the image
  5. 5. Start the Docker HTTP server
  6. ARM64 example
  7. AMD64
  8. Important
  9. 6. Verify the container and effective environment
  10. 7. Verify the AOT binary
  11. 8. Verify the multi-repository workspace
  12. Why this check matters
  13. 9. Verify health
  14. 10. Verify direct AOT execution
  15. 11. Verify MCP initialize
  16. 12. Verify an actual MCP tool
  17. Docker path rule
  18. 13. Verify Docker MCP Inspector
  19. 14. Docker stdio smoke test
  20. 15. Docker state persistence

The procedure assumes a developer workspace containing multiple independent Git repositories. The parent workspace is mounted at /workspace; the individual repository selected by MCP must have its own .git directory.

Do not use older mixed Docker commands from historical documentation. Follow this document in order.


1. What Docker is proving

Docker adds a new runtime boundary:

For example, the host may contain:

text
/Users/<user>/pyc/missionmq/gl/
├── gitaiflow/.git
├── djangoplay-cli/.git
├── astwire/.git
├── issuetracker/.git
└── ...

and Docker exposes it as:

text
/workspace/
├── gitaiflow/.git
├── djangoplay-cli/.git
├── astwire/.git
├── issuetracker/.git
└── ...

/workspace is the allowed workspace container. It does not need to be a Git repository itself.

The selected path must be a real Git repository root. For example:

text
path="gitaiflow"
    ↓
/workspace/gitaiflow
    ↓
Git root = /workspace/gitaiflow

The Docker test is not complete merely because the container starts.

The required sequence is:

text
host parent workspace
    ↓
Docker image
    ↓
container
    ↓
AOT binary
    ↓
repository mount
    ↓
selected Git repository
    ↓
health
    ↓
direct AOT
    ↓
MCP protocol
    ↓
Inspector

2. Confirm Docker architecture

Check the image architecture:

bash
docker run --rm gitaiflow-mcp:local uname -m

Typical results:

text
aarch64

or:

text
x86_64

Use the matching Linux AOT binary.

For ARM64:

text
installers/AOT/v1.1.3/gitaiflow-linux-arm64

For AMD64:

text
installers/AOT/v1.1.3/gitaiflow-linux-amd64

3. Resolve the host repository workspace

The Docker mount should be the parent directory containing the repositories you want MCP to access.

If your repositories are under:

text
/Users/<user>/pyc/missionmq/gl/

define:

bash
export MCP_HOST_WORKSPACE="/Users/<user>/pyc/missionmq/gl"
printf 'Docker host workspace: %s\n' "$MCP_HOST_WORKSPACE"

Do not use an arbitrary current working directory.

In particular, this is unsafe for a multi-repository workspace:

bash
-v "$PWD:/workspace"

If $PWD is .../gl/gitaiflow, only that repository is mounted as /workspace and sibling repositories disappear from the Docker view.

Instead use the explicit parent workspace:

bash
-v "$MCP_HOST_WORKSPACE:/workspace"

4. Build the image

bash
docker build --no-cache -f Dockerfile.mcp -t gitaiflow-mcp:local .

5. Start the Docker HTTP server

ARM64 example

bash
docker rm -f gitaiflow-mcp 2>/dev/null || true

docker run --rm \
  --name gitaiflow-mcp \
  -p 8080:8080 \
  --env-file .mcp.env \
  -e MCP_TRANSPORT=streamable-http \
  -e MCP_WORKSPACE=/workspace \
  -e MCP_ALLOWED_WORKSPACES=/workspace \
  -e GITAIFLOW_BINARY=/app/bin/gitaiflow \
  -e MCP_RATE_LIMIT=100 \
  -v "$HOME/.gitaiflow:/root/.gitaiflow" \
  -v "$MCP_HOST_WORKSPACE:/workspace" \
  -v "$MCP_HOST_WORKSPACE/gitaiflow/installers/AOT/v1.1.3/gitaiflow-linux-arm64:/app/bin/gitaiflow:ro" \
  gitaiflow-mcp:local

For a different repository checkout, adjust the AOT source path to that checkout's versioned binary. The workspace mount must continue to point at the parent multi-repository directory.

AMD64

Replace the AOT mount with:

bash
-v "$MCP_HOST_WORKSPACE/gitaiflow/installers/AOT/v1.1.3/gitaiflow-linux-amd64:/app/bin/gitaiflow:ro"

Important

For the v1.1.3 local verification image, explicitly mount the versioned AOT binary.

Do not assume:

text
GITAIFLOW_BINARY=/app/bin/gitaiflow

means the file exists. Verify it.


6. Verify the container and effective environment

From a second terminal:

bash
docker ps --filter name=gitaiflow-mcp
docker logs gitaiflow-mcp

Then inspect the actual workspace mount:

bash
docker exec gitaiflow-mcp sh -c '
mount | grep workspace || true
'

Then inspect the effective container configuration:

bash
docker exec gitaiflow-mcp sh -c '
echo "MCP_TRANSPORT=$MCP_TRANSPORT"
echo "MCP_WORKSPACE=$MCP_WORKSPACE"
echo "MCP_ALLOWED_WORKSPACES=$MCP_ALLOWED_WORKSPACES"
echo "MCP_EXECUTION_TIMEOUT=$MCP_EXECUTION_TIMEOUT"
echo "MCP_RATE_LIMIT=$MCP_RATE_LIMIT"
echo "GITAIFLOW_BINARY=$GITAIFLOW_BINARY"
'

Expected Docker values include:

text
MCP_WORKSPACE=/workspace
MCP_ALLOWED_WORKSPACES=/workspace
GITAIFLOW_BINARY=/app/bin/gitaiflow

If .mcp.env contains host paths, that is fine. The explicit -e values override those variables inside the Docker container.


7. Verify the AOT binary

bash
docker exec -it gitaiflow-mcp sh -c '
ls -lh /app/bin/gitaiflow
/app/bin/gitaiflow --version
'

Expected:

text
gitaiflow 1.1.3

If you get:

text
/app/bin/gitaiflow: not found

stop here.

The container is running, but the AOT boundary is not configured.

Do not troubleshoot MCP yet.


8. Verify the multi-repository workspace

First verify the parent workspace exists:

bash
docker exec gitaiflow-mcp sh -c '
echo "=== WORKSPACE ==="
ls -lad /workspace
'

Then verify the repository you intend to call:

bash
docker exec gitaiflow-mcp sh -c '
echo "=== GITAIFLOW ==="
ls -lad /workspace/gitaiflow
ls -lad /workspace/gitaiflow/.git

echo
echo "=== GITAIFLOW ROOT ==="
git -C /workspace/gitaiflow rev-parse --show-toplevel

echo
echo "=== OTHER REPO ==="
git -C /workspace/djangoplay-cli rev-parse --show-toplevel
'

Expected:

text
/workspace/gitaiflow/.git
/workspace/gitaiflow
/workspace/djangoplay-cli

This proves that Docker sees the sibling repositories independently.

If /workspace/gitaiflow/.git is missing, do not change MCP workspace validation. Fix the Docker mount first.

Why this check matters

If you start Docker from inside .../gl/gitaiflow with:

bash
-v "$PWD:/workspace"

the container will see:

text
/workspace/.git

and there will be no /workspace/gitaiflow/.git. Git will therefore report /workspace as the repository root. That is a mount-layout problem, not an MCP validation problem.


9. Verify health

bash
curl -i http://localhost:8080/health

Expected:

text
HTTP/1.1 200 OK

and:

json
{
  "status": "ok",
  "service": "gitaiflow",
  "version": "1.1.3"
}

Health proves MCP is alive. It does not prove the AOT binary or repository selection works.


10. Verify direct AOT execution

This deliberately bypasses MCP.

For the selected gitaiflow repository:

bash
docker exec -it gitaiflow-mcp sh -c \
  'cd /workspace/gitaiflow && /app/bin/gitaiflow --last-summary'

This must succeed before MCP tool testing.

You can also verify:

bash
docker exec -it gitaiflow-mcp sh -c \
  'cd /workspace/gitaiflow && /app/bin/gitaiflow --release-notes'

and:

bash
docker exec -it gitaiflow-mcp sh -c \
  'cd /workspace/gitaiflow && /app/bin/gitaiflow --usage current'

11. Verify MCP initialize

Only after the previous checks pass:

bash
curl -i -X POST http://localhost:8080/mcp \
  -H "Authorization: Bearer $MCP_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"docker-local-test","version":"1.0.0"}}}'

Capture:

text
Mcp-Session-Id
bash
export MCP_SESSION_ID="<Mcp-Session-Id from initialize>"

12. Verify an actual MCP tool

For a multi-repository Docker workspace, select the repository by name:

bash
curl -i -X POST http://localhost:8080/mcp \
  -H "Authorization: Bearer $MCP_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: $MCP_SESSION_ID" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"gitaiflow_last_summary","arguments":{"path":"gitaiflow"}}}'

Expected:

text
HTTP 200

with an MCP result containing:

text
status: ok

You can similarly select another repository:

json
{"path":"djangoplay-cli"}

The selected directory must be its own Git repository root.

Docker path rule

For the multi-repository layout:

text
MCP_ALLOWED_WORKSPACES=/workspace

means /workspace is the allowed parent workspace. The path argument selects a repository beneath it:

text
path="gitaiflow"
    → /workspace/gitaiflow

path="djangoplay-cli"
    → /workspace/djangoplay-cli

Do not replace the multi-repository mount with an individual repository just to make one tool call work.


13. Verify Docker MCP Inspector

Only after the direct MCP call succeeds.

See:

text
MCP-INSPECTOR-VERIFICATION.md

Connect to:

text
http://localhost:8080/mcp

with:

text
Authorization: Bearer <MCP_API_TOKEN>

14. Docker stdio smoke test

Claude Desktop uses stdio, not HTTP.

Use the same multi-repository parent workspace:

bash
docker run --rm -i \
  --env-file .mcp.env \
  -e MCP_TRANSPORT=stdio \
  -e MCP_WORKSPACE=/workspace \
  -e MCP_ALLOWED_WORKSPACES=/workspace \
  -e GITAIFLOW_BINARY=/app/bin/gitaiflow \
  -v "$HOME/.gitaiflow:/root/.gitaiflow" \
  -v "$MCP_HOST_WORKSPACE:/workspace" \
  -v "$MCP_HOST_WORKSPACE/gitaiflow/installers/AOT/v1.1.3/gitaiflow-linux-arm64:/app/bin/gitaiflow:ro" \
  gitaiflow-mcp:local

Expected:

text
stdio transport starts
no Uvicorn listener
no HTTP port is required

Use the matching AOT binary for the container architecture.


15. Docker state persistence

After a command that records usage:

bash
docker exec -it gitaiflow-mcp sh -c \
  'test -f /root/.gitaiflow/usage.jsonl && tail -n 5 /root/.gitaiflow/usage.jsonl'

The same state should be visible on the host:

bash
ls -l "$HOME/.gitaiflow/usage.jsonl"
tail -n 5 "$HOME/.gitaiflow/usage.jsonl"