Setup tips & tricks — CMA as an MCP server
Things that aren't obvious from the docs and tend to cost debugging time.
Mental model
Claude Desktop is the frontend, CMA is the backend
The Claude you're typing to in Desktop is a relay. It calls send_message with your words, calls wait_for_idle to block until the CMA agent finishes, then shows you the reply. The actual work — tool use, code execution, repo edits — happens in the CMA session, not in Desktop.
Eight 1:1 tools, one shim
list_agents, get_agent, create_session, send_message, interrupt, get_session, list_events, archive_session are straight endpoint wrappers. wait_for_idle is the only editorial: MCP is request/response and CMA completion is SSE, so something has to stream-to-idle inside a tool call.
session_id is the only state, and Claude holds it
create_session returns it; Claude passes it to every subsequent call. The MCP server itself is stateless.
Two transports, one tool set
src/tools.ts registers the nine tools. src/server.ts wraps it in stdio (Claude Desktop spawns it as a subprocess); src/server-http.ts wraps it in Streamable HTTP (claude.ai web reaches it over the network). Pick one.
Setup — Claude Desktop (stdio, local)
- Environment (one-time — sessions need an
environment_id):bashant beta:environments create --name cma-mcp \ --config '{type: cloud, networking: {type: unrestricted}}' --transform id -r - Agents: this server doesn't create agents — it drives the ones already in your workspace. Create/update them via the
antCLI or the Console. .env.local:ANTHROPIC_API_KEY=sk-ant-... CLAUDE_ENVIRONMENT_ID=env_...- Register with Claude Desktop — add to
~/Library/Application Support/Claude/claude_desktop_config.json(macOS) and restart Desktop:json{ "mcpServers": { "cma": { "command": "bun", "args": ["run", "/absolute/path/to/managed_agents/cma-mcp/src/server.ts"], "env": { "ANTHROPIC_API_KEY": "sk-ant-...", "CLAUDE_ENVIRONMENT_ID": "env_..." } } } } - Test: in a new Desktop chat, ask "list my managed agents, start a session with the first one, and relay this message to it: hello."
Setup — claude.ai web (Streamable HTTP, remote)
Same tools, but the server runs at a public URL and claude.ai connects to it as a custom Connector.
Token — generate and keep it; anyone with this token can drive your agents:
bashexport CMA_MCP_TOKEN=$(openssl rand -hex 32)Run locally first (ngrok/cloudflared for a public URL while testing):
bashbun run http # → :3000/mcpDeploy — the
Dockerfiletargets Fly / Railway / Render; setANTHROPIC_API_KEY,CLAUDE_ENVIRONMENT_ID,CMA_MCP_TOKENas secrets. (Cloudflare Workers also works —WebStandardStreamableHTTPServerTransportis fetch-native; swapprocess.env→envandBun.serve→export default \{ fetch \}.)claude.ai → Settings → Connectors → Add custom connector:
Field Value Name CMA