The assumption was that MCP is the right way to give AI agents access to external tools. Wire a server to the agent configuration and the tools appear. That’s the design.
In early July I built a CFO agent for Mission Control to field money questions. Is this week’s AWS spend unusual. Where is the money going. The awslabs billing MCP server has 33 tools covering cost-explorer, compute-optimizer, budgets, anomaly detection. Seemed like exactly the right fit.
Interactive test first. I ran claude --mcp-config mcp.json on the EC2 box. All 33 tools connected in 1.66 seconds. I asked it what AWS cost in the last seven days. It came back with $1.75, anomaly detection ran. The whole thing worked.
Then I deployed it.
The CFO’s production runtime is a headless claude --print spawn, one per turn. In that context, the MCP server status came back as pending. No tools at all. Every call.
I tried four approaches. Plain --mcp-config flag. An enableAllProjectMcpServers: true setting in the agent config. Bypassing permissions mode, which was already set in production. And claude mcp add, the CLI’s own sanctioned registration path. Same result every time. Pending status, no tools, and nothing in the output explaining why.
What I found, by pulling the raw stream-json system-init event directly, is that headless mode freezes before the MCP handshake completes. The tool index never gets populated. Not a config problem or a permissions problem. Behavior specific to the --print path.
So I gave the CFO bash access and pointed it at aws ce --profile cfo-billing. Direct AWS CLI, no MCP layer. That connects immediately, returns real cost data, and works in the headless spawn exactly as it would anywhere.
The billing MCP server is fine. The interactive session works exactly as it should. I’d confirmed the tool against a working configuration, and that confirmation was real. It just happened to be a different runtime than production actually runs.