AWS Builder Center
Serve agentic AI surfaces from one MCP backend on Amazon Bedrock AgentCore

Serve agentic AI surfaces from one MCP backend on Amazon Bedrock AgentCore

A hotel sells rooms on ChatGPT, Claude, Alexa+, Meta Muse, Perplexity, and WhatsApp from one MCP server on Amazon Bedrock AgentCore, with payment on the server.

This article is part of the series Agentic Enterprise Capabilities: Solutions for the Hospitality Industry. Upcoming articles explain how in-stay interactions work for property operations staff, how guests and staff interact through their personal agents, and how to embed EnterpriseLLM, a purpose-built small language model for the industry and the enterprise. Follow me to get an alert when each one is published.
Travelers can now find and book a hotel stay by talking to an AI assistant, and Alexa+ is one of the surfaces adding that path (Alexa+ launches new ways to build experiences ). This post shows how a hotel can sell rooms on six of those assistants (ChatGPT, Claude, Alexa+, Meta Muse, Grok, and Perplexity) from a single Model Context Protocol (MCP) server on Amazon Bedrock AgentCore . It covers discovery, booking, and payment, with one booking service behind every surface. The companion post, In-stay guest services and hotel staff tools on AI agent surfaces with Amazon Bedrock AgentCore , covers the stay itself and tools for hotel staff on the same backend.

Business problem

Each AI surface connects to a hotel on its own terms, with its own connector model, sign-in options, and review rules (ChatGPT plugin guidelines ; Claude review criteria ; Alexa+ certification guidelines ). Some render interactive views, and others show text alone (MCP extension client matrix ). Some run tool calls without asking the guest first (Perplexity Agent API MCP tools ). Building one integration per surface multiplies the cost, and over time those integrations drift apart.
MCP gives the hotel one integration point. To serve every surface from it, the hotel needs a backend that:
  • sets every price from the hotel's own systems, so no agent decides what a guest pays;
  • places every tool in a trust zone, so any allowed surface can search and quote, and only a signed-in guest can book or pay;
  • confirms each booking and takes each payment on the server, whatever the surface does;
  • lets the hotel allowlist, rate-limit, or cut off one surface without touching the others;
  • shows the hotel's own property content and media the same way on every surface.

The solution in action

The omnichannel walkthrough is the reference implementation of this solution. It extends a hotel's omnichannel experience, across web, mobile, and online travel agencies (OTAs), to agentic surfaces, with data in sync. A guest books a stay on each surface: Meta Muse in text only; Claude, ChatGPT, and Grok in interactive MCP Apps beside chat; and the hotel's own assistant with UI, chat, and voice together on one screen.
VIDEO: More >
 
About the live demo recording. The recording uses ZenithStays, a reference brand for demo purposes, and synthetic data for hotels in a few cities, in place of the hotel's systems. Every guest payment runs on Stripe's hosted checkout page in a Stripe sandbox (test mode), and the recording shows no partner purchase.
Built with guidance from the book Practical Agentic Coding .

Solution architecture

Every guest surface reaches one MCP server through the guest gateways on Amazon Bedrock AgentCore Gateway (Figure 1). The hotel's systems stay the systems of record for rooms, rates, reservations, and the folio (the guest's running bill). The hotel can host each of them on AWS, on premises, or as a vendor's software as a service.
 
Architecture diagram: AI agent surfaces reach one MCP server on Amazon Bedrock AgentCore through a s
Figure 1 shows the full reference architecture. This post follows the guest's path through it:
  • Guest surfaces. The hotel's website and mobile app, and the online travel agencies, book through the central reservation system (CRS). The agentic surfaces are chatbots, which show text and structured data, and voice and UI agents, which add voice or MCP Apps views.
  • Front door. Amazon CloudFront , the two guest gateways, Amazon Cognito  with an app client for each surface, and an OAuth front for sign-in.
  • Application. The MCP server on Amazon Bedrock AgentCore Runtime, which reads an Amazon Bedrock Managed Knowledge Base of hotel content; a booking service of deterministic AWS Lambda  functions that applies the hotel's rules; an AWS Step Functions  purchase workflow; a concierge agent on AgentCore harness that only plans; and Amazon Bedrock  for models and guardrails.
  • Data and integrations. Amazon EventBridge  for events and hold expiry, Amazon DynamoDB  for holds, idempotency keys, and the loyalty record, the internal concierge and payments gateways, and AgentCore payments.
  • Hotel systems. The CRS, the property management system (PMS), and folio and billing.
  • Payments and partners. Stripe for guest checkout, a wallet provider (Coinbase CDP or Stripe (Privy)), and partner vendors.
  • Cross-cutting services. Policy in AgentCore, Amazon Bedrock AgentCore Identity, AWS WAF , AWS Secrets Manager , AWS Key Management Service (AWS KMS) , Amazon Bedrock AgentCore Observability, and AWS CloudTrail .

Trust zones

Each tool belongs to exactly one trust zone, and a signed-in guest can also call every Public-zone tool.
ZoneCallerCredentialTools
PublicAny allowed surface clientA token with catalog.read: the surface's service credential, or a signed-in guest's tokenSearch hotels, read a hotel's details and policies, and get a quote that holds no rooms
GuestA signed-in guestA user access token from the guest user poolHold a room, get a checkout link, manage the guest's own reservations, and start and approve a partner purchase
Two more zones sit off the guest path. The concierge agent and the purchase workflow call Internal-zone tools through the concierge and payments gateways with IAM roles, and no guest-facing gateway reaches them. Only the booking service calls the hotel's systems, through one adapter per system, with credentials from AgentCore Identity.
Each guest has one account. The guest user pool is the hotel's single guest identity, for the website, the mobile app, and every agent surface. Cognito federates the identity providers that guests already have, such as Login with Amazon, Google, and Apple (Cognito social identity providers ). At the first sign-in, a pre token generation Lambda trigger (pre token generation trigger ) enrolls the guest in loyalty and adds the loyalty number to the access token, so no guest links a membership.

How the solution works

Sign guests in through the OAuth front

A surface that calls a guest gateway without a valid token receives HTTP 401 and a link to the protected resource metadata, as the MCP authorization specification requires (MCP authorization, 2025-06-18 ). It follows the link, signs the guest in with the authorization code grant and Proof Key for Code Exchange (PKCE), and retries with the bearer token.
An OAuth front on the hotel's own hostname fits Cognito to that flow. CloudFront Functions on the viewer request serve the metadata document, return the 401 challenge, and pass only the parameters that Cognito accepts on to Cognito managed login. No Lambda function answers an unauthenticated caller, and the gateways validate every token against Cognito.
Enable all four MCP versions on every gateway, so each surface connects with the version it uses. AgentCore Gateway translates between 2025-era clients and 2026-07-28 MCP server targets (How AgentCore Gateway supports the MCP 2026-07-28 spec ):
1
2
3
4
5
"protocolConfiguration": {
"mcp": {
"supportedVersions": ["2025-03-26", "2025-06-18", "2025-11-25", "2026-07-28"]
}
}

Data security: check the zone on every tool call

Each surface connects through one MCP URL, so it reaches exactly one gateway, and that gateway enforces every zone the surface uses, tool by tool. The two guest gateways share their targets, interceptors, and policies. They differ only in how they check the caller's token:
  • Audience gateway. A JSON Web Token (JWT) authorizer validates each call against Cognito and checks the token's aud claim against the gateway's own MCP URL, plus the allowed clients and scopes (gateway inbound authorization ). It serves clients that send the OAuth resource parameter, such as ChatGPT, Claude, and the hotel's own assistant.
  • Compatibility gateway. The same kind of authorizer checks the allowed clients and scopes for clients that can't carry an audience, such as Meta Muse, Alexa+, and WhatsApp through Meta Business Agent.
On both, Policy in AgentCore evaluates each tool call against Cedar policies before the gateway allows it (Policy in Amazon Bedrock AgentCore ). The policies permit Public-zone tools for any allowed client, and Guest-zone tools only for user tokens, so a service credential reaches only Public-zone tools.
A server "MUST NOT pass through the token it received from the MCP client", the MCP specification says (MCP authorization, 2025-06-18 ). So a request interceptor, a Lambda function that runs before each request reaches a target (gateway interceptors ), takes the guest's identity from the token that the gateway already validated. It checks the tool's zone again, removes any identity the model supplied, and denies the call on any error:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Outline for reference only; helpers omitted. Request interceptor on both guest gateways.
def handler(event, context):
try:
request = event["mcp"]["gatewayRequest"]
body = request["body"]
claims = token_claims(request["headers"]) # validated by the JWT authorizer
params = body.setdefault("params", {})
meta = {k: v for k, v in (params.get("_meta") or {}).items()
if not k.startswith("hotel/")} # drop caller-supplied hotel keys
if body.get("method") == "tools/call":
require_zone(params["name"], claims) # Public or Guest; raises to deny
params["arguments"] = drop_identity_args(params.get("arguments") or {})
if "username" in claims: # a user token; a service token has none
meta["hotel/guest"] = claims["sub"] # the only identity the server trusts
params["_meta"] = meta
return {"interceptorOutputVersion": "1.0",
"mcp": {"transformedGatewayRequest": {"body": body}}}
except Exception:
return deny(event, "request could not be authorized") # fail closed
A response interceptor then removes tokens, card data, and every field outside the tool's allowlist. Because the guest ID comes from the token, a request for another guest's reservation returns not_found.
Close the paths around the gateway. A regional AWS WAF web ACL on each guest gateway blocks any request without a secret header that only your CloudFront distribution adds (protecting your gateway with AWS WAF ). The MCP server's resource-based policy on AgentCore Runtime allows only the two guest gateways' roles (restrict IAM inbound invocation to your gateway ), so every call passes the interceptor and the policies.

Return text first, and views where the host renders them

An MCP Apps view is HTML from a ui:// resource, rendered by the host in an isolated iframe (MCP Apps announcement ). Figure 2 shows which surfaces render views. Views matter to hotel brands, because they let the hotel own what guests see, such as photos of the hotel, its rooms, and its facilities.
 
Table comparing ten guest AI surfaces on MCP connector support, MCP Apps views, sign-in model, and d
So every tool result carries readable text and structured data, and the text answers the guest on its own. A tool that renders a view adds a UI pointer:
1
2
3
4
5
6
7
8
9
{
"content": [{ "type": "text",
"text": "King room, October 12 to 14: $389 total including taxes and fees. Free cancellation until October 10." }],
"structuredContent": {
"kind": "offers",
"offers": [{ "offer_id": "of_7Qx", "room": "King", "total_minor": 38900, "currency": "USD" }]
},
"_meta": { "ui": { "resourceUri": "ui://hotel/app@3f9a1c2b.html" } }
}
Put resourceUri on the tool result as well as on the tool definition, because Alexa+ renders custom UI when the tool response carries it (Alexa+ client lifecycle ). Keep every ui:// resource free of guest data, because Policy in AgentCore always allows resources/list and resources/read (Use an AgentCore Gateway with Policy in AgentCore ).
Hotel content takes the same shape. ask_property_info takes a property code and a question, and the MCP server answers from the managed knowledge base, filtered to that property, with text, structured data, and source IDs (Configure and customize queries for managed knowledge bases ).

Connect the hotel's systems of record through APIs

The booking service is the only caller of the CRS, the PMS, and the folio, and every call carries the property code. It validates each tool argument first, so no agent or prompt reaches the hotel's systems, and the hotel's prices and rules hold on every surface. Rates, availability, and new bookings come from the CRS, the CRS and the PMS keep reservations in step themselves (What is a hotel CRS ), and partner charges post to the folio. An AgentCore Identity credential provider holds each system's API key or OAuth 2.0 client credentials, so no credential sits in the booking service's code or configuration (AgentCore Identity credential providers ).
Changes, such as a modified reservation or a new folio charge, come back as events on an Amazon EventBridge Custom Event Bus (Custom Event Bus event sources ). Use the reservation ID as the event group, so changes to one reservation arrive in order, and skip any event ID already applied (what is the Custom Event Bus ).

Book in two steps, then capture

The server confirms every booking itself, because some surfaces run tool calls without asking the guest:
  1. Quote. search_hotels and get_room_offers are public tools that hold nothing. Each offer carries an all-in total, the cancellation terms, and an offer ID.
  2. Hold. A Guest-zone tool holds the room for 15 minutes, bound to the guest, and places a tentative reservation in the CRS where the CRS supports one. An EventBridge schedule releases expired holds.
  3. Agree. The host shows the total and the terms, and the guest agrees in the conversation.
  4. Commit. The commit sends the hold, the accepted total, and an idempotency key. The booking service re-prices against the CRS and returns totals_changed if anything moved. Otherwise it returns a hosted checkout link that authorizes now and captures later.
  5. Pay. The guest pays on the provider's hosted page, which authorizes the payment method without capturing it (place a hold on a payment method ).
  6. Book, then capture. The payment event reaches the booking service through Amazon EventBridge, with no public endpoint (Send events to Amazon EventBridge ). The booking service books the stay in the CRS, and only then captures the payment. If the CRS refuses the booking, the booking service cancels the authorization, so the guest pays nothing.
  7. Confirm. The guest sees the CRS confirmation number, and hosts that render views show a receipt.
Store each idempotency key with its result, so a retried commit returns the first result and never books twice (REL04-BP04 Make mutating operations idempotent ).

Move money both ways

The guest pays the hotel, and the hotel pays partner vendors (Figure 3).
 
Payment diagram: the guest pays the hotel on a hosted checkout page, and the hotel pays partner vend
Guests pay on a hosted checkout page. The commit tool returns a link to the payment provider's hosted checkout page, where the provider takes the card, so no card data reaches a tool, the model, or your MCP server. Alexa+ runs checkout itself, through endpoints that you implement (Alexa+ checkout endpoints ). It gets its own adapter on Amazon API Gateway routes with a JWT authorizer, and the hotel's PCI DSS review sets that adapter's scope.
Signed-in guests can pay with saved methods, points, or the folio. Money authority rises in tiers. Below a small cap, the host's own tool confirmation stands as the guest's consent. Above it, the guest approves on a hosted page behind guest sign-in, and above a higher cap, the guest also clears a passkey step-up. Hosts that run tool calls without approval get a small cap of zero.
The hotel pays partners through AgentCore payments. AgentCore payments pays x402 (HTTP 402-based) and Machine Payments Protocol (MPP) requests within the limits of a payment session (Amazon Bedrock AgentCore payments ). That fits partner purchases that the concierge plans, such as a harbor tour. After the guest approves, the workflow pays through pay_vendor inside a capped session, the vendor confirms, and the booking service posts the charge to the guest's folio. The hotel pays from a wallet that it funds with a stablecoin, so get a legal review first: AWS Service Terms section 50.15 state that AWS provides no regulated financial services as part of AgentCore payments and is not in the flow of funds (AWS Service Terms ).
These controls are up to you:
  • Allowlist payees. AgentCore payments doesn't enforce payTo restrictions server-side (AgentCore payments security best practices ), so check every payTo address against the hotel's allowlist, and accept none from a model.
  • Cap every payment session at the quoted price plus a small buffer, because spending limits are optional in the API (CreatePaymentSession ).
  • Pay from a workflow, through a gateway. Policy in AgentCore evaluates only calls that pass through a gateway, so the workflow calls pay_vendor on the payments gateway with IAM authorization. Its policies pay only against a matching guest approval from the last 10 minutes, and pay each approval once. Give the concierge only the concierge gateway, and limit its tools with allowedTools (AgentCore harness tools ).
  • Track the signing grant. The hotel grants the agent permission to sign for 7 to 90 days (AgentCore payments wallet setup ), so alert operations before a grant expires.
Turn on CloudTrail data events for the AWS::BedrockAgentCore::Payments resource type to keep an audit trail; they are off by default (CloudTrail data events ).

Get ready for every surface

Build one path end to end first:
  1. Create the guest user pool on the Cognito Essentials plan, with one resource server per MCP hostname (Cognito resource binding ).
  2. Deploy the MCP server to AgentCore Runtime with search_hotels and get_room_offers only.
  3. Create the audience gateway with a JWT authorizer, all four MCP versions, and the request interceptor. Attach the server as an MCP server target (AgentCore Gateway MCP server targets ), and lock the Runtime to the gateway's role.
  4. Put CloudFront, the OAuth front, and the regional web ACL in front of the gateway.
  5. Confirm the sign-in and a text-only answer, and confirm with a contract test that the guest's identity reaches the MCP server.
Then add surfaces one at a time:
  • Give each surface its own app clients, so you can allowlist, rate-limit, or cut off one surface alone. Alexa+, which uses a service credential and guest sign-in together, needs two (Cognito OAuth grants ).
  • Plan revocation and rate limits. Cut a surface off with a forbid policy for its app clients, keep access tokens short-lived (Cognito token revocation ), and key rate limits on the client ID and subject rather than on IP addresses (gateway rate limit dimensions ).
  • Meet each surface's review. ChatGPT review requires the readOnlyHint, destructiveHint, and openWorldHint annotations on every tool, and its guidelines allow commerce only for physical goods, so a hotel app needs enablement from OpenAI (ChatGPT plugin guidelines ). Claude connectors meet Anthropic's review criteria (Claude review criteria ). Alexa+ is in preview for select partners (Alexa+ for Builders ), and its MCP Toolkit serves the United States (Alexa+ MCP Toolkit overview ).
  • Connect WhatsApp through Meta Business Agent on the compatibility gateway, with a client-credentials app client for public tools and per-guest tokens for booking (Meta Business Agent connectors ).
  • Add MCP Apps views for the hosts that render them, once text-only results work on every surface, and set each host's ui.domain (OpenAI plugin reference ; Claude MCP Apps getting started ).
  • Keep every endpoint before sign-in off Lambda. Serve it from CloudFront Functions, a provider-hosted page, or an event integration with no public endpoint, and pin each service-principal permission with aws:SourceArn.
  • Rehearse partner purchases in a separate test account, with the payee allowlist, the capped session, and the approval window in force from the first purchase.
Vendor capabilities change; the vendor details here reflect documentation as of October 24, 2026.

Conclusion

A single MCP server on AgentCore can serve every agentic surface in this post when their differences are handled as front-door configuration rather than as separate integrations. Place each tool in a trust zone, give each guest one hotel account, take identity from the validated token, write results that work as text, and confirm bookings and take payment on the server. To start, see AgentCore Gateway MCP server targets  and gateway inbound authorization .
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article