gitaiflow MCP — Docker Verification
This is the canonical Docker verification procedure for v1.1.3.
On this page ▾
- 1. What Docker is proving
- 2. Confirm Docker architecture
- 3. Resolve the host repository workspace
- 4. Build the image
- 5. Start the Docker HTTP server
- ARM64 example
- AMD64
- Important
- 6. Verify the container and effective environment
- 7. Verify the AOT binary
- 8. Verify the multi-repository workspace
- Why this check matters
- 9. Verify health
- 10. Verify direct AOT execution
- 11. Verify MCP initialize
- 12. Verify an actual MCP tool
- Docker path rule
- 13. Verify Docker MCP Inspector
- 14. Docker stdio smoke test
- 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:
flowchart TB
Host["Developer machine"]
Workspace["Host parent workspace"]
Container["Docker container"]
MCP["MCP server"]
AOT["/app/bin/gitaiflow"]
Repo["Selected Git repository"]
Config["$HOME/.gitaiflow"]
Workspace -->|bind mount| Container
Config -->|bind mount| Container
Container --> MCP
MCP --> AOT
AOT --> RepoFor example, the host may contain:
/Users/<user>/pyc/missionmq/gl/
├── gitaiflow/.git
├── djangoplay-cli/.git
├── astwire/.git
├── issuetracker/.git
└── ...and Docker exposes it as:
/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:
path="gitaiflow"
↓
/workspace/gitaiflow
↓
Git root = /workspace/gitaiflowThe Docker test is not complete merely because the container starts.
The required sequence is:
host parent workspace
↓
Docker image
↓
container
↓
AOT binary
↓
repository mount
↓
selected Git repository
↓
health
↓
direct AOT
↓
MCP protocol
↓
Inspector2. Confirm Docker architecture
Check the image architecture:
docker run --rm gitaiflow-mcp:local uname -mTypical results:
aarch64or:
x86_64Use the matching Linux AOT binary.
For ARM64:
installers/AOT/v1.1.3/gitaiflow-linux-arm64For AMD64:
installers/AOT/v1.1.3/gitaiflow-linux-amd643. 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:
/Users/<user>/pyc/missionmq/gl/define:
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:
-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:
-v "$MCP_HOST_WORKSPACE:/workspace"4. Build the image
docker build --no-cache -f Dockerfile.mcp -t gitaiflow-mcp:local .5. Start the Docker HTTP server
ARM64 example
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:localFor 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:
-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:
GITAIFLOW_BINARY=/app/bin/gitaiflowmeans the file exists. Verify it.
6. Verify the container and effective environment
From a second terminal:
docker ps --filter name=gitaiflow-mcp
docker logs gitaiflow-mcpThen inspect the actual workspace mount:
docker exec gitaiflow-mcp sh -c '
mount | grep workspace || true
'Then inspect the effective container configuration:
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:
MCP_WORKSPACE=/workspace
MCP_ALLOWED_WORKSPACES=/workspace
GITAIFLOW_BINARY=/app/bin/gitaiflowIf .mcp.env contains host paths, that is fine. The explicit -e values override those variables inside the Docker container.
7. Verify the AOT binary
docker exec -it gitaiflow-mcp sh -c '
ls -lh /app/bin/gitaiflow
/app/bin/gitaiflow --version
'Expected:
gitaiflow 1.1.3If you get:
/app/bin/gitaiflow: not foundstop 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:
docker exec gitaiflow-mcp sh -c '
echo "=== WORKSPACE ==="
ls -lad /workspace
'Then verify the repository you intend to call:
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:
/workspace/gitaiflow/.git
/workspace/gitaiflow
/workspace/djangoplay-cliThis 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:
-v "$PWD:/workspace"the container will see:
/workspace/.gitand 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
curl -i http://localhost:8080/healthExpected:
HTTP/1.1 200 OKand:
{
"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:
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:
docker exec -it gitaiflow-mcp sh -c \
'cd /workspace/gitaiflow && /app/bin/gitaiflow --release-notes'and:
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:
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:
Mcp-Session-Idexport 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:
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:
HTTP 200with an MCP result containing:
status: okYou can similarly select another repository:
{"path":"djangoplay-cli"}The selected directory must be its own Git repository root.
Docker path rule
For the multi-repository layout:
MCP_ALLOWED_WORKSPACES=/workspacemeans /workspace is the allowed parent workspace. The path argument selects a repository beneath it:
path="gitaiflow"
→ /workspace/gitaiflow
path="djangoplay-cli"
→ /workspace/djangoplay-cliDo 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:
MCP-INSPECTOR-VERIFICATION.mdConnect to:
http://localhost:8080/mcpwith:
Authorization: Bearer <MCP_API_TOKEN>14. Docker stdio smoke test
Claude Desktop uses stdio, not HTTP.
Use the same multi-repository parent workspace:
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:localExpected:
stdio transport starts
no Uvicorn listener
no HTTP port is requiredUse the matching AOT binary for the container architecture.
15. Docker state persistence
After a command that records usage:
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:
ls -l "$HOME/.gitaiflow/usage.jsonl"
tail -n 5 "$HOME/.gitaiflow/usage.jsonl"