Claude Managed Agents as MCP Tools: Build a Persistent Agent Pipeline
Anthropic just merged a cookbook that turns their Claude Managed Agents (CMA) Sessions API into a full MCP server. Persistent, hosted agents — the things people have been asking how to wire up for months — are now callable as tools from Claude Desktop or the claude.ai Connector. No custom glue code required. The cookbook ships two entrypoints, nine tools, an SSE shim, and a Dockerfile. Let’s read it together.
What you need
You’ll need a Claude account with org-admin access (the Connector path is org-admin gated), Node.js to run the server locally, and a basic familiarity with MCP concepts — if you know what a tool call is and have configured Claude Desktop before, you’re set. The stdio path works with Claude Desktop; the HTTP path targets the claude.ai Connector.
Step 1: Understand what shipped
The cookbook’s commit body describes this as a “DIY bridge until publish agent to claude.ai is first-class.” That framing matters: this is an explicitly temporary scaffold that makes persistent agents usable now, before Anthropic ships a native first-class publishing flow.
The architecture is straightforward:
flowchart LR
A[Claude Desktop] -->|stdio| B[MCP Server\nserver.ts]
C[claude.ai Connector] -->|Streamable HTTP + Bearer Auth| D[MCP Server\nserver-http.ts]
B --> E[CMA Sessions API]
D --> E
Two entrypoints share a single tool layer defined in src/tools.ts. Eight of the nine tools are one-to-one wrappers around CMA Sessions API endpoints. The ninth — wait_for_idle — is the interesting one, and we’ll get to it.
Step 2: Wire up the stdio path for Claude Desktop
The stdio path is the faster one to validate locally. Clone the cookbook repo, install dependencies, and register the server in your Claude Desktop config:
// claude_desktop_config.json
{
"mcpServers": {
"cma-sessions": {
"command": "node",
"args": ["/path/to/cookbook/dist/server.js"],
"env": {
"ANTHROPIC_API_KEY": "<your_api_key>",
"CMA_BASE_URL": "https://api.anthropic.com"
}
}
}
}
The commit notes this path was proven end-to-end in Claude Desktop. Once registered, restart Claude Desktop and the nine tools from src/tools.ts appear in your tool list.
Step 3: Call your first tool — list_agents
With the server running, you can ask Claude Desktop to list available Managed Agents:
Use the list_agents tool to show me what agents are available.
Under the hood, that fires a tool call shaped like:
{
"tool": "list_agents",
"input": {
"name_contains": "support"
}
}
The name_contains filter is deliberate, not cosmetic. The commit notes that list_agents is capped and includes the filter specifically because auto-pagination hangs on busy workspaces with many agents. If you’re in a large org, always pass a filter.
Step 4: Dispatch a task and use the wait_for_idle shim
This is the engineering centerpiece. Managed Agents are async by nature: you dispatch a task, and the agent works on it over SSE. But MCP tool calls are request/response. The wait_for_idle tool is the shim that bridges them.
Here’s the pattern:
// Pseudocode for what happens when you call wait_for_idle
async function wait_for_idle(sessionId: string, timeoutMs: number) {
return new Promise((resolve, reject) => {
const eventSource = new SSEClient(`/sessions/${sessionId}/events`);
eventSource.on("idle", (event) => {
eventSource.close();
resolve(event.data); // surface final output back to the tool caller
});
setTimeout(() => {
eventSource.close();
reject(new Error("timeout"));
}, timeoutMs);
});
}
In practice, from Claude Desktop you’d chain two calls:
create_sessionorsend_messageto dispatch work to a Managed Agentwait_for_idleto block until the agent finishes and return the result
The second call converts an open-ended SSE stream into a synchronous tool response that Claude can reason over. Without this shim, you’d need a separate polling loop outside the tool call boundary — which breaks the conversational flow entirely.
Step 5: The HTTP path for the claude.ai Connector
For cloud deployment, server-http.ts exposes the same nine tools over Streamable HTTP with bearer token auth. The cookbook ships a Dockerfile ready for Fly.io, Railway, or Render:
FROM node:lts-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
ENV PORT=3000
EXPOSE 3000
CMD ["node", "dist/server-http.js"]
Deploy that, set your ANTHROPIC_API_KEY as an environment variable, and register the URL in the claude.ai Connector settings (org-admin required). The bearer token in the Authorization header is validated on every request — this is the production-ready path for teams.
Where this breaks
The commit is explicit about what’s missing: authoring, destructive, and secret endpoints were deliberately excluded. That means you can’t create or modify agent definitions through this MCP bridge, you can’t delete sessions or agents, and you can’t read or write secrets attached to agents. You’re limited to session management and message dispatch — which covers most runtime use cases but not the full administrative surface.
The org-admin gating on the Connector path is also a real constraint for teams where the Claude admin and the developer are different people. The stdio path sidesteps this for local development, but anything you want to deploy to production for non-admin teammates requires that access.
The “DIY bridge” framing in the commit is worth taking seriously. When Anthropic ships a first-class “publish agent to claude.ai” flow, some of this scaffolding becomes redundant — particularly the authoring-adjacent capabilities this bridge doesn’t expose. Build workflows on the runtime tools (send_message, wait_for_idle, session management) and you’ll be on solid ground regardless of what the native flow looks like.
Next steps
The fastest path to value here is wiring a specialized Managed Agent — one you’ve already tuned with system prompt, tools, and memory — into a Claude Desktop workflow via the stdio path. You get persistent agent identity, tool state, and memory across calls, all surfaced through the standard MCP tool interface. Clone the cookbook, register the stdio server, and call list_agents first to orient yourself. The wait_for_idle shim is the piece that makes everything composable — once you see it fire in Claude Desktop, the rest of the architecture makes immediate sense.
← Back to blog