Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Build artifacts (rebuilt inside the image)
node_modules
dist
.xmcp
xmcp-env.d.ts

# VCS / CI
.git
.github

# Test output
test-results
.mcp-test-results
data
**/.terraform
**/.terraform.lock.hcl

# Secrets / local registry tokens (never bake into the image)
.mcpregistry*
.env
.env.*

# Editor / OS noise
.DS_Store
*.log

# Docs/meta not needed at runtime
CLAUDE.md
75 changes: 75 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Docker Image (Build & Test)

on:
pull_request:
branches: [main]
paths:
- "Dockerfile"
- ".dockerignore"
- "src/**"
- "package.json"
- "yarn.lock"
- "tests/docker/**"
- ".github/workflows/docker.yml"
push:
branches: [main]
# release:
# types: [published]
# workflow_dispatch:

env:
IMAGE_NAME: localstack/localstack-mcp-server

jobs:
smoke:
runs-on: ubuntu-latest
env:
CI_LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build image (single-arch, load locally)
uses: docker/build-push-action@v6
with:
context: .
load: true
tags: ${{ env.IMAGE_NAME }}:ci
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22.x

- name: Smoke test MCP startup
env:
HARNESS_SKIP: prompt,docs,status,start,aws,logs,state,cloudpods,appinspector,chaos,iam,replicator,ephemeral,deploy,deploy-cdk,extensions,restart,stop,snowflake
run: |
node tests/docker/validate-image.mjs -- \
docker run -i --rm \
${{ env.IMAGE_NAME }}:ci

- name: Integration test Docker runtime
env:
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
HARNESS_TOKEN_REAL: "1"
HARNESS_SKIP: cloudpods,ephemeral,replicator,chaos
run: |
npm ci --prefix data/sample-cdk
mkdir -p "$HOME/.localstack-mcp"
node tests/docker/validate-image.mjs -- \
docker run -i --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$HOME/.localstack-mcp:$HOME/.localstack-mcp" \
-e XDG_CACHE_HOME="$HOME/.localstack-mcp" \
--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" \
${{ env.IMAGE_NAME }}:ci
79 changes: 79 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# syntax=docker/dockerfile:1

FROM node:22-bookworm-slim AS builder
WORKDIR /app

COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build

FROM python:3.12-slim-bookworm AS runtime
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONDONTWRITEBYTECODE=1

RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends ca-certificates curl gnupg unzip git; \
install -m 0755 -d /usr/share/keyrings; \
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -; \
curl -fsSL https://apt.releases.hashicorp.com/gpg \
| gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg; \
chmod a+r /usr/share/keyrings/hashicorp-archive-keyring.gpg; \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com bookworm main" \
> /etc/apt/sources.list.d/hashicorp.list; \
curl -fsSL https://download.docker.com/linux/debian/gpg \
| gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg; \
chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg; \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bookworm stable" \
> /etc/apt/sources.list.d/docker.list; \
apt-get update; \
apt-get install -y --no-install-recommends nodejs terraform docker-ce-cli; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir --upgrade pip \
&& pip install --no-cache-dir --no-compile \
localstack \
awscli \
awscli-local \
terraform-local \
aws-sam-cli \
aws-sam-cli-local \
snowflake-cli \
&& find /usr/local/lib/python3.12/site-packages \
\( -type d \( -name __pycache__ -o -name tests -o -name test \) -o -type f \( -name '*.pyc' -o -name '*.pyo' \) \) \
-prune -exec rm -rf '{}' +

RUN npm install -g aws-cdk aws-cdk-local \
&& npm cache clean --force

WORKDIR /app
RUN mkdir -p /usr/lib/localstack /tmp/dockerode-deps \
&& npm install --prefix /tmp/dockerode-deps --omit=dev --ignore-scripts --no-audit --no-fund dockerode@4.0.7 \
&& mkdir -p /app/node_modules \
&& cp -R /tmp/dockerode-deps/node_modules/. /app/node_modules/ \
&& rm -rf /tmp/dockerode-deps \
&& npm cache clean --force
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./package.json

RUN set -eux; \
localstack --version; \
aws --version; \
awslocal --version; \
terraform version; \
tflocal --version; \
sam --version; \
command -v samlocal; \
cdklocal --version; \
snow --version; \
docker --version; \
node -e "require('dockerode'); console.log('dockerode ok')"

LABEL org.opencontainers.image.title="LocalStack MCP Server" \
org.opencontainers.image.description="Self-contained MCP server for managing LocalStack (CLI, CDK, Terraform, SAM, awslocal baked in)" \
org.opencontainers.image.source="https://github.com/localstack/localstack-mcp-server" \
org.opencontainers.image.licenses="Apache-2.0"

ENTRYPOINT ["node", "dist/stdio.js"]
36 changes: 33 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ This server provides your AI with dedicated tools for managing your LocalStack e
| [`localstack-chaos-injector`](./src/tools/localstack-chaos-injector.ts) | Injects and manages chaos experiment faults for system resilience testing | - Inject, add, remove, and clear service fault rules<br/>- Configure network latency effects<br/>- Comprehensive fault targeting by service, region, and operation<br/>- Built-in workflow guidance for chaos experiments<br/>- Requires a valid LocalStack Auth Token |
| [`localstack-cloud-pods`](./src/tools/localstack-cloud-pods.ts) | Manages remote LocalStack Cloud Pods for development workflows | - Save current state as a Cloud Pod<br/>- Load previously saved Cloud Pods instantly<br/>- Delete Cloud Pods from remote cloud-backed storage<br/>- Use this for managed remote state snapshots, not local export/import files<br/>- Requires a valid LocalStack Auth Token |
| [`localstack-state-management`](./src/tools/localstack-state-management.ts) | Manages local file-based LocalStack state export/import workflows | - Export LocalStack state to a local file on disk through the LocalStack State REST API<br/>- Import LocalStack state from a local file<br/>- Inspect current LocalStack state as JSON metamodel data<br/>- Reset all state or only selected services<br/>- Supports service-level granularity for export, reset, and inspect<br/>- Use this for local disk workflows; use Cloud Pods for remote cloud-backed snapshots<br/>- Requires a valid LocalStack Auth Token |
| [`localstack-extensions`](./src/tools/localstack-extensions.ts) | Installs, uninstalls, lists, and discovers LocalStack Extensions | - Manage installed extensions via CLI actions (`list`, `install`, `uninstall`)<br/>- Browse the LocalStack Extensions marketplace (`available`)<br/>- Requires a valid LocalStack Auth Token support |
| [`localstack-extensions`](./src/tools/localstack-extensions.ts) | Installs, uninstalls, lists, and discovers LocalStack Extensions | - Manage installed extensions via CLI actions (`list`, `install`, `uninstall`)<br/>- Browse the LocalStack Extensions marketplace (`available`)<br/>- Requires a valid LocalStack Auth Token |
| [`localstack-ephemeral-instances`](./src/tools/localstack-ephemeral-instances.ts) | Manages cloud-hosted LocalStack Ephemeral Instances | - Create temporary cloud-hosted LocalStack instances and get an endpoint URL<br/>- List available ephemeral instances, fetch logs, and delete instances<br/>- Supports lifetime, extension preload, Cloud Pod preload, and custom env vars on create<br/>- Requires a valid LocalStack Auth Token and LocalStack CLI |
| [`localstack-aws-client`](./src/tools/localstack-aws-client.ts) | Runs AWS CLI commands inside the LocalStack for AWS container | - Executes commands via `awslocal` inside the running container<br/>- Sanitizes commands to block shell chaining<br/>- Auto-detects LocalStack coverage errors and links to docs |
| [`localstack-aws-replicator`](./src/tools/localstack-aws-replicator.ts) | Replicates external AWS resources into a running LocalStack instance | - Start single-resource replication jobs with a resource type and identifier or ARN<br/>- Start batch replication jobs, such as SSM parameters under a path prefix<br/>- Poll job status by job ID and list existing jobs<br/>- List resource types supported by the running Replicator extension<br/>- Reads source AWS credentials from the MCP server environment and supports optional target account or region overrides |
Expand All @@ -63,13 +63,14 @@ For other MCP Clients, refer to the [configuration guide](#configuration).
### Prerequisites

- [LocalStack CLI](https://docs.localstack.cloud/getting-started/installation/#localstack-cli) and Docker installed in your system path
- [`cdklocal`](https://github.com/localstack/aws-cdk-local), [`tflocal`](https://github.com/localstack/terraform-local), or [`samlocal`](https://github.com/localstack/aws-sam-cli-local) installed in your system path for running infrastructure deployment tooling
- [`cdklocal`](https://github.com/localstack/aws-cdk-local), [`tflocal`](https://github.com/localstack/terraform-local), or [`samlocal`](https://github.com/localstack/aws-sam-cli-local) installed in your system path if you want to deploy CDK, Terraform, or SAM projects
- Snowflake CLI (`snow`) installed in your system path if you want to use the Snowflake tool
- A [valid LocalStack Auth Token](https://docs.localstack.cloud/aws/getting-started/auth-token/) configured as `LOCALSTACK_AUTH_TOKEN` (**required for all MCP tools**)
- [Node.js v22.x](https://nodejs.org/en/download/) or higher installed in your system path

### Configuration

Add the following to your MCP client's configuration file (e.g., `~/.cursor/mcp.json`). This configuration uses `npx` to run the server, which will automatically download & install the package if not already present:
Add the following to your MCP client's configuration file (e.g., `~/.cursor/mcp.json`). This configuration uses `npx` to run the server, which will automatically download and install the package if needed. LocalStack and any deployment CLIs used by tools run from your host PATH.

```json
{
Expand Down Expand Up @@ -103,6 +104,35 @@ If you installed from source, change `command` and `args` to point to your local
}
```

### Run with Docker

The `localstack/localstack-mcp-server` Docker image bundles the LocalStack CLI, `awslocal`, Terraform/`tflocal`, CDK/`cdklocal`, SAM/`samlocal`, Snowflake CLI, and Docker CLI. The only required host dependency is Docker. The container uses the mounted Docker socket to run LocalStack as a sibling container on the host.

```json
{
"mcpServers": {
"localstack-mcp-server": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "/var/run/docker.sock:/var/run/docker.sock",
"-v", "/Users/you/.localstack-mcp:/Users/you/.localstack-mcp",
"-e", "XDG_CACHE_HOME=/Users/you/.localstack-mcp",
"--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",
"localstack/localstack-mcp-server:latest"
],
"env": { "LOCALSTACK_AUTH_TOKEN": "<YOUR_TOKEN>" }
}
}
}
```

See **[docs/DOCKER.md](./docs/DOCKER.md)** for the run command, MCP client config, IaC project mounts, CDK notes, and troubleshooting.

## LocalStack Configuration

| Variable Name | Description | Default Value |
Expand Down
26 changes: 26 additions & 0 deletions data/sample-cdk/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const cdk = require("aws-cdk-lib");
const s3 = require("aws-cdk-lib/aws-s3");

class SampleCdkStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);

const bucket = new s3.Bucket(this, "SampleBucket", {
bucketName: "mcp-cdk-sample-bucket",
removalPolicy: cdk.RemovalPolicy.DESTROY,
});

new cdk.CfnOutput(this, "BucketName", {
value: bucket.bucketName,
});
}
}

const app = new cdk.App();
new SampleCdkStack(app, "McpSampleCdkStack", {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT || "000000000000",
region: process.env.CDK_DEFAULT_REGION || process.env.AWS_REGION || "us-east-1",
},
synthesizer: new cdk.BootstraplessSynthesizer(),
});
6 changes: 6 additions & 0 deletions data/sample-cdk/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"app": "node app.js",
"context": {
"@aws-cdk/core:newStyleStackSynthesis": true
}
}
Loading
Loading