Inspiration

Local governments run on paperwork and phone tag. Anyone who's tried to get a food truck permit, dispute a utility bill, or report a pothole knows the drill: multiple calls, multiple departments, and no way to check status without starting over. We wanted to see what city services would feel like if they were genuinely conversational — not a chatbot that answers FAQs, but an agent that can actually do the workflow: check eligibility, take a payment, schedule an inspection, and tell you exactly what's still needed. That's a natural fit for Alexa+ and for the Model Context Protocol's stateful, tool-calling design, so we built Civic Concierge: an MCP server for a fictional city, Rio Cardenal, TX.

What it does

Civic Concierge is a self-hosted MCP server (Streamable HTTP, protocol version 2025-11-25) that exposes three city services as real multi-step case workflows instead of one-off Q&A:

  • Food truck permits — the flagship workflow. A single orchestrator tool (run_permit_workflow) drives a case through zoning eligibility, fee payment, health inspection scheduling, inspection results, fire marshal signoff, and final issuance, advancing as far as it can each call and reporting exactly what's still needed (a location, an inspection date, a pass/fail result) rather than guessing or stalling.
  • Utility billing — balance lookups and payment plans for past-due, eligible accounts.
  • 311 service requests — pothole, streetlight outage, water leak, illegal dumping, and animal control reports, auto-routed to the right department.

Every case is persisted to SQLite, so it survives a server restart — a resident (or an agent acting for them) can pick up exactly where they left off.

For the AWS Builder mini challenge, we also built a web chat simulator (a stand-in for the Alexa+ voice experience) backed by a real AWS Bedrock Converse API agent with tool use enabled. The chat UI connects to the MCP server as a genuine external client over Streamable HTTP — the same way a real Alexa+ integration would — and shows every MCP tool call it makes, for transparency.

How we built it

  • TypeScript + Node.js 22, using the official @modelcontextprotocol/sdk and Express for the Streamable HTTP transport, with one McpServer/transport pair per session.
  • Zod schemas validate every tool's input.
  • node:sqlite (Node's built-in SQLite module) for zero-dependency case persistence — no external database to stand up.
  • A step-validating orchestrator pattern: each workflow step is its own function that checks the case is in the right state before acting, and a single orchestrator advances as far as it can in one call, returning a structured {blockedOn, message} when it needs more input.
  • AWS Bedrock's Converse API (tool use / function calling) powers the web chat agent, looping tool calls against the live MCP tool list fetched from the server itself — no hardcoded tool definitions.
  • A small offline mock agent (regex-based intent matching, sharing the same MCP transport code as the Bedrock agent) let us build and test the entire web UI and tool-calling pipeline before we had AWS credentials configured.

Challenges we ran into

  • AWS SDK v3's discriminated-union types for Bedrock's Tool/ToolInputSchema don't structurally narrow from plain object literals, even when the shape is correct — required an explicit, documented cast.
  • Bedrock model access changed mid-build: AWS retired the old manual "Model access" approval page in favor of automatic activation on first invocation, plus a one-time Anthropic use-case form — the docs hadn't caught up yet, so we worked it out from the console directly.
  • Cross-region inference profiles: some Claude models on Bedrock can only be invoked through an inference profile rather than the bare model ID, which isn't obvious until you hit the error.
  • Getting a stateful, multi-step orchestrator to fail usefully — returning "need a proposed location" instead of a stack trace — took more iteration than a single-turn tool wrapper would have.

Accomplishments that we're proud of

  • A workflow orchestrator that genuinely reasons about state instead of scripting a fixed conversation tree — it advances as far as it safely can and stops cleanly exactly where a human decision is needed.
  • Real persistence: cases survive a server restart, verified explicitly.
  • A web chat agent that calls the actual MCP server as an external client over the actual transport — not an in-process shortcut — satisfying both the Alexa+ track's spirit and the AWS Builder mini challenge's requirement to really call Bedrock in code.
  • A running friction log kept throughout the build, documenting real integration snags (SDK typing, Bedrock console changes) as they happened.

What we learned

Stateful agentic workflows are a different design problem than single-turn tool wrappers: the interesting engineering is in the stop conditions — knowing precisely what's missing and saying so — not just in chaining API calls. We also learned that AWS's own Bedrock onboarding is evolving quickly (model access, cross-region inference profiles), so building against current documentation and the console directly, rather than assumptions, mattered more than expected.

What's next for Civic Concierge

  • Expand the health-inspection and payment-plan workflows with more realistic failure/retry paths.
  • Add a live Alexa+ integration once developer access is available, rather

Built With

Share this project:

Updates

Submission history