Flores Innovations

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?

cover

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

architecture (1)

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:

What one turn looks like

workflow

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

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