Containerized Strands Agents is an MCP (Model Context Protocol) server that hosts isolated Strands AI agents in Docker containers. Each agent runs independently with its own workspace, persists conversation history across restarts, and supports custom system prompts, per-agent tools, and GitHub integration. The fire-and-forget architecture enables autonomous background task execution while the host manages container lifecycle, idle timeouts, and session persistence.
src/containerized_strands_agents/— Core package:server.py— MCP server (FastMCP tools)agent_manager.py— Docker orchestration, container lifecycleagent.py— Shared agent logic (create_agent, run_agent)cli.py— CLI commands (snapshot, restore, run)config.py— Configuration constants
docker/— Docker image: FastAPI runner, GitHub tools, requirementsui/— Optional web UI: FastAPI REST wrapper and HTML interfacescripts/— Shell scripts for building Docker image and running the servertests/— Unit, integration, and end-to-end tests using pytesttemplates/— GitHub Actions workflow template for running agents in CI.github/workflows/— CI and PyPI publishing workflowsdata/— Runtime persistence (gitignored): agent workspaces, sessions, task registry
# Install in development mode
pip install -e ".[dev]"
# Install with web UI support
pip install -e ".[webui]"
# Or use Makefile
make dev # Install with all dependencies
make test # Run unit tests
make test-all # Run all tests (requires Docker)
make build # Build wheel and sdist
make docker # Build Docker image
# Build Docker image (auto-built on first use, or manually)
./scripts/build_docker.sh
# Run MCP server (for use with Kiro, Claude Desktop, etc.)
containerized-strands-agents-server
# or
python -m containerized_strands_agents.server
# Run web UI (finds free port 8000-8100)
containerized-strands-agents-webui
# Run tests
python -m pytest tests/ -v# Create a snapshot (backup) of an agent
containerized-strands-agents snapshot --data-dir ./my-agent --output snapshot.zip
# Restore an agent from snapshot
containerized-strands-agents restore --snapshot snapshot.zip --data-dir ./restored-agent
# Run an agent directly (no Docker)
containerized-strands-agents run --data-dir ./my-agent --message "do the thing"
# Pull agent state from GitHub Actions artifact
containerized-strands-agents pull --repo owner/repo --run-id 12345 --data-dir ./my-agent- Python 3.11+ required; type hints used throughout
- Formatting: Standard Python conventions; ~100 char line length preferred
- Naming:
snake_casefor functions/variables,PascalCasefor classes,UPPER_SNAKEfor constants - Async/await pattern for all I/O operations (Docker, HTTP, file system)
- Pydantic models for data validation (
AgentInfo, request/response schemas) - Logging via
loggingmodule; uselogger.info/warning/errorappropriately - Environment variables prefixed with
CONTAINERIZED_AGENTS_orAGENT_HOST_ - Docstrings: Google style for public functions and classes
TODO: Add pre-commit hooks configuration for automated linting
┌─────────────────────────────────────────────────────────────────────────────┐
│ MCP Client (Kiro, etc.) │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ FastMCP Server (server.py) │
│ Tools: send_message, get_messages, list_agents, stop_agent │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ AgentManager (agent_manager.py) │
│ - Docker container lifecycle (create, start, stop) │
│ - TaskTracker: JSON-based agent registry persistence │
│ - Idle monitor: auto-stop containers after timeout │
│ - System prompt & tool management │
└─────────────────────────────────────────────────────────────────────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Container 1 │ │ Container 2 │ │ Container N │
│ (agent-foo) │ │ (agent-bar) │ │ ... │
│ │ │ │ │ │
│ FastAPI:8080 │ │ FastAPI:8080 │ │ FastAPI:8080 │
│ Strands Agent│ │ Strands Agent│ │ Strands Agent│
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────┐
│ Host File System │
│ data/agents/{agent_id}/ │
│ ├── workspace/ (agent's files) │
│ └── .agent/ │
│ ├── session/ (conversation history) │
│ ├── tools/ (per-agent tools) │
│ ├── runner/ (agent code for GHA) │
│ └── system_prompt.txt │
└──────────────────────────────────────────────────┘
Data Flow:
- MCP client calls
send_messagewith agent_id and message - AgentManager creates/restarts Docker container if needed
- Message dispatched to container's
/chatendpoint (fire-and-forget) - Strands Agent processes message using available tools
- FileSessionManager persists conversation to mounted volume
- Client polls
get_messagesto retrieve results when needed
Key Components:
FastMCP: MCP protocol implementation exposing tools to clientsAgentManager: Orchestrates Docker containers, manages state viaTaskTrackeragent.py: Shared agent logic used by both Docker runner and CLIagent_runner.py: FastAPI server inside container running Strands AgentFileSessionManager: Persists agent conversation history to JSON filesSummarizingConversationManager: Intelligently summarizes old messages to manage context
Agents can be snapshotted (backed up) and restored anywhere. A snapshot is just a zip of the agent's data directory.
What's included in a snapshot:
workspace/— Agent's files (repos, code, etc.).agent/session/— Conversation history (agent remembers context).agent/tools/— Custom tools.agent/runner/— Agent code (for running without Docker).agent/system_prompt.txt— Custom system prompt
Snapshot workflow:
# 1. Create snapshot
containerized-strands-agents snapshot --data-dir ./data/agents/my-agent --output backup.zip
# 2. Restore anywhere
containerized-strands-agents restore --snapshot backup.zip --data-dir ./new-location
# 3. Run restored agent (Docker or CLI)
containerized-strands-agents run --data-dir ./new-location --message "continue where you left off"Portability:
- Snapshots work across machines (same OS)
- Session uses hardcoded agent ID ("agent") so any restored snapshot continues the same conversation
- Can run in Docker (via MCP server) or standalone (via CLI
runcommand) - Designed for GitHub Actions: restore snapshot → run agent → upload new snapshot
| Type | Location | Runner | Notes |
|---|---|---|---|
| Unit | tests/test_agent_manager.py |
pytest |
Mocked Docker, fast |
| Unit | tests/test_custom_system_prompt*.py |
pytest |
System prompt handling |
| Integration | tests/test_integration.py |
pytest (requires Docker) |
Real containers, short tasks |
| E2E | tests/test_e2e.py |
pytest (requires Docker+AWS) |
Full agent flow with Bedrock |
# Run all tests
python -m pytest tests/ -v
# Run only unit tests (no Docker required)
python -m pytest tests/test_agent_manager.py tests/test_custom_system_prompt.py -v
# Run integration tests
python -m pytest tests/test_integration.py -v --timeout=120
# Run with coverage (if pytest-cov installed)
python -m pytest tests/ --cov=src/containerized_strands_agents --cov-report=htmlTests use pytest-asyncio with asyncio_mode = "auto" configured in pyproject.toml.
GitHub Actions Workflows:
.github/workflows/ci.yml— Runs tests on push/PR (Python 3.11-3.13).github/workflows/publish.yml— Publishes to PyPI on GitHub release
Publishing to PyPI:
Via GitHub (recommended):
- Update version in
pyproject.tomlandsrc/containerized_strands_agents/__init__.py - Create a GitHub release with tag matching version (e.g.,
v0.1.0) - Publish workflow runs automatically
Via local commands:
make build # Build wheel and sdist
make publish-test # Publish to TestPyPI (for testing)
make publish # Publish to PyPIPyPI Trusted Publisher Setup:
- Go to repo Settings → Environments → Create "pypi"
- Go to PyPI → Account → Publishing → Add trusted publisher:
- Owner:
mkmeral - Repository:
containerized-strands-agents - Workflow:
publish.yml
- Owner:
Secrets Handling:
- AWS credentials: Mounted read-only from
~/.aws/into containers - GitHub token: Passed via
CONTAINERIZED_AGENTS_GITHUB_TOKENenvironment variable - API keys (OpenAI, Google): Passed via environment variables, never logged
- System prompts can contain sensitive instructions; stored in agent data directories
Container Isolation:
- Each agent runs in isolated Docker container on
agent-host-netbridge network - Workspace mounted read-write; AWS credentials mounted read-only
- Tools directory mounted read-only to prevent agent modification
BYPASS_TOOL_CONSENT=trueset for automated operation (agents can execute tools freely)
Dependency Scanning:
TODO: Add dependabot or similar for automated dependency updates
License: MIT (see LICENSE file)
Files Never Modified by Agents:
- Host system files outside mounted volumes
~/.aws/credentials(read-only mount)- Docker configuration and images
- MCP server source code
Automatic Safeguards:
- Idle timeout: Containers auto-stop after
AGENT_HOST_IDLE_TIMEOUTminutes (default: 720/12hrs) - Container isolation: Agents cannot access host network or other containers directly
- Retry limits: Max 3 retries with exponential backoff for transient errors
Recommended Reviews:
- Review agent output before committing to external repositories
- Audit
data/agents/*/workspace/for unexpected file creation - Monitor container resource usage for runaway processes
Rate Limits:
- Bedrock/Claude API rate limits apply per AWS account
- GitHub API rate limits apply per token (5000 requests/hour for authenticated)
Environment Variables:
| Variable | Default | Description |
|---|---|---|
CONTAINERIZED_STRANDS_DATA_DIR |
./data |
Base directory for all persistence |
AGENT_HOST_IDLE_TIMEOUT |
720 |
Minutes before idle container stops |
CONTAINERIZED_AGENTS_GITHUB_TOKEN |
— | GitHub PAT for git operations |
CONTAINERIZED_AGENTS_SYSTEM_PROMPTS |
— | Comma-separated paths to prompt files |
CONTAINERIZED_AGENTS_TOOLS |
— | Path to global tools directory |
CONTAINERIZED_AGENTS_MCP_CONFIG |
— | Path to default mcp.json for all agents |
OPENAI_API_KEY |
— | Passed to containers for OpenAI models |
GOOGLE_API_KEY |
— | Passed to containers for Gemini models |
AWS_BEARER_TOKEN_BEDROCK |
— | Cross-account Bedrock access |
Per-Agent Customization:
description: Brief description of the agent's purpose (shown in list_agents and web UI)system_prompt: Custom instructions via text or file pathtools: List of.pyfiles to load as additional Strands toolsdata_dir: Custom data directory for project-specific agentsaws_profile: Different AWS credentials per agentaws_region: Different Bedrock region per agentmcp_config: MCP server configuration dict (same format as Kiro/Claude Desktop)mcp_config_file: Path to existing mcp.json file on host
MCP Server Support:
Agents can connect to MCP (Model Context Protocol) servers for additional tools. Configuration uses the same format as Kiro/Claude Desktop:
// data/agents/my-agent/.agent/mcp.json
{
"mcpServers": {
"github": {
"command": "uvx",
"args": ["mcp-server-github"],
"env": {"GITHUB_TOKEN": "..."},
"disabled": false
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
}
}
}Configuration precedence (highest to lowest):
- Per-agent
mcp_config_fileparameter (path to mcp.json) - Per-agent
mcp_configparameter (inline dict) - Agent's persisted config (
.agent/mcp.json) - Global default (
CONTAINERIZED_AGENTS_MCP_CONFIGenv var)
Example usage:
# Point to existing Kiro config
send_message(
agent_id="reviewer",
message="Review this PR",
mcp_config_file="~/.kiro/settings/mcp.json"
)
# Or inline config
send_message(
agent_id="researcher",
message="Search for docs",
mcp_config={
"mcpServers": {
"aws-docs": {
"command": "uvx",
"args": ["awslabs.aws-documentation-mcp-server@latest"]
}
}
}
)Adding New Tools:
- Create
.pyfile with@tooldecorated functions (Strands tools format) - Place in global tools directory (
CONTAINERIZED_AGENTS_TOOLS) or pass viatoolsparameter - Tools are copied to agent's
/app/tools/and loaded viaload_toolat startup
Web UI Extension:
- REST API at
ui/api.pywraps MCP tools for HTTP access - Extend by adding new FastAPI routes
- Static UI served from
ui/index.html
- README.md — Quick start guide and MCP configuration
- docker/Dockerfile — Container image specification
- docker/agent_runner.py — In-container agent implementation
TODO: Add docs/ARCHITECTURE.md with detailed design decisions TODO: Add docs/TROUBLESHOOTING.md for common issues TODO: Add ADR (Architecture Decision Records) directory