Towline Agent Documentation
This document is designed for AI agents (Claude Code, Cursor, Codex, Gemini CLI, Windsurf, etc.) that need to understand what Towline is, how it works, and how to use its tools to build, deploy, and operate software on Portainer-managed infrastructure.
TL;DR: Towline gives you an isolated container stack on Portainer with 10 high-level MCP tools for deployment, health checks, logs, domain routing, scaling, and exec. You can go from "write code" to "running in production" without leaving your MCP session.
What is Towline?
Towline is the agentic engineering SDK for Portainer. It has three components:
- towline-mcp — An MCP server (Go binary) that runs per-project, providing your agent with scoped access to a single Portainer stack. It adds stack isolation, tier-based approval gating, and 10 high-level operational tools on top of the upstream Portainer MCP.
- towline CLI — A scaffolding tool.
towline init <project>creates everything: Portainer team, scoped API key, container stack, agent configuration, compose files, and git repo. - Template packs — Compose files + agent skills + MCP configs bundled as starter kits (api, fullstack, worker, static-site, databases, etc.).
How Your MCP Session Works
When your user runs towline init my-project, it creates a .claude/settings.json (or equivalent for your agent) that tells your MCP client to launch towline-mcp with these flags:
towline-mcp \
-server https://portainer.example.com \
-token <scoped-api-key> \
-stack my-project \
-tier devThis MCP server process is your gateway to the Portainer environment. Every tool call you make goes through it, and it enforces:
- Stack scoping — You can only see and modify the
my-projectstack. Other stacks are invisible. - Container ownership — Docker proxy calls are filtered to containers belonging to your stack.
- Tier gating — In
devtier, you have full autonomy. Inprodtier, mutations require an approval token.
MCP Tools Reference
You have access to two categories of tools: Towline tools (high-level, one-call answers) and upstream Portainer tools (stack CRUD and Docker proxy).
Towline Tools
towline_service_health
Get health snapshot for one or all services in the stack.
| Parameter | Type | Required | Description |
|---|---|---|---|
service | string | No | Service name from docker-compose. Omit for all services. |
Returns: state, uptime, restart count, CPU/memory usage, exit code. If stats or inspect calls fail, stats_error or inspect_error fields will contain the error message.
towline_service_logs
Fetch recent log output for a named service.
| Parameter | Type | Required | Description |
|---|---|---|---|
service | string | Yes | Service name from docker-compose |
tail | number | No | Lines to return (default 200) |
since | string | No | RFC3339 timestamp filter |
filter | string | No | Filter lines containing this string |
towline_env_get
Read stack environment variables. Sensitive values (names containing KEY, SECRET, PASSWORD, TOKEN) are masked.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | No | Specific variable name. Omit for all. |
towline_env_set
Set a stack environment variable. Requires approval in prod tier.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Variable name |
value | string | Yes | Variable value |
approvalToken | string | No | Token for prod tier approval |
towline_domains_list
List all domain/routing mappings for services in the stack. No parameters.
towline_domains_add
Add domain routing to a service. Requires approval in prod tier.
| Parameter | Type | Required | Description |
|---|---|---|---|
service | string | Yes | Service name |
domain | string | Yes | Domain name (e.g. app.example.com) |
port | number | No | Service port (default 80) |
method | string | No | traefik, caddy, or cloudflare (auto-detected if omitted) |
approvalToken | string | No | Token for prod tier approval |
towline_domains_remove
Remove domain routing from a service. Requires approval in prod tier.
| Parameter | Type | Required | Description |
|---|---|---|---|
service | string | Yes | Service name |
domain | string | Yes | Domain to remove |
method | string | No | traefik, caddy, or cloudflare (auto-detected if omitted) |
approvalToken | string | No | Token for prod tier approval |
towline_scale
Scale a service to N replicas. Warns if the service has persistent volumes. No approval required (operational).
| Parameter | Type | Required | Description |
|---|---|---|---|
service | string | Yes | Service name |
replicas | number | Yes | Number of replicas |
towline_deployments
View deployment history with diffs and outcomes.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | number | No | Max entries (default 10) |
towline_exec
Execute a command inside a running container and capture stdout/stderr. Requires approval in prod tier.
| Parameter | Type | Required | Description |
|---|---|---|---|
service | string | Yes | Service name |
command | string | Yes | Command to run (space-separated args) |
approvalToken | string | No | Token for prod tier approval |
Upstream Portainer Tools
These are the standard Portainer MCP tools, scoped to your stack:
| Tool | Description |
|---|---|
listLocalStacks | List stacks (filtered to yours) |
getLocalStackFile | Get compose file content |
createLocalStack | Deploy a new stack |
updateLocalStack | Update stack (full compose required!) |
startLocalStack | Start a stopped stack |
stopLocalStack | Stop a running stack |
deleteLocalStack | Delete a stack |
dockerProxy | Raw Docker API proxy (GET/POST/PUT/DELETE) |
Critical: Partial Compose Files
When calling updateLocalStack, you MUST submit the COMPLETE compose file. Portainer removes any service not included in the update. If you only include the service you changed, all other services will be destroyed.
Safe workflow:
- Call
getLocalStackFileto get the current compose content - Modify the YAML as needed
- Submit the entire modified file to
updateLocalStack
Tier System & Approval Flow
The -tier flag controls what you can do without human approval:
Dev Tier (-tier dev)
Full autonomy. Every tool call executes immediately. Use this for development and testing.
Prod Tier (-tier prod)
| Operation | Approval? | Examples |
|---|---|---|
| Read | No | health, logs, env_get, domains_list, deployments, listLocalStacks |
| Operational | No | startLocalStack, scale |
| Configuration | Yes | env_set, domains_add, domains_remove |
| Deploy | Yes | createLocalStack, updateLocalStack |
| Destructive | Yes | stopLocalStack, deleteLocalStack |
| Exec / Docker write | Yes | towline_exec, dockerProxy non-GET |
How Approval Works
- You call a tool that requires approval (e.g.
updateLocalStackin prod) - The response contains an
approvalTokenstring and a message describing the action - The human reviews and approves (the token is shown to them)
- You re-call the same tool with the same arguments plus the
approvalTokenparameter - The call executes
Tokens are single-use, expire after 5 minutes, and are bound to the specific tool and arguments. You cannot reuse a token with different arguments.
Common Agent Workflows
Deploy a new service
1. getLocalStackFile → get current compose
2. Add your new service to the YAML
3. updateLocalStack → deploy (submit FULL compose)
4. towline_service_health → verify it started
5. towline_service_logs → check for errorsDebug a failing service
1. towline_service_health → check state, restarts, exit code
2. towline_service_logs service=failing-svc tail=100 → read logs
3. towline_exec service=failing-svc command="cat /app/config.json" → inspect files
4. towline_env_get → check environment variables
5. Fix the issue, redeploy via updateLocalStackExpose a service on a domain
1. towline_domains_add service=web domain=app.example.com port=3000
(auto-detects Traefik/Caddy/Cloudflare)
2. towline_domains_list → verify routing
3. towline_service_health → ensure service is healthyScale a service
1. towline_scale service=worker replicas=3
2. towline_service_health → verify all replicas runningRoll back a broken deploy
1. towline_deployments → see history, find last working version
2. getLocalStackFile → get current (broken) compose
3. Revert to previous compose content
4. updateLocalStack → redeploy
5. towline_service_health → verify rollbackCLI Reference
These are commands the human user runs (not MCP tools). You may need to instruct them to run these:
towline init <project>
Create a new project with full Portainer scaffolding.
towline init my-project --template api --tier dev
Flags:
--template Template pack (api, fullstack, worker, static-site, etc.)
--tier Deployment tier (dev or prod, default: dev)towline list
List all Towline projects on this machine.
towline destroy <project>
Remove a project: deletes Portainer team, API key, stack, and local files.
towline setup
Interactive setup: connects to a Portainer instance and saves credentials.
Generated Project Structure
~/projects/<name>/
├── .claude/settings.json # MCP server configuration
├── CLAUDE.md # Agent instructions for this project
├── docker-compose.yml # From template
├── .env.example # Env var template
├── skills/ # Agent skills library
└── .git/The .claude/settings.json file tells your MCP client how to launch towline-mcp. The CLAUDE.md file contains project-specific instructions including available tools, the stack name, and operational guidelines.
Using the Docker Proxy
The dockerProxy tool gives you raw Docker API access, scoped to your stack's containers. Use it for operations not covered by the Towline tools.
// List containers
dockerProxy method=GET dockerAPIPath=/containers/json
// Inspect a container
dockerProxy method=GET dockerAPIPath=/containers/<id>/json
// Restart a container (no approval in prod — operational)
dockerProxy method=POST dockerAPIPath=/containers/<id>/restart
// Non-GET requests to non-operational paths require approval in prodInternal Environment Variables
Variables prefixed with _TOWLINE_ are managed internally by Towline (e.g. deployment history). You cannot set or override them — they are silently filtered from createLocalStack and updateLocalStack requests.
Prerequisites
- Portainer v2.28+ with API access
- Docker on the container host
- Network connectivity from the dev machine to the Portainer API
- An MCP-compatible agent (Claude Code, Cursor, Codex, Gemini CLI, Windsurf)
Links
This documentation is designed to be consumed by AI agents. For human-readable docs, see the Getting Started guide.