Introduction

Concepts like Model Context Protocol (MCP) enable us to easily integrate AI systems with internal resources, such as databases, personal calendars, and communication logs. This integration allows AI to automate tasks fully personalized to our needs, whether it’s summarizing weekly performance reports, generating client-specific presentations, or drafting tailored responses to customer inquiries. In this tutorial, we’ll show you how to build an AI agent that analyze insights of your AWS usage costs, generate a report out of it, and send the report over email using MCP and tools from xpander.ai. The AI agent we’ll build will have access to the following components:
  • AWS Cost Explorer MCP server: to analyze your AWS cost and usage data.
  • Notion interface: to transform the analysis into a final report based on a provided template in Notion. You can view the example template on this Notion page and copy it into your own Notion workspace.
  • xpander’s Send Email built-in tool: to send the final report to a specific email address.

Set Up

Before we get started, let’s set up a few prerequisites:

Install xpander client using npm

# Install Xpander CLI
npm install -g xpander-cli

# Login to your xpander account and create project
xpander login

Create a new Python environment

python3 -m venv .venv
source .venv/bin/activate

Create a requirements file and install them in the new Python environment

# Put these libraries inside requirements.txt
agno
mcp
openai
awslabs-cost-explorer-mcp-server
xpander-utils

# Install the requirements.txt into the new Python environment
pip install -r requirements.txt

Add AWS credentials into .env file

Add the following AWS and LLM-specific credentials inside a .env file:
# inside .env
OPENAI_API_KEY = <YOUR_OPENAI_API_KEY>
AWS_ACCESS_KEY_ID = <YOUR_AWS_ACCESS_KEY_ID>
AWS_SECRET_ACCESS_KEY = <YOUR_AWS_SECRET_ACCESS_KEY>

Set necessary AWS IAM user permissions

The AWS cost explorer MCP server allows our AI agent to analyze AWS costs and usage data. Therefore, we can ask our AI agent to perform tasks like comparing AWS costs accross different time periods, querying AWS cost data with plain English, forecasting our future AWS spending, etc. To enable this MCP server, your IAM user must have the following permission:
ce:GetCostAndUsage
ce:GetDimensionValues
ce:GetTags
ce:GetCostForecast
ce:GetCostAndUsageComparisons
ce:GetCostComparisonDrivers
You can learn more about how to add these permissions to your IAM user in the official AWS documentation.

Copy the xpander.ai template to equip the agent with necessary tools

Click the button below to equip your AI agent with the Notion interface and the Send Email tool provided by xpander. Once you click the button above, you’ll be redirected to your xpander.ai account to begin creating an agent graph composed of tools supported by xpander. img_1 Click “Next” to start creating the agent. Then, select the Notion interface you want to use. If you haven’t set up a Notion account, click “New Notion Interface”. img_2 If you choose “New Notion Interface” without having connected a Notion account, a red warning will appear in the agent graph. img_3 To resolve this, click the warning icon and complete the authentication process for your Notion account using your preferred method. img_4

Create an xpander configuration file

Add your xpander configuration, such as agent ID, organization ID, and xpander API key, into a file named xpander_config.json as follows:
# Inside xpander_config.json
{
    "agent_id" : "<your_xpander_agent_id",
    "api_key" : "<your_xpander_api_key>",
    "organization_id" : "<your_xpander_organization_id>"
}
To find your Organization ID and xpander API key, go to “Settings” in your xpander dashboard, then click on “API Keys”. To locate your Agent ID, navigate to the “Connect” tab in the Agent configuration, and you’ll find the Agent ID under the SDK section.

Create AI Agent Execution Logic

To connect the AWS Cost Explorer MCP server to our AI agent, we’ll use Agno. Agno is a Python framework for building multi-agent systems that allows us to integrate MCP servers as tools for our AI agents. Next, we’ll wrap the AWS MCP-powered Agno agent with the xpander backend, which is already equipped with tools like the Notion and Email interfaces you created from the template in the previous section.
# inside a Python script called agno_agent_with_aws.py


import asyncio
from dotenv import load_dotenv
import os
import json
from pathlib import Path
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.mcp import  MultiMCPTools
from agno.tools.thinking import ThinkingTools
from xpander_utils.sdk.adapters import AgnoAdapter

load_dotenv()

CFG_PATH = Path("xpander_config.json")
xpander_cfg: dict = json.loads(CFG_PATH.read_text())
Let’s create the execution logic for our AI agent using Agno and the xpander backend. To give our AI agent access to AWS, we need to set our AWS credentials in the env argument of the MultiMCPTools class from Agno. To build the agent, we’ll use the Agent class from Agno. In the tools argument, we’ll provide:
  • The MCP tools created using MultiMCPTools, and
  • The tools associated with the xpander agent graph we created from the template in the previous section.
This setup ensures that our AI agent has access to all the necessary tools to complete its tasks.
# still inside a Python script called agno_agent_with_aws.py

class AgnoAgent:
    def __init__(self, agent_backend: AgnoAdapter):
        self.mcp_tools = MultiMCPTools(
            commands=[
                "awslabs.cost-explorer-mcp-server"
            ],
            env={"AWS_ACCESS_KEY_ID": os.environ["AWS_ACCESS_KEY_ID"], "AWS_SECRET_ACCESS_KEY": os.environ["AWS_SECRET_ACCESS_KEY"]}
        )

        self.agent_backend = agent_backend
        self.agent = None
    
    async def run(self, message: str, user_id: str, session_id: str, cli: bool = False) -> str:
        """Run the agent with the given message and maintain state"""
        if self.agent is None:
            await self.mcp_tools.__aenter__()
            self.agent = Agent(
            model=OpenAIChat(id="gpt-4.1"),
            tools=[self.mcp_tools, *self.agent_backend.get_tools()],
            add_history_to_messages=True,
            search_previous_sessions_history=True,
            read_chat_history=True,
            instructions=[
                "Analyse AWS usage cost in any given timeline",
                "Create a detailed report based on the analysis",
                "Make sure to use the provided template and resources to generate the final report",
                "Do not add additional sections that are not mentioned in the provided template in your report",
            ],
            markdown=True,
            success_criteria="The response should contain the actual data of the requested resource",
            add_state_in_messages=True,
            add_datetime_to_instructions=True
            )
                    
        if(cli):
            response = await self.agent.aprint_response(message, user_id=user_id, session_id=session_id, stream=True)
        else:
            response = await self.agent.arun(message, user_id=user_id, session_id=session_id)

        return response
Beyond giving the agent the tools it needs to perform its tasks, integrating our AI agents into xpander’s backend offers several key advantages:
  • Persistent storage of chat history, state, and sessions
  • Built-in multi-user and multi-session support
  • Web-based Chat UI and Agent Builder for easy interaction and configuration
  • Centralized analytics, monitoring, and logging for all agent activity
  • Seamless deployment to xpander’s cloud infrastructure (with scaling, monitoring, and production readiness)
  • Customizable system prompts, tools, and storage via the backend

Create xpander Event Streaming Script

Now that we’ve built the agent’s execution logic, we’re ready to run the AI agent and perform the task. As mentioned above, one major benefit of xpander’s backend integration is the ability to interact with the agent through the Agent Builder and web-based Chat UI. To support this, xpander provides an event streaming feature that enables real-time chat with our AI agent.
# Inside a Python file called xpander_handler.py

import json
import asyncio
import os
from xpander_utils.events import XpanderEventListener, AgentExecutionResult, AgentExecution
from xpander_utils.sdk.adapters import AgnoAdapter

from pathlib import Path
from dotenv import load_dotenv
from agno_agent_with_aws import AgnoAgent
from xpander_sdk import LLMTokens, Tokens

load_dotenv()

CFG_PATH = Path("xpander_config.json")
if not CFG_PATH.exists():
    raise FileNotFoundError("Missing xpander_config.json")

xpander_cfg: dict = json.loads(CFG_PATH.read_text())

# xpander‑sdk is blocking; create the client in a worker thread
xpander_backend: AgnoAdapter = asyncio.run(
    asyncio.to_thread(AgnoAdapter, agent_id=xpander_cfg["agent_id"], api_key=xpander_cfg["api_key"])
)

agno_agent_with_backend = AgnoAgent(xpander_backend)

# === Define Execution Handler ===
async def on_execution_request(execution_task: AgentExecution) -> AgentExecutionResult:
    """
    Callback triggered when an execution request is received from a registered agent.
    
    Args:
        execution_task (AgentExecution): Object containing execution metadata and input.

    Returns:
        AgentExecutionResult: Object describing the output of the execution.
    """
    
    try:
        
        # initialize the agent with task
        await asyncio.to_thread(xpander_backend.agent.init_task, execution=execution_task.model_dump())
        
        IncomingEvent = (
            f"Incoming message: {execution_task.input.text}\n"
            f"From user: {execution_task.input.user.first_name} "
            f"{execution_task.input.user.last_name}\n"
            f"Email: {execution_task.input.user.email}" 
        )

        agent_response = await agno_agent_with_backend.run(IncomingEvent, execution_task.input.user.id, execution_task.memory_thread_id)

        # Record prompt and generation tokens
        metrics = agent_response.metrics
        llm_tokens = LLMTokens(
            completion_tokens=sum(metrics['completion_tokens']),
            prompt_tokens=sum(metrics['prompt_tokens']),
            total_tokens=sum(metrics['total_tokens']),
        )
        xpander_backend.agent.report_execution_metrics(llm_tokens=Tokens(worker=llm_tokens), ai_model=agent_response.model, source_node_type="agno")
    except Exception as e:
        return AgentExecutionResult(result=str(e), is_success=False)
    
    return AgentExecutionResult(result=agent_response.content, is_success=True)

# === Register Callback ===
# Attach your custom handler to the listener
listener = XpanderEventListener(**xpander_cfg)
listener.register(on_execution_request=on_execution_request)
To interact with the agent, run the script:
python xpander_handler.py
And we’ll see an output like this: img_5 After running the script, you’ll see two links, each redirecting you to a different channel where you can interact with your agent: The web-based Chat UI and the Agent Builder

Interact with AI Agent

Let’s test our AI agent using the Chat UI to verify it can perform the intended task. As mentioned at the beginning of this tutorial, the agent should be able to:
  1. Analyze the cost of your AWS account
  2. Generate a report based on the Notion template we provided
  3. Send the report to your email address
To test the agent, try using the following prompt:
Analyse my AWS usage cost in April 2025.

Then, create a report based on the analysis using a report template  called "AWS Usage Cost Summary" saved on my Notion page.

Finally, send the report to my email address [youremail@address.com]
img_6 If everything works as expected, you’ll receive an email from the AI agent containing a detailed breakdown of your AWS service costs, along with key insights. You’ll also notice that the structure of the report strictly follows the Notion template provided to the agent. img_7 Another benefit of integrating xpander’s backend into your agent is the ability to monitor various metrics, such as token usage (for both prompt and completion), number of requests, and execution logs To access these metrics, click on the “Monitor” tab at the top of your xpander dashboard. img_8

Conclusion

By following this tutorial, you’ve successfully built an AI agent that can:
  • Analyze AWS usage costs
  • Generate personalized reports using a Notion template
  • Send those reports via email
As you’ve seen, combining the AWS MCP server with the capabilities of the xpander backend allows you to create a powerful and flexible AI agent. Beyond the AWS Cost Explorer, AWS also offers several other MCP servers you can integrate to further enhance your AI agent. You can explore all available AWS MCP servers on this page. If you’d like to dive deeper into what xpander offers as a backend-as-a-service for AI agents, check out the xpander documentation.