MCP Dockhand
Provides comprehensive management of Docker infrastructure, including tools for containers, stacks, images, networks, and volumes across multiple host environments.
Enables management of Git-based stacks, allowing for the deployment, synchronization, and configuration of repositories and credentials for containerized applications.
Supports vulnerability scanning of Docker images through integration with security tools like Trivy.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Dockhandshow me the logs for the nginx container in the production environment"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Dockhand
An MCP (Model Context Protocol) server that exposes the Dockhand API as MCP tools. Manage your entire Docker infrastructure through AI assistants.
API coverage: 88.7% of in-scope Dockhand endpoints (282/318) have an MCP tool — see docs/coverage.md for the full, auto-updated breakdown by area.
Dockhand is a Docker management server that connects to multiple Docker hosts via Hawser agents. This MCP server provides full programmatic access to all Dockhand features.
Features
280+ MCP Tools covering the Dockhand API — see
docs/coverage.mdfor exact, auto-updated coverageStreamable HTTP Transport (MCP Spec 2025-03-26) for Docker container hosting
Session-based Auth with auto-relogin on 401
SSE Support for deploy operations (start, stop, down, restart)
Environment Filter enforced on all container/stack/image/network/volume endpoints
Docker Ready with multi-stage build, non-root user, and health checks
Related MCP server: Portainer MCP Server
Quick Start
Docker (recommended)
docker run -d \
--name mcp-dockhand \
-p 8080:8080 \
-e DOCKHAND_URL=https://your-dockhand-server.com \
-e DOCKHAND_USERNAME=your-username \
-e DOCKHAND_PASSWORD=your-password \
ghcr.io/strausmann/mcp-dockhand:latestDocker Compose
services:
mcp-dockhand:
image: ghcr.io/strausmann/mcp-dockhand:latest
container_name: mcp-dockhand
restart: unless-stopped
ports:
- "8080:8080"
environment:
- DOCKHAND_URL=https://your-dockhand-server.com
- DOCKHAND_USERNAME=your-username
- DOCKHAND_PASSWORD=your-passwordFrom Source
git clone https://github.com/strausmann/mcp-dockhand.git
cd mcp-dockhand
npm install
npm run build
DOCKHAND_URL=https://your-server.com DOCKHAND_USERNAME=admin DOCKHAND_PASSWORD=secret npm startConfiguration
Variable | Required | Default | Description |
| Yes | - | Dockhand server URL |
| Yes | - | Dockhand username |
| Yes | - | Dockhand password |
| No |
| Port for the MCP server |
| No |
| Inactivity timeout before a retained MCP session is expired |
| No |
| Interval for removing expired sessions (clamped to the session TTL) |
| No |
| Maximum retained sessions; |
| No |
| Listen address. Kept as the wildcard address by default so the published Docker port ( |
| No | (unset — Host check disabled) | Comma-separated |
| No | (unset — Origin check disabled) | Comma-separated |
| No | (unset — endpoint unauthenticated) | Shared secret required as |
| No |
| Log level |
Securing the transport
/mcp binds 0.0.0.0:8080 by default (see MCP_HOST above), and out of the box — with none of
MCP_ALLOWED_HOSTS, MCP_ALLOWED_ORIGINS, or MCP_AUTH_TOKEN set — it accepts any request
with no Host/Origin check and no authentication. This is the same behavior mcp-dockhand
has always had, kept as the default deliberately: enabling a check by default would reject
requests from any client that doesn't reach the server as localhost/127.0.0.1 (a LAN IP, a
reverse proxy, a Docker network alias), breaking existing deployments on a routine update.
You should turn this on once /mcp is reachable beyond your own machine's loopback interface
— the server holds one Dockhand admin credential and every tool call acts with that identity, so
anyone who can open an MCP session controls Docker (container exec, host bind-mounts via
create_container, file read/write, stored git credentials). With no protection configured, the
server logs a [security] WARNING at startup as a reminder. Three independent, all-opt-in layers
are available:
Host allowlist (
MCP_ALLOWED_HOSTS). Once set to a non-empty value, every request to/mcp—POST,GET, andDELETE— is rejected with403unless itsHostheader matches the allowlist. This is the primary defense against DNS-rebinding: a malicious web page cannot make the operator's browser reach the server under a Host value the allowlist accepts. Set it to however your client actually reaches the server —localhost:8080/127.0.0.1:8080for the documented local setup, or, if you connect directly by address rather than throughlocalhost(including the mcp-proxy remote-server setup below), the exacthost:portyour client sends, e.g.100.100.50.40:8222. Get this wrong and every request is rejected with403 Invalid Host header— check the message, it echoes the Host value it saw.Origin allowlist (
MCP_ALLOWED_ORIGINS). Once set, any request that does send anOriginheader not in the list is rejected with403. A missingOriginheader always passes (the SDK's own MCP client and most non-browser tooling never send one), so this is only useful if a browser-based client talks to/mcpdirectly; the Host allowlist above is what actually stops DNS-rebinding.Bearer token (
MCP_AUTH_TOKEN). Once set, every/mcprequest must carryAuthorization: Bearer <token>or is rejected with401; the comparison is constant-time. Recommended alongside the Host allowlist for any deployment reachable from more than the operator's own machine.
# .env — recommended configuration once /mcp is reachable beyond loopback
MCP_ALLOWED_HOSTS=dock-mcp.internal.example.com
# or, connecting directly by address instead of a hostname:
#MCP_ALLOWED_HOSTS=100.100.50.40:8222
MCP_AUTH_TOKEN=<a long random secret, e.g. `openssl rand -hex 32`>MCP Client Configuration
Claude Desktop / Claude Code
Add to your MCP settings:
{
"mcpServers": {
"dockhand": {
"url": "http://localhost:8080/mcp"
}
}
}If the server enforces a bearer token (
MCP_AUTH_TOKENset — see Securing the transport), the client must send it as anAuthorizationheader, or every request is rejected with401. In Claude Code's.mcp.json, add aheadersblock — reference an environment variable so the token never lives in the (often version-controlled) config file:{ "mcpServers": { "dockhand": { "type": "http", "url": "http://your-server:8080/mcp", "headers": { "Authorization": "Bearer ${DOCKHAND_MCP_TOKEN}" } } } }Send the token only over an encrypted transport. A bearer over plain
http://on a shared network can be sniffed — terminate TLS at a reverse proxy, or reach the server over a WireGuard/Tailscale/VPN link (the app-layer HTTP is then encrypted by the tunnel).Export
DOCKHAND_MCP_TOKENin the environment Claude Code is launched from (e.g. from a gitignored.envyousourcebefore starting). TheHost/host:portyou connect to must also be in the server'sMCP_ALLOWED_HOSTSif that allowlist is set. For Claude Desktop (native config has noheadersfield), pass the token through the mcp-proxy workaround below — mcp-proxy forwards anAuthorizationheader via its own environment/args.
Claude Desktop with a remote server (mcp-proxy)
Claude Desktop can fail to connect to a remote mcp-dockhand server (not
localhost) using the native "url" config above, even though the endpoint
itself is reachable. The symptom is a generic "not a valid MCP server" error
in Claude Desktop, while a plain browser/curl request to the same URL
correctly returns {"error":"Invalid or missing session ID"}. This is a known
limitation of Claude Desktop with remote Streamable HTTP servers, not a
mcp-dockhand bug.
Workaround: wrap the connection with mcp-proxy, which translates Streamable HTTP to stdio — a transport Claude Desktop handles reliably:
{
"mcpServers": {
"dockhand": {
"command": "/path/to/mcp-proxy",
"args": ["--transport", "streamablehttp", "http://your-server:8080/mcp"]
}
}
}All tools load and work correctly through the proxy. Thanks to @deadrubberboy for reporting this and sharing the workaround (#90).
Tool Reference
Containers (27 tools)
Tool | Description |
| List all containers in an environment |
| Get container details |
| Docker inspect (full details) |
| Get container logs |
| Get resource usage stats |
| Get running processes |
| Start a container |
| Stop a container |
| Restart a container |
| Pause a container |
| Unpause a container |
| Rename a container |
| Update container settings |
| Create a new container |
| List available shells |
| Create a terminal exec session (execId + WS connectionInfo); does NOT run a one-shot command or return output — no such endpoint exists in the Dockhand API |
| Browse files inside container |
| Read file from container |
| Create an empty file or directory in container (no content — use |
| Delete file in container |
| Rename file in container |
| Change file permissions |
| Check for image updates |
| Get pending updates |
| Batch update containers |
| Run a bulk lifecycle operation (start/stop/restart/remove/etc.) across containers, images, volumes, networks, or stacks |
| Get container disk sizes |
| Get aggregated stats |
Stacks (21 tools)
Tool | Description |
| List all stacks |
| Get stack details |
| Create and optionally deploy a stack |
| Start a stack (compose up) |
| Stop a stack (compose stop) |
| Restart a stack |
| Take down a stack (compose down) |
| Delete a stack |
| Read compose file |
| Update compose file |
| Read environment variables |
| Update environment variables (merge by default — safe for partial updates; use |
| Read raw .env file |
| Validate env variables |
| Scan filesystem for stacks |
| Adopt an untracked stack |
| Move stack to new path |
| Get stack sources |
| Get base path |
| Get path suggestions |
| Validate a stack path |
Images (9 tools)
Tool | Description |
| List all images |
| Get image details |
| Get image layer history |
| Tag an image |
| Remove an image |
| Pull an image |
| Push an image |
| Vulnerability scan (Trivy/Grype) |
| Export image as tarball |
Environments (18 tools)
Tool | Description |
| List all environments |
| Get environment details |
| Create an environment |
| Update an environment |
| Delete an environment |
| Test connection |
| Test without saving |
| Auto-detect socket |
| Get timezone |
| Set timezone |
| Get update-check settings |
| Set update-check settings |
| Get image prune settings |
| Set image prune settings |
| List notifications |
| Create notification |
| Get notification |
| Delete notification |
Networks (7 tools)
Tool | Description |
| List all networks |
| Get network details |
| Inspect network |
| Create a network |
| Remove a network |
| Connect container |
| Disconnect container |
Volumes (9 tools)
Tool | Description |
| List all volumes |
| Get volume details |
| Inspect volume |
| Browse files in volume |
| Read file from volume |
| Release browse session |
| Clone a volume |
| Export volume |
| Remove volume (destructive) |
Git Stacks (15 tools)
Tool | Description |
| List Git-based stacks |
| Get Git stack details |
| Deploy a Git stack (SSE) |
| Sync with remote repo |
| Test Git connection |
| Get env files |
| Trigger webhook |
| Get webhook details |
| List Git credentials |
| Create Git credential |
| Get credential details |
| Update credential |
| Delete credential |
| List Git repositories |
| Create repository config |
Dashboard & Activity (8 tools)
Tool | Description |
| Get dashboard statistics |
| Get display preferences |
| Set display preferences |
| Get activity feed |
| Container activity |
| Activity events |
| Activity statistics |
| Merged logs from containers |
Auth & Hawser (12 tools)
Tool | Description |
| Check session status |
| List auth providers |
| Get auth settings |
| Create OIDC provider |
| Get OIDC provider |
| Test OIDC provider |
| Create LDAP provider |
| Get LDAP provider |
| Test LDAP provider |
| List Hawser tokens |
| Create Hawser token |
| Revoke Hawser token |
Audit (4 tools)
Tool | Description |
| Get audit log |
| Get audit event types |
| Audit data by user |
| Export audit log |
Notifications (8 tools)
Tool | Description |
| List notifications |
| Create notification |
| Get notification |
| Update notification |
| Delete notification |
| Test notification |
| Test without saving |
| Trigger a real test event for a given event type + payload |
Registries (10 tools)
Tool | Description |
| List registries |
| Add registry |
| Get registry details |
| Update registry |
| Delete registry |
| Set as default |
| Search registry |
| Get catalog |
| Get image from registry |
| Get image tags |
System & Settings (19 tools)
Tool | Description |
| Server health |
| Database health |
| Host information |
| System information |
| Disk usage |
| List system files |
| Read system file |
| Changelog |
| Dependencies |
| General settings |
| Update settings |
| Theme settings |
| Update theme |
| Scanner settings |
| Update scanner |
| License info |
| Activate license by name and key |
| Prometheus metrics |
| Prune all resources |
Users, Roles & Preferences (20 tools)
Tool | Description |
| List users |
| Create user |
| Get user details |
| Update user |
| Delete user |
| MFA status |
| Enable MFA |
| Disable MFA |
| Get user roles |
| Assign one role to a user (no bulk-replace) |
| Unassign one role from a user |
| List roles |
| Create role with name + permissions object |
| Get role |
| Update role |
| Delete role |
| Get own profile |
| Update own profile |
| Get favorites |
| Set favorites |
| List config sets |
Schedules (9 tools)
Tool | Description |
| List schedules |
| Get settings |
| Update settings |
| Execution history |
| Execution details |
| Get schedule |
| Run immediately |
| Enable/disable |
| Toggle system schedule |
Auto-Update (3 tools)
Tool | Description |
| Get all auto-update settings |
| Get container auto-update |
| Set auto-update policy |
Self-help / meta tools (6 tools)
Diagnostics for this MCP server itself, distinct from the Dockhand API tools above —
useful for a client or operator asking "is this server healthy and correctly configured?"
rather than "is Dockhand healthy?". None of these six take any input arguments, and none of
them wrap a single Dockhand endpoint the way the tables above do (get_tool_manifest and
get_runtime_stats call no Dockhand endpoint at all) — see src/tools/meta.ts.
Tool | Description |
| This server's own version, git SHA, build date, uptime, MCP protocol version, and the Dockhand URL/server version it's connected to |
| Compares this server's running version against the latest GitHub release (TTL-cached) |
| Lists every registered tool with its Dockhand |
| End-to-end diagnostic: Dockhand reachability, credential validity, and a live, per-environment reachability check ( |
| Checks that the required |
| In-process counters for this server: total/per-tool call and error counts, uptime, and the last error's tool/message/timestamp |
Notes:
check_for_updateneeds outbound network access toapi.github.com(GitHub's releases API) — it will degrade toupdateAvailable: nullrather than fail if that's unreachable.No meta tool exposes any secret value.
validate_configreports only whether the required env vars are present (booleans) and whether they authenticate (a boolean + the raw HTTP status code, e.g.200/401) — never the credential values themselves.self_checkreports auth validity the same way.get_runtime_stats'lastErrorcarries only a tool name, an error message, and a timestamp — never call arguments or response payloads. That error message is not fully opaque, though: for a failed Dockhand API call it can embed a slice of the upstream HTTP status and response body (viaDockhandClient's ownDockhand API error: ... returned <status>: <body>message), and it is echoed to whichever MCP client next callsget_runtime_stats— not necessarily the one that hit the original error. It never includes request bodies or credential values, and it is truncated to 500 characters (with an ellipsis marker) before being stored, so an oversized upstream response is never echoed wholesale.
Important Notes
update_stack_env — Merge vs Replace Semantics
The Dockhand REST endpoint PUT /api/stacks/{name}/env has replace-semantics: submitting a partial list of variables silently deletes all other variables from the stack. A single-variable update would wipe everything else.
To prevent accidental data loss, this MCP tool defaults to merge mode:
It fetches the current variable list via
GET /api/stacks/{name}/env.It merges the incoming variables by key (new values overwrite existing ones on key collision).
It writes the full combined list back via
PUT.
# Safe partial update — only MY_VAR changes, all others preserved
update_stack_env(environmentId=1, name="my-stack", variables=[{key: "MY_VAR", value: "new"}])
# Explicit full replacement — all other variables are deleted
update_stack_env(environmentId=1, name="my-stack", variables=[...], mode="replace")Use mode="replace" only when you intentionally want to replace the entire variable set.
Environment ID is Required
Most Docker resource endpoints (containers, stacks, images, networks, volumes) require an environmentId parameter. This maps to the ?env=<id> query parameter in the Dockhand API. Without it, endpoints return empty arrays.
SSE Responses
Deploy operations (start, stop, down, restart, compose update with restart) return Server-Sent Events. The MCP server automatically parses these and returns the final result.
Authentication
The server uses session-based cookie authentication. It automatically:
Logs in on first request
Stores the session cookie in memory
Re-authenticates on 401 responses
Handles session timeout (24h)
Development
# Install dependencies
npm install
# Type check
npm run typecheck
# Build
npm run build
# Run in development mode
DOCKHAND_URL=https://your-server.com \
DOCKHAND_USERNAME=admin \
DOCKHAND_PASSWORD=secret \
npm run devLinting
There is currently no npm run lint script. typescript-eslint (the only maintained
ESLint/TypeScript integration) does not yet support the pinned typescript@^7.0.2
devDependency — it refuses to run at all against TS 7.0 (hard runtime error, not just a
peer-dependency warning): see
typescript-eslint#10940.
Re-add eslint + typescript-eslint as devDependencies once that's resolved upstream —
tsc --noEmit (via npm run typecheck) is the only static check enforced today.
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceEnables AI assistants to manage Docker containers, deploy stacks, and monitor services across multiple Docker hosts from one centralized location. Supports container lifecycle management, Docker Compose operations, and infrastructure orchestration through natural language commands.6MIT
- Flicense-qualityDmaintenanceEnables AI assistants to manage Docker containers, stacks, images, volumes, and networks through Portainer's API. Supports listing resources, viewing logs, and performing container operations with configurable write permissions.1
- Alicense-qualityFmaintenanceExposes the Dockhand Docker management API as tools for LLMs, enabling container, stack, image, volume, and network management via natural language.3MIT
- AlicenseBqualityDmaintenanceEnables AI assistants to manage Docker containers, images, volumes, networks, and compose projects through Arcane's API. Provides comprehensive tools for environment, container, image, volume, network, project, and system operations.5215MIT
Related MCP Connectors
Universal AI API Orchestrator — 1,554 tools, 96 services. One install.
Provides cloud browser automation capabilities using Stagehand and Browserbase, enabling LLMs to i…
SaaS intelligence for AI agents. 5 unified tools cover 1,000+ services with 91-96% token savings.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/strausmann/mcp-dockhand'
If you have feedback or need assistance with the MCP directory API, please join our Discord server