Skip to content

Terraform plugins spawn duplicate, leaked Docker containers per Claude Code session #46

@tfriedel

Description

@tfriedel

Problem

The terraform-code-generation and terraform-module-generation plugins both define an identical MCP server in their plugin.json:

"mcpServers": {
  "terraform": {
    "command": "docker",
    "args": ["run", "-i", "--rm", "-e", "TFE_TOKEN", "-e", "TFE_ADDRESS", "hashicorp/terraform-mcp-server"]
  }
}

This causes two issues:

1. Duplicate containers per session

Both plugins launch the exact same hashicorp/terraform-mcp-server image with identical arguments. With both plugins enabled, every Claude Code session starts 2 identical containers. They provide the same MCP tools, so there's no benefit to running two.

2. Containers are never cleaned up

The containers are started with -i --rm, but when a Claude Code session ends, the stdin pipe is not cleanly closed. The container doesn't detect the broken pipe and keeps running indefinitely. The --rm flag never triggers because the container never exits.

Over time this leads to an ever-growing list of orphaned containers:

CONTAINER ID   IMAGE                              CREATED         STATUS
2a55cef7afb5   hashicorp/terraform-mcp-server     2 hours ago     Up 2 hours
11453ae06a6d   hashicorp/terraform-mcp-server     2 hours ago     Up 2 hours
207c224f8d3a   hashicorp/terraform-mcp-server     6 hours ago     Up 6 hours
872fd3600b83   hashicorp/terraform-mcp-server     6 hours ago     Up 6 hours
2fb5383d29f9   hashicorp/terraform-mcp-server     11 hours ago    Up 11 hours
80532aa71341   hashicorp/terraform-mcp-server     11 hours ago    Up 11 hours
... (12 containers from ~6 sessions over 5 days)

Suggested fixes

For the duplicate container issue

Use a fixed --name for the Docker container so that when both plugins are enabled, the second docker run detects the already-running container instead of spawning a duplicate. A wrapper script could first check if a container with that name is already running and reuse it, or both plugins could coordinate on a shared container name.

For the leaked container issue

The container needs a way to detect that stdin has been closed and exit cleanly, so that --rm actually triggers. Options:

  • Add stdin EOF detection inside the MCP server process
  • Use a wrapper entrypoint that monitors the stdin pipe and kills the process on broken pipe
  • Use --name combined with a cleanup-before-start pattern (docker rm -f <name> before docker run)

Workaround

I'm currently using a wrapper script that forces a fixed container name and kills any stale container before starting:

#!/bin/bash
CONTAINER_NAME="terraform-mcp-server"
docker rm -f "$CONTAINER_NAME" 2>/dev/null
exec docker run -i --rm --name "$CONTAINER_NAME" -e TFE_TOKEN -e TFE_ADDRESS hashicorp/terraform-mcp-server

Plus a Claude Code Stop hook to clean up on session exit:

{"type": "command", "command": "docker rm -f terraform-mcp-server 2>/dev/null || true"}

Environment

  • Claude Code (latest)
  • Both terraform-code-generation@hashicorp and terraform-module-generation@hashicorp plugins enabled
  • Docker on Linux (Ubuntu 24.04)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions