Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions