Skip to main content
Glama
README.md
# docker-mcp

A read-only MCP server for Docker. Exposes your Docker daemon over the [Model Context Protocol](https://modelcontextprotocol.io/) so AI assistants can inspect containers and logs without any write access.

Built with [FastAPI](https://fastapi.tiangolo.com/) and [FastMCP](https://github.com/jlowin/fastmcp).

## Tools

| Tool | Description |
|------|-------------|
| `list_containers` | List running containers (pass `all=true` to include stopped) |
| `get_container` | Full details for a container — ports, networks, env vars, mounts, resource limits |
| `get_logs` | Fetch container logs with filtering by tail/head, time range, and regex pattern |

### `get_logs` parameters

| Parameter | Default | Description |
|-----------|---------|-------------|
| `container_id` | — | Container ID or name |
| `tail` | `100` | Last N lines. Mutually exclusive with `head`. |
| `head` | — | First N lines. Mutually exclusive with `tail`. |
| `since` | — | UTC datetime — only return logs after this time |
| `until` | — | UTC datetime — only return logs before this time |
| `last_minutes` | — | Convenience shorthand: logs from the last N minutes |
| `pattern` | — | Regex (or substring) filter applied to log lines |
| `timestamps` | `true` | Prefix each line with an RFC3339 timestamp |

## Quick start

### Docker run

```bash
docker run -d \
  --name docker-mcp \
  -p 8000:8000 \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -e MCP_API_KEY=mysecret \
  codeberg.org/jhot/docker-mcp:latest
```

### Docker Compose

```yaml
services:
  docker-mcp:
    image: codeberg.org/jhot/docker-mcp:latest
    ports:
      - "8000:8000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      MCP_API_KEY: ${MCP_API_KEY:-}
    restart: unless-stopped
```

```bash
MCP_API_KEY=mysecret docker compose up -d
```

## Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `MCP_API_KEY` | unset | Bearer token for `/mcp`. Unset = no auth. |
| `DOCKER_HOST` | unset | Docker daemon socket. Unset = `/var/run/docker.sock`. |
| `HOST` | `0.0.0.0` | Uvicorn bind address |
| `PORT` | `8000` | Host port (container always listens on 8000) |
| `LOG_LEVEL` | `info` | Uvicorn log level |

## MCP endpoint

The MCP Streamable HTTP endpoint is at `http://localhost:8000/mcp`.

Configure your client (e.g. Claude Desktop, Cursor) to connect to it:

```json
{
  "mcpServers": {
    "docker": {
      "url": "http://localhost:8000/mcp",
      "headers": {
        "Authorization": "Bearer mysecret"
      }
    }
  }
}
```

Omit `headers` if `MCP_API_KEY` is not set.

## Security

The Docker socket grants full control of the Docker daemon. Treat access to this server the same as access to the socket itself:

- Set `MCP_API_KEY` for any network-accessible deployment.
- Use a firewall or reverse proxy to restrict which clients can reach port 8000.
- The `:ro` socket mount prevents replacing the socket file but does not restrict Docker API calls — `MCP_API_KEY` is the primary access control.

## Remote Docker

To connect to a remote Docker daemon instead of the local socket, remove the `volumes` block and set `DOCKER_HOST`:

```bash
docker run -d \
  --name docker-mcp \
  -p 8000:8000 \
  -e DOCKER_HOST=tcp://192.168.1.10:2376 \
  -e MCP_API_KEY=mysecret \
  codeberg.org/jhot/docker-mcp:latest
```

## Routes

| Path | Auth | Description |
|------|------|-------------|
| `/` | public | Landing page |
| `/health` | public | `{"status": "ok"}` |
| `/api/tools` | public | Tool metadata list |
| `/mcp` | gated | FastMCP Streamable HTTP endpoint |

## Development

Requirements: [mise](https://mise.jdx.dev/), Python 3.12, Docker

```bash
mise exec -- task install   # uv sync
mise exec -- task fmt        # ruff format
mise exec -- task lint       # ruff check
mise exec -- task test       # unit tests (no Docker required)
mise exec -- task test-integration  # integration tests (requires live Docker)
mise exec -- task run        # dev server at http://localhost:8000
mise exec -- task build      # docker build
mise exec -- task up         # docker compose up --build
```