The published image bundles everything the server shells out to — Terraform +
tflocal, AWS CDK + cdklocal, AWS SAM + samlocal, and the Snowflake snow
CLI — so the only dependency on your machine is Docker itself. LocalStack
lifecycle, logs, and awslocal run through the Docker Engine API and LocalStack's
REST APIs.
The image is multi-arch (linux/amd64 and linux/arm64).
The container talks to your host Docker daemon through the bind-mounted
/var/run/docker.sock. When you ask the server to start LocalStack, it creates a
sibling localstack-main container on the host (not nested inside the MCP
container) directly via the Docker API. Stop/restart operations act on the detected
sibling container the same way. The MCP server and the IaC CLIs reach that sibling
over the host gateway.
MCP client ── stdio ──► docker run … (MCP server)
│ /var/run/docker.sock (mounted)
▼
host Docker daemon
└─ localstack-main (sibling, publishes :4566 on the host)
Because LocalStack is a sibling container, one thing must be configured at run time:
- Reachability — set
LOCALSTACK_HOSTNAME=host.docker.internalso the server and the IaC CLIs target the sibling's published port instead of the container's ownlocalhost.
LocalStack state lives in a named Docker volume (localstack-mcp) by default,
so no host directory needs to be mounted or path-mirrored. To keep state in a host
directory instead, set -e LOCALSTACK_VOLUME_DIR=/absolute/host/path (the path is
interpreted by the host daemon).
Upgrading from an older image? Previous versions required a one-to-one cache mount plus
XDG_CACHE_HOME. Old configs keep working: whenXDG_CACHE_HOMEis set, the server keeps using$XDG_CACHE_HOME/localstack/volumefor state, so your persisted resources survive the upgrade. New configs need neither flag.
docker run -i --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--add-host s3.host.docker.internal:host-gateway \
--add-host snowflake.localhost.localstack.cloud:host-gateway \
-e LOCALSTACK_AUTH_TOKEN="<YOUR_TOKEN>" \
-e LOCALSTACK_HOSTNAME=host.docker.internal \
localstack/localstack-mcp-server:latest| Flag | Why it's needed |
|---|---|
-v /var/run/docker.sock:/var/run/docker.sock |
Lets the server create/stop/restart the sibling LocalStack container, read its logs, and run awslocal inside it. |
--add-host host.docker.internal:host-gateway |
Resolves host.docker.internal on Linux. Harmless on Docker Desktop (Mac/Windows), where it already resolves. |
--add-host s3.host.docker.internal:host-gateway |
Lets CDK's virtual-hosted S3 endpoint resolve when cdklocal uses AWS_ENDPOINT_URL_S3=http://s3.host.docker.internal:4566. |
--add-host snowflake.localhost.localstack.cloud:host-gateway |
Lets the Snowflake CLI reach the sibling Snowflake emulator through the hostname the emulator expects for routing. |
-e LOCALSTACK_AUTH_TOKEN |
Required by every tool in this server. |
-e LOCALSTACK_HOSTNAME=host.docker.internal |
Tells the server + IaC CLIs where the sibling LocalStack lives. |
MCP clients launch the server over stdio. Note that client config files do not
expand $HOME/$PWD — use absolute paths.
Deploys run inside the MCP container, so your project directory must be visible
there. Mount it and pass the in-container path to the localstack-deployer tool.
The simplest convention is to mount it at the same absolute path:
-v "/Users/you/projects/my-infra:/Users/you/projects/my-infra"
Then tell the tool directory: /Users/you/projects/my-infra.
Terraform, SAM, and CDK receive the LocalStack endpoint automatically when
LOCALSTACK_HOSTNAME=host.docker.internal is set. CDK asset publishing is forced
to path-style S3 inside the Docker image, so the single s3.host.docker.internal
alias covers bootstrap asset uploads.
- Extra host aliases. Include the aliases shown in the quick-start command.
- First cold start of LocalStack can take up to ~2 minutes while the image is pulled and the runtime initializes; subsequent starts reuse the persisted volume.
- Persistence across MCP restarts. The sibling
localstack-mainkeeps running on the host even if your editor restarts the MCP container — reconnecting finds your stack still up. State persists in thelocalstack-mcpnamed volume (orLOCALSTACK_VOLUME_DIRif you set one).
| Symptom | Cause / fix |
|---|---|
Tools report LocalStack Not Running after start |
Check LOCALSTACK_HOSTNAME=host.docker.internal is set and --add-host is present (Linux). |
Auth Token Required |
LOCALSTACK_AUTH_TOKEN must be passed through (every tool requires it). |
Docker Not Available / daemon unreachable |
Ensure /var/run/docker.sock is mounted (or pass DOCKER_HOST for a non-default daemon). |
LocalStack container not found or Could not find a running LocalStack container named "localstack-main" |
Set MAIN_CONTAINER_NAME if you use a custom LocalStack container name. |
| State disappeared after upgrading the image | Old configs stored state under $XDG_CACHE_HOME/localstack/volume — keep that env var, or point LOCALSTACK_VOLUME_DIR at the old directory. |
| MCP server containers pile up over time | Older images did not exit when the client disconnected. Pull the latest image, then remove strays with docker ps -aq --filter ancestor=localstack/localstack-mcp-server | xargs docker rm -f. |
tests/docker/validate-image.mjs is a dependency-free MCP stdio client that drives
the image through real tool calls.
LOCALSTACK_AUTH_TOKEN="<YOUR_TOKEN>" \
HARNESS_TOKEN_REAL=1 \
node tests/docker/validate-image.mjs -- \
docker run -i --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--add-host s3.host.docker.internal:host-gateway \
--add-host snowflake.localhost.localstack.cloud:host-gateway \
-e LOCALSTACK_AUTH_TOKEN \
-e LOCALSTACK_HOSTNAME=host.docker.internal \
-v "$PWD/data:/work/data" \
localstack/localstack-mcp-server:latestUse HARNESS_SKIP to skip scenarios, for example:
HARNESS_SKIP=docs,cloudpods,ephemeral,replicator
{ "mcpServers": { "localstack-mcp-server": { "command": "docker", "args": [ "run", "-i", "--rm", "-v", "/var/run/docker.sock:/var/run/docker.sock", "--add-host", "host.docker.internal:host-gateway", "--add-host", "s3.host.docker.internal:host-gateway", "--add-host", "snowflake.localhost.localstack.cloud:host-gateway", "-e", "LOCALSTACK_AUTH_TOKEN", "-e", "LOCALSTACK_HOSTNAME=host.docker.internal", "-v", "/Users/you/projects:/Users/you/projects", "localstack/localstack-mcp-server:latest", ], "env": { "LOCALSTACK_AUTH_TOKEN": "<YOUR_TOKEN>" }, }, }, }