I built a production-shaped multi-agent app on Amazon Bedrock AgentCore — here's what broke, what I learned, and how I actually worked with AI
After 15+ years of cloud engineering and carrying the AWS Certified Solutions Architect – Professional cert, I wanted to answer a question I keep getting from other engineers: what does it actually take to move an "AI agent demo" to a production-shaped architecture?

So I built one in public: ShowRunner — a movie-night agent that figures out what's on tonight, where you can watch it near you, and whether you have time to grab food first.
The movie app is the vehicle, not the point. The point is the architecture underneath it — and the honest story of building it with Claude (Claude Code, powered by Fable 5) as my pair. Including the parts where we drove straight into a wall.
Repo (free and keyless — clone it and run it, no API signups): github.com/andaro74/showrunner
The architecture

Three layers:
Layer 1 — Two keyless MCP servers. tvmaze (what's on tonight) and places (cinemas, restaurants, travel time over OpenStreetMap). Both are plain FastMCP servers with zero framework code inside — no Strands imports, no LangChain imports. That neutrality is the whole trick, and it pays off in Layer 2.
Layer 2 — An orchestrator + two framework specialists. A Strands orchestrator is the single entry point. Its only tools are two delegates — ask_show_expert and ask_places_expert (the agents-as-tools pattern). The show specialist runs on Strands and owns only the tvmaze server; the places specialist runs on LangGraph and owns only the places server. Same MCP servers, two different frameworks, zero per-framework tool rewrites. That's MCP portability made concrete — which framework serves which server is interchangeable.
Layer 3 — Amazon Bedrock AgentCore, the production concerns, adopted one at a time:
- Runtime — serverless hosting. Deployed shape is three runtimes, not five: the orchestrator (the specialists ship inside its bundle and run in-process) plus the two MCP servers.
- Memory — short-term session replay, plus long-term namespaces per user (
/users/{id}/preferences,/users/{id}/facts). Next week it already knows you hate horror movies. - Identity — an inbound Cognito JWT. Here's the nuance: the APIs are keyless, so Identity isn't protecting a secret. It exists so one user's remembered preferences can't leak into another user's movie night. The
subclaim becomes the memory actor — a caller-supplied user ID can't impersonate anyone. - Gateway — managed tool routing. The caller's JWT is forwarded on every request.
- Cedar Policy Engine — default-deny authorization. Identity answers who is calling; Cedar answers what they may do. Each of the seven tools is permitted individually, so a newly added tool is refused until explicitly approved.
- Evaluation — LLM-as-a-judge, offline in CI and online on traces.
- Observability — OTEL on all three runtimes, flowing into CloudWatch's GenAI views as one connected trace per turn.
What one turn looks like

Identity verifies the caller → Memory loads their history → the orchestrator (Claude on Bedrock) splits the request → each sub-question goes to the right specialist, through the Gateway, authorized by Cedar → the plan comes back assembled (show + cinema + food + travel time) → new facts persist to Memory → the whole thing lands in CloudWatch as a single trace.
The honest part: what went wrong
This is the section I wish more AI-build posts had. Every one of these cost real time.
1. A "plausible" model ID rolled back an entire deploy. For the evaluator, a reconstructed-from-memory inference profile ID (right family, wrong date suffix) passed agentcore validate… and then failed at CloudFormation with the stack rolled back. Lesson: current inference profiles carry no date suffix — copy IDs, never reconstruct them. And verify two independent things before deploying: that the profile exists, and that your account has an agreement for it. Passing one tells you nothing about the other — we failed each of them once.
2. --allowed-audience vs --allowed-clients are not synonyms. They validate different JWT claims, and Cognito puts the client ID in a different claim per token type (aud on ID tokens, client_id on access tokens). Agents present access tokens — so --allowed-audience makes every call fail with what looks like a broken credential. Decoding an actual token is what solved it.
3. The MCP runtime contract bit us on port AND bind address. AgentCore has two service contracts: HTTP on 8080 (/invocations), MCP on 8000 (/mcp). We copied 8080 from the HTTP example — the platform probed 8000, found nothing, and every call returned "Runtime initialization time exceeded" while our server ran perfectly healthy on a port nobody was looking at. Also: bind 0.0.0.0, because the default 127.0.0.1 is unreachable from outside the container.
4. Our own package shadowed the real langgraph — only in production. The entry file's directory goes on sys.path, and we had a folder named agents/langgraph. The real langgraph is a namespace package, ours was a regular package, and regular beats namespace — so the container died at import while everything worked locally. Fix: entry files live at the repo root. This class of bug cannot reproduce on your laptop, which is exactly what makes it dangerous.
5. Observability failed silently — twice. The OTEL wrapper without the ADOT distro exports nothing, with no error anywhere. And the tooling's defaults disagree with each other: the CDK treats a missing instrumentation key as on, while the CLI wrote false for the MCP runtimes — so the orchestrator was instrumented and the servers silently weren't. Verify by looking at the data (fresh events in the spans log stream), never the config.
6. Security that looks redundant usually isn't. The MCP runtimes carry their own JWT authorizer even though the Gateway already validates the same token. Without it they fall back to IAM auth — and anyone with InvokeAgentRuntime permission could reach the tools directly, bypassing every Cedar policy, because Cedar binds at the gateway only. Both doors need the same key.
How the work was actually split
This is where I want to be precise, because "I built it with AI" hides the interesting part.
I brought the architecture judgment. The three-layer design, the decision to deploy three runtimes instead of five (stateless single-caller specialists don't earn a network hop and a second auth surface), the ordering rule Identity → Gateway → Policy Engine → Policies, the insistence that a refactor should transform test invariants rather than delete them, and the call on when "redundant" auth is actually the design working. That's the 15 years talking.
Claude Fable 5 brought speed and breadth — through Claude Code's own workflow: plan mode before any file was touched, a lean CLAUDE.md as project memory, a subagent to research Overpass QL in isolation, a reusable skill for adding MCP tools, and hooks that ran ruff/pytest on save and blocked secrets from ever being committed. Every step landed as a small, verified, single-purpose commit — so git log is the tutorial.
Neither of us would have shipped this alone at this pace. The AI without the architecture judgment would have happily deployed five runtimes and IAM-reachable tools. Me without the AI would still be reading Overpass QL docs.
The full step-by-step method — with the exact prompts used at every phase, including the failures above — is in BUILD.md in the repo.
Takeaways for engineers starting this journey
- Adopt AgentCore primitives a la carte, one commit each. Each one is independently reviewable and independently breakable.
- Keep MCP servers framework-agnostic. It's what makes multi-agent composition nearly free later.
- The bugs that hurt are the ones that can't reproduce locally and the ones that fail silently. Design your verification around the deployed artifact and the actual data.
- Write down the gotchas as you hit them. My skill's "Gotchas" section did more for reliability than the happy path ever did.
If you're building agentic systems on AWS, I'd genuinely like to compare notes — especially if you've hit different walls than I did. The repo is open: github.com/andaro74/showrunner. What would you add as the third MCP server?
Transparency note: this article was generated with Claude Fable 5 — but driven, reviewed, and fact-checked by me, drawing on the project's actual build log. The same division of labor that built the project wrote the post about it.
#AWS #AmazonBedrock #AgentCore #AgenticAI #MCP #GenAI #SolutionsArchitecture #ClaudeCode #Anthropic