What is the Control Tower?
The Control Tower is a special agent that acts as the single conversational entry point to your muxAI deployment. You talk to it in chat — it can list every agent, invoke runs, and report results back to you. Think of it as the admin layer between you and the rest of your agents. There is one Control Tower per deployment. It’s a singleton, identified by the reservedrole = "control_tower". You can’t create it from the regular New Agent page — the /agents API rejects that role — and it’s hidden from the agent list, team reports-to pickers, and memory summaries.
Setting it up
Visit/control-tower in the sidebar (Platform section, Radar icon). If no Control Tower exists yet, you’ll see an empty state with a Set up button. One click creates it with default settings and its own Solana + Base/EVM wallets.
Once set up, the page shows an admin card with an Open chat button that preselects the Control Tower in /chat.
MCP access
The Control Tower gets every built-in MCP server except two:| Server | Included? | Why |
|---|---|---|
mcp-control-tower | ✅ | Its own admin tools — list agents, invoke runs, read run status. |
| All other built-ins | ✅ | Wide access makes chat useful: research, trade data, memory, etc. |
mcp-wallet | ❌ | The only MCP that can spend funds via x402. Admin’s asymmetric risk — excluded by default. |
mcp-orchestrator | ❌ | The Control Tower has no direct reports, so team coordination tools don’t apply. |
apps/api/src/services/adapters/claude-local.ts and is enforced on every run.
Admin tools
packages/mcp-control-tower exposes these tools that only the Control Tower can call:
| Tool | Purpose |
|---|---|
list_agents | Enumerate every agent (excluding itself), with id, role, status, run count, and schedule. |
invoke_agent | Invoke an agent by name, role, or id and wait for the run to complete. Optional task overrides the default prompt. |
get_run_status | Fetch status, result, and logs for any run by id. |
get_agent_decisions | Pull the recent structured decisions and user-marked outcomes for one agent. |
stop_agent | Kill the active run on a stuck or runaway agent. |
pause_agent | Pause a scheduled agent so the scheduler skips it. |
resume_agent | Bring a paused or errored agent back to idle. |
reset_agent_memory | Clear the shared Claude session for an agent with Active Memory. |
claude-local.ts excludes mcp-control-tower from every non-admin spawn.
Chatting with it
The/chat page fetches the Control Tower separately from the regular agent list and merges it into the agent dropdown. When selected, it’s marked with a red ring, a Radar icon, and a red dot. The ?agent=<id> query param on /chat preselects it — the Open chat button on /control-tower uses this.
Because chat doesn’t create HeartbeatRun records, the Control Tower card shows Messages (count of ChatMessage rows on its session) instead of Total runs.
Messaging gateways
The/control-tower page shows a Comms channels grid: in-app chat is always online; Telegram, Discord, and WhatsApp are progressively being added. Gateways share a single ChatSession with the web /chat page via the reusable services/chat-runner.ts helper, so resetting or continuing a conversation is consistent across channels.
Telegram
The Telegram gateway runs in-process using long polling — no webhook, no public URL required. Config is colocated with the agent atadapterConfig.gateways.telegram.
Pairing flow (on /control-tower):
- Click the Telegram tile → paste a bot token from @BotFather.
- The server calls Telegram’s
getMeto validate and resolve the bot username. - Open the bot in Telegram and send
/start. The first chat to say/startclaims ownership (ownerChatId). Any other chat gets anUnauthorizedreply. - Cancel mid-pairing calls
DELETEon the gateway route so the poller is stopped and the token isn’t left polling in the background.
| Command | Effect |
|---|---|
/start | First time: pair. Afterwards: brief confirmation that the gateway is live. |
/whoami | Prints your Telegram chat id and username. |
/reset | Deletes the shared ChatSession messages and clears the Claude session — same as a web-side reset. |
runChatTurn, which is the same helper the web /chat route uses. The gateway streams a typing indicator every 4 seconds during a turn and sends assistant text as it arrives. Because admin tool chains (invoke_agent, get_agent_decisions) can exceed 3 minutes, the chat runner’s default maxMs is 900 seconds; the SKILL.md also instructs the Control Tower to acknowledge before starting slow work so remote users see a preamble instead of silence.
The poller is started lazily on boot via initTelegramGatewayOnBoot if a token is saved, and restarted on successful pairing. Source: apps/api/src/services/gateways/telegram.ts.
