AI Thinkers Logo
    Insights/

    Salesforce to Teams on AWS: Building an Escalation Agent with Amazon Bedrock AgentCore

    AI AgentsAmazon Bedrock

    Salesforce to Teams on AWS: Building an Escalation Agent with Amazon Bedrock AgentCore

    July 20, 2026
    Vikram Thakur

    Vikram Thakur

    Architecture diagram: an EventBridge schedule triggers a notifier Lambda that queries Salesforce through AgentCore Gateway and posts alerts to Teams; Teams @mentions flow through Azure Bot Service and a bridge Lambda to an AgentCore Harness running Claude, which queries Salesforce through the same Gateway.

    In our last post we built an escalation agent with Copilot Studio and Power Automate: when a purchase-order case in Salesforce is escalated, an alert lands in Microsoft Teams. It worked, and it took an afternoon.

    This time we built the same agent on AWS, using Amazon Bedrock AgentCore and Claude. The goal wasn't to replace the Microsoft version. We wanted to see what you gain when the agent is something you design and control yourself, and what it costs to get there.

    What we wanted the agent to do

    Two things, which we kept deliberately separate:

    • Push: when a case becomes Escalated, post an alert in the team's channel within about a minute, once per escalation.
    • Pull: let anyone in the channel ask the agent follow-up questions, such as "what's escalated today?" or "what should I check on this one?", and answer from live Salesforce data.

    Alerts need to be boring and reliable. Conversations benefit from a model that can reason. Separating the two paths means each can be built the way it should be.

    The architecture

    Architecture diagram: an EventBridge schedule triggers a notifier Lambda that queries Salesforce through AgentCore Gateway and posts alerts to Teams; Teams @mentions flow through Azure Bot Service and a bridge Lambda to an AgentCore Harness running Claude, which queries Salesforce through the same Gateway

    The alert path (steps 1–4).

    An EventBridge schedule runs a small notifier Lambda every minute.

    The notifier asks Salesforce for escalated cases through AgentCore Gateway.

    It compares the result with the cases it has already alerted on.

    It posts a card to Teams for anything new.

    Because it tracks state, editing an already-escalated case doesn't produce a second alert.

    The conversation path (steps 5–8).

    A Teams @mention goes to Azure Bot Service.

    Bot Service forwards it to a bridge Lambda, which verifies that the request really came from Microsoft.

    The bridge passes the question to an AgentCore Harness running Claude.

    The agent uses the same Gateway tools to look things up, and the answer comes back into the same thread.

    Both paths share one Salesforce connection, and neither Lambda ever holds a Salesforce credential. AgentCore Identity keeps the OAuth client, and the Gateway fetches tokens as it needs them.

    Step 1: Connect Salesforce the right way

    Create an External Client App in Salesforce with OAuth enabled and the client credentials flow turned on, running as a dedicated read-only integration user. The agent works on behalf of a team rather than an individual, so there's no per-user sign-in to manage.

    The detail that matters: Salesforce only issues client-credentials tokens from your org's My Domain (yourorg.my.salesforce.com), not the generic login endpoint. In AgentCore Identity, register the OAuth client as a custom provider using your My Domain discovery URL.

    Step 2: Give the agent tools, and only the tools it needs

    AgentCore Gateway turns APIs into tools an agent can call. There is a built-in Salesforce template, but we wrote our own two-endpoint OpenAPI spec instead: one operation runs a SOQL query, the other fetches a case by ID. Both are GETs.

    That makes the agent read-only by construction. Even if someone asks it to close a case, and the prompt somehow failed, there's no tool that could do it.

    Step 3: Build the agent with AgentCore Harness

    Harness is AgentCore's managed way to run an agent without packaging code. You choose a model, write a system prompt and attach the Gateway. Our prompt does four things:

    • defines the agent's narrow role (inform, don't resolve),
    • fixes a response format for every case,
    • tells it never to invent data it didn't get from a tool, and
    • tells it to refuse any request to change records.

    Harness also adds short-term memory, so follow-up questions in a thread keep their context.

    Step 4: Bring it into Teams

    Teams doesn't talk to AWS directly. Every Teams bot goes through Azure Bot Service, so the bridge between the two is a small Lambda (about 200 lines of Python) that:

    • validates the Bot Framework token on every request,
    • acknowledges immediately so Teams never times out,
    • strips the @mention text, and
    • gives each Teams conversation its own agent session.

    Register an Azure Bot (the free tier covers Teams), point its messaging endpoint at the Lambda, and upload a Teams app manifest that references the bot.

    Step 5: Add proactive alerts

    The notifier Lambda reuses everything above. It calls the Gateway directly with IAM credentials, formats a card, and posts it as the same bot. When the bot is first used in a channel, the bridge records that channel, so the notifier knows where to post.

    On orgs that support it, Salesforce Event Relay can push changes to EventBridge in real time instead of polling. The rest of the design stays the same.

    What the team sees

    A Teams channel showing an escalation alert card for a discontinued SKU, followed by a team member asking the agent what to check, and the agent's read-only answer

    The alert arrives, someone asks a question in the thread, and the agent answers from live data. Nobody has to open a dashboard or copy details from one system to another.

    What we learned the hard way

    Six lessons learned: use your Salesforce My Domain, write your own tool spec, load specs from S3, re-check IAM when credentials change, confirm model access, and send the MCP protocol version header

    None of these are obvious from the documentation, and each one stopped us for a while:

    • Use your My Domain for tokens. The generic Salesforce login endpoint rejects the client credentials flow with an unhelpful 400 error.
    • Write your own tool spec. The Salesforce template assumes Developer Edition hostnames. Two endpoints you control are easier to reason about, and much safer.
    • If the console won't save your schema, use S3. The inline editor sometimes submitted its placeholder instead of our spec. Uploading the file to S3 and pointing the target at it worked first time.
    • Re-check IAM when you change credentials. The Gateway's service role was scoped to the first OAuth client we attached. Switching providers meant adding a permission.
    • Confirm model access before you debug anything else. A model can be blocked at the account level, for example by a Marketplace subscription issue. A quick playground test tells you right away.
    • Send the MCP protocol version. When calling the Gateway directly from your own code, include an MCP-Protocol-Version header, or requests are rejected.

    Copilot Studio or AgentCore?

    Both are good answers to different questions.

    Copilot Studio gets a working agent into Teams in hours, stays inside Microsoft 365 governance, and suits teams that want low-code. Choose it when speed and simplicity matter most.

    AgentCore takes longer to set up, but you control the model, the tools, the prompt and the alert logic. It's also where you'd go when the rest of your stack already runs on AWS, or when you need behaviour the low-code tools don't offer, like once-per-escalation alerts posted by the agent itself.

    What's next

    Next we'll add real-time triggers with Salesforce Event Relay, add CloudWatch alarms and a dead-letter queue, and, carefully and with human approval, let the agent take its first small actions, such as adding a note to a case. The pattern also generalizes well beyond purchase orders: any system that produces a status change a human needs to act on can use it.

    Salesforce to Teams on AWS: Building an Escalation Agent with Amazon Bedrock AgentCore | AIThinkers Blog