<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jamal</title>
    <description>The latest articles on DEV Community by Jamal (@d3vjamal).</description>
    <link>https://dev.to/d3vjamal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178582%2F47a8a424-59e1-477c-acf7-d0c541e27a3a.png</url>
      <title>DEV Community: Jamal</title>
      <link>https://dev.to/d3vjamal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/d3vjamal"/>
    <language>en</language>
    <item>
      <title>I Built an npm Package That Scaffolds AWS AppSync, Lambda &amp; GraphQL Services — Files, Infra, and All</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Wed, 02 Sep 2026 15:00:18 +0000</pubDate>
      <link>https://dev.to/d3vjamal/i-built-an-npm-package-that-scaffolds-aws-appsync-lambda-graphql-services-files-infra-and-all-4ijn</link>
      <guid>https://dev.to/d3vjamal/i-built-an-npm-package-that-scaffolds-aws-appsync-lambda-graphql-services-files-infra-and-all-4ijn</guid>
      <description>&lt;h3&gt;
  
  
  create-lambda-graphql-app: A CLI That Scaffolds Fully Wired AWS AppSync + Lambda Services
&lt;/h3&gt;

&lt;p&gt;Every engineering team has that one repository everyone secretly clones just to copy-paste a folder.&lt;/p&gt;

&lt;p&gt;For us, it was a microservice built around AWS AppSync and Lambda. Whenever someone needed to write a new API handler, the ritual was always the same: find the last service a teammate built, copy the folder, purge whatever logic wasn't needed, rename half the files, fix the broken relative imports, manually update &lt;code&gt;template.yaml&lt;/code&gt;, forget to update the GraphQL schema, and eventually deploy something that &lt;em&gt;mostly&lt;/em&gt; worked.&lt;/p&gt;

&lt;p&gt;It was slow, error-prone, and propagated technical debt across projects. Every copy carried forward the hidden flaws of the template before it.&lt;/p&gt;

&lt;p&gt;To solve this, I packaged our entire boilerplate into an open-source CLI tool: &lt;a href="https://www.npmjs.com/package/create-lambda-graphql-app" rel="noopener noreferrer"&gt;&lt;code&gt;create-lambda-graphql-app&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-lambda-graphql-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all it takes. Answer a few interactive prompts and you get a production-ready, fully wired project structure instantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Root Problem with Manual Scaffolding
&lt;/h2&gt;

&lt;p&gt;Copy-pasting directories fails in subtle, compounding ways over time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Directory drift.&lt;/strong&gt; Service A keeps input validation in &lt;code&gt;validators/&lt;/code&gt;, Service B moves it to &lt;code&gt;validation/&lt;/code&gt;, and Service C inlines it inside the handler. Six months later, jumping between repositories requires a re-learning curve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invisible glue code.&lt;/strong&gt; An AppSync service requires multiple pieces to stay tightly synced: the GraphQL schema, VTL mapping templates, AppSync data sources, resolvers, IAM execution roles, and Lambda code. Missing a single link leads to successful deployments that silently fail at runtime with &lt;code&gt;400 Bad Request&lt;/code&gt; errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tribal knowledge onboarding.&lt;/strong&gt; Relying on "just ask whoever built the last one" is not a scalable documentation strategy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boilerplate fatigue.&lt;/strong&gt; Setting up &lt;code&gt;.gitignore&lt;/code&gt;, ESLint, Prettier, debug configurations, and local invocation runners gets reinvented slightly differently every single time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLI makes the ideal architecture the path of least resistance: running a single command is simply faster than manually copying and editing folders.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Included Out of the Box
&lt;/h2&gt;

&lt;p&gt;The package unifies the whole stack — interactive CLI, directory structure, GraphQL typing, infrastructure as code, and local developer tooling.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The CLI tool
&lt;/h3&gt;

&lt;p&gt;A lightweight, zero-bloat Node.js CLI written in modern ES Modules (Node 18+):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Dependency&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parsing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;commander&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Command-line option management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompts&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inquirer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interactive user input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;&lt;code&gt;chalk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Colorized terminal output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File system&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fs-extra&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Directory creation and templating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formatting&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dedent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clean code generation formatting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It provides two core workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;npx create-lambda-graphql-app&lt;/code&gt;&lt;/strong&gt; — scaffolds a new service from scratch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;npx create-lambda-graphql-app add &amp;lt;handler-name&amp;gt;&lt;/code&gt;&lt;/strong&gt; — safely injects a new handler into an existing project.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Standard project structure
&lt;/h3&gt;

&lt;p&gt;Here is the folder structure generated out of the box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-service/
├── handlers/
│   └── create-order/
│       ├── index.mjs          # Orchestration pipeline
│       ├── validators/        # Request payload validation (Joi)
│       ├── transformers/      # Input data transformation
│       ├── helpers/           # Core business logic
│       ├── dal/               # Data Access Layer (DynamoDB, S3, etc.)
│       ├── exceptions/        # Custom error definitions
│       └── constants/
├── layers/
│   └── common-dependency/     # Shared node_modules layer
├── local-test/
│   └── create-order/          # Local invocation events &amp;amp; harness
├── mapping/
│   ├── request.vtl            # AppSync request template + guards
│   └── response.vtl           # AppSync response template + security headers
├── schema/
│   └── schema.graphql         # GraphQL SDL definition
├── scripts/
│   └── deploy-assets.mjs      # S3 sync script for schema &amp;amp; VTL
├── .vscode/
│   └── launch.json            # Auto-generated debug configs per handler
├── template.yaml               # AWS SAM infrastructure definition
├── samconfig.toml              # Default SAM deployment configuration
├── eslint.config.mjs
├── .prettierrc.json
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Standardized Handler Architecture
&lt;/h2&gt;

&lt;p&gt;Every generated handler is structured as a clean, predictable pipeline. The entry file (&lt;code&gt;index.mjs&lt;/code&gt;) contains zero business logic — it delegates processing across distinct layers and normalizes errors into standard HTTP status codes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Request Event → Validator → Transformer → Helper Logic → Data Access (DAL)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each layer raises explicit domain exceptions (&lt;code&gt;ValidationError&lt;/code&gt;, &lt;code&gt;TransformError&lt;/code&gt;, &lt;code&gt;BusinessLayerError&lt;/code&gt;, &lt;code&gt;DataLayerError&lt;/code&gt;, &lt;code&gt;NotFoundError&lt;/code&gt;). The handler catches these and maps them into a uniform envelope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"responseDetail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SUCCESS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Operation completed successfully"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This guarantees that every API across your architecture reports errors in the exact same format, simplifying error parsing for frontends and monitoring tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pre-Wired AWS SAM Infrastructure
&lt;/h2&gt;

&lt;p&gt;The auto-generated &lt;code&gt;template.yaml&lt;/code&gt; isn't a dummy file — it provides a complete AWS SAM stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtime defaults.&lt;/strong&gt; Node.js 20 on &lt;code&gt;arm64&lt;/code&gt;, active AWS X-Ray tracing, shared Lambda dependency layers, and environment-aware timeouts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment mapping (&lt;code&gt;Mappings.StagesMap&lt;/code&gt;).&lt;/strong&gt; Clean separation of deployment variables across &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;qa&lt;/code&gt;, &lt;code&gt;ppe&lt;/code&gt;, and &lt;code&gt;prod&lt;/code&gt; stages (VPC subnets, log retention, bucket names, and authentication provider ARNs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AppSync integration.&lt;/strong&gt; Provisioned GraphQL API with Lambda &amp;amp; API Key authorization, CloudWatch logs enabled, and automated S3 schema loading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Granular IAM roles.&lt;/strong&gt; Pre-configured permissions scoped for DynamoDB, S3, SSM, Secrets Manager, EventBridge, X-Ray, and VPC access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated resolver wiring.&lt;/strong&gt; Naming a handler &lt;code&gt;get-orders&lt;/code&gt; configures it as a GraphQL Query; naming it anything else (e.g., &lt;code&gt;create-order&lt;/code&gt;) automatically registers it as a Mutation, complete with generated &lt;code&gt;Input&lt;/code&gt; and &lt;code&gt;Response&lt;/code&gt; types in your schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  S3 schema &amp;amp; VTL deployment workflow
&lt;/h3&gt;

&lt;p&gt;To bypass template size limits and simplify deployment, GraphQL schemas and VTL files live inside the repository but are read directly from S3 during deployment.&lt;/p&gt;

&lt;p&gt;The included build tool simplifies asset synchronization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run deploy:assets &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--env&lt;/span&gt; dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command automatically publishes &lt;code&gt;schema.graphql&lt;/code&gt;, &lt;code&gt;request.vtl&lt;/code&gt;, and &lt;code&gt;response.vtl&lt;/code&gt; directly to &lt;code&gt;s3://&amp;lt;org&amp;gt;-app-schema-bucket/&amp;lt;env&amp;gt;/&amp;lt;service&amp;gt;/&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Daily Developer Workflow
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrapping a new service:&lt;/strong&gt; run &lt;code&gt;npx create-lambda-graphql-app&lt;/code&gt; → &lt;code&gt;npm install&lt;/code&gt; → &lt;code&gt;sam build&lt;/code&gt; → deploy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adding a handler safely:&lt;/strong&gt; run &lt;code&gt;npx create-lambda-graphql-app add cancel-order&lt;/code&gt;. It creates the folder hierarchy, appends SAM infrastructure blocks, and updates &lt;code&gt;schema.graphql&lt;/code&gt; without disturbing your current codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless onboarding:&lt;/strong&gt; every generated service includes an explicit &lt;code&gt;README.md&lt;/code&gt; walking developers through local invocation, parameter customization, and deployment commands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Out-of-the-box debugging:&lt;/strong&gt; pre-configured VS Code &lt;code&gt;launch.json&lt;/code&gt; files and mock event payloads let you debug handlers with breakpoints locally in seconds.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;You don't need to install anything globally. Run it directly with &lt;code&gt;npx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Generate the service&lt;/span&gt;
npx create-lambda-graphql-app

&lt;span class="c"&gt;# Prompt responses:&lt;/span&gt;
&lt;span class="c"&gt;#   ? Project name: my-service&lt;/span&gt;
&lt;span class="c"&gt;#   ? Organization name: my-org&lt;/span&gt;
&lt;span class="c"&gt;#   ? Primary handler name: get-orders  (get-* maps to a Query)&lt;/span&gt;
&lt;span class="c"&gt;#   ? Add another handler: create-order (maps to a Mutation)&lt;/span&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;my-service
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--prefix&lt;/span&gt; layers/common-dependency

&lt;span class="c"&gt;# 2. Build local SAM artifacts&lt;/span&gt;
npm run build

&lt;span class="c"&gt;# 3. Deploy GraphQL schema and VTL templates to S3&lt;/span&gt;
npm run deploy:assets &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--env&lt;/span&gt; dev

&lt;span class="c"&gt;# 4. First-time guided SAM deployment&lt;/span&gt;
sam deploy &lt;span class="nt"&gt;--guided&lt;/span&gt;

&lt;span class="c"&gt;# 5. Start local API Gateway / AppSync emulator&lt;/span&gt;
npm run &lt;span class="nb"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding another handler down the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-lambda-graphql-app add cancel-order
npm run build
npm run deploy:assets &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--env&lt;/span&gt; dev
sam deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Roadmap &amp;amp; Next Steps
&lt;/h2&gt;

&lt;p&gt;While the template covers most production needs out of the box, future releases will introduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A non-interactive &lt;code&gt;--yes&lt;/code&gt; flag / configuration file for CI/CD automation pipelines.&lt;/li&gt;
&lt;li&gt;Automated unit test scaffolding (&lt;code&gt;jest&lt;/code&gt; / &lt;code&gt;vitest&lt;/code&gt;) per handler.&lt;/li&gt;
&lt;li&gt;Pluggable database layer presets (DynamoDB Single-Table vs. Amazon RDS / Prisma).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your team is still manually copying service directories to launch AppSync and Lambda APIs, give it a try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-lambda-graphql-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GitHub repository &amp;amp; issues:&lt;/strong&gt; &lt;a href="https://github.com/d3vjamal/lambda-node-graphql-starter" rel="noopener noreferrer"&gt;d3vjamal/lambda-node-graphql-starter&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Appendix: Generated Project &lt;code&gt;README.md&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Below is the standard &lt;code&gt;README.md&lt;/code&gt; included inside generated repositories.&lt;/p&gt;

&lt;h2&gt;
  
  
  create-lambda-graphql-app
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Scaffold a fully wired AWS AppSync + Lambda + SAM microservice in seconds with a single command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/create-lambda-graphql-app" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fnpm%2Fv%2Fcreate-lambda-graphql-app.svg%3Fstyle%3Dflat-square" alt="npm version" width="80" height="20"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/d3vjamal/lambda-node-graphql-starter" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fgithub%2Flicense%2Fd3vjamal%2Flambda-node-graphql-starter.svg%3Fstyle%3Dflat-square" alt="license" width="128" height="20"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fnode%2Fv%2Fcreate-lambda-graphql-app.svg%3Fstyle%3Dflat-square" alt="node version" width="78" height="20"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;create-lambda-graphql-app&lt;/code&gt; turns complex AWS AppSync + Lambda + SAM setup into a zero-friction CLI workflow. Stop copy-pasting old folders, broken relative imports, and out-of-sync &lt;code&gt;template.yaml&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why use &lt;code&gt;create-lambda-graphql-app&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero configuration setup:&lt;/strong&gt; get a production-ready, multi-stage AWS SAM project out of the box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Opinionated handler architecture:&lt;/strong&gt; enforces a clean pipeline separation (Validator → Transformer → Helper → DAL) across all Lambda functions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fully wired GraphQL + AppSync:&lt;/strong&gt; schema definitions, VTL request/response mapping templates, AppSync data sources, and resolvers auto-generated in sync.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local debugging out of the box:&lt;/strong&gt; includes VS Code &lt;code&gt;launch.json&lt;/code&gt; configurations and event payload harnesses for instant local debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental scaffolding:&lt;/strong&gt; easily add new handlers to an existing project at any time without breaking existing code or manual infrastructure configurations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Quick start
&lt;/h3&gt;

&lt;p&gt;No global installation required. Execute directly using &lt;code&gt;npx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Generate a new service&lt;/span&gt;
npx create-lambda-graphql-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interactive prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;? Project name: my-service
? Organization name: my-org
? Initial handler name: get-orders
? Add another handler? Yes
? Handler name: create-order
? Add another handler? No
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Project setup &amp;amp; local build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-service

&lt;span class="c"&gt;# Install dependencies for project &amp;amp; common layer&lt;/span&gt;
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--prefix&lt;/span&gt; layers/common-dependency

&lt;span class="c"&gt;# Build local SAM artifacts&lt;/span&gt;
npm run build

&lt;span class="c"&gt;# Deploy assets (GraphQL schema &amp;amp; VTL templates) to S3&lt;/span&gt;
npm run deploy:assets &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--env&lt;/span&gt; dev

&lt;span class="c"&gt;# Deploy to AWS via SAM CLI (first time setup)&lt;/span&gt;
sam deploy &lt;span class="nt"&gt;--guided&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Directory structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-service/
├── handlers/
│   ├── get-orders/            # Auto-generated Query handler
│   │   ├── index.mjs          # Entrypoint &amp;amp; exception mapping pipeline
│   │   ├── validators/        # Request validation logic (Joi)
│   │   ├── transformers/      # Input/output mapping logic
│   │   ├── helpers/           # Business logic
│   │   ├── dal/               # Data Access Layer (DynamoDB, S3, RDS)
│   │   ├── exceptions/        # Custom domain exceptions
│   │   └── constants/
│   └── create-order/          # Auto-generated Mutation handler
├── layers/
│   └── common-dependency/     # Shared dependencies Lambda Layer
├── local-test/
│   └── get-orders/            # Local test event &amp;amp; execution harness
├── mapping/
│   ├── request.vtl            # AppSync request mapping template
│   └── response.vtl           # AppSync response template + security headers
├── schema/
│   └── schema.graphql         # Auto-generated GraphQL SDL
├── scripts/
│   └── deploy-assets.mjs      # Syncs schema &amp;amp; VTL templates to S3
├── .vscode/
│   └── launch.json            # Auto-generated VS Code debug configs
├── template.yaml               # Complete AWS SAM infrastructure template
├── samconfig.toml              # Default SAM deployment configuration
├── eslint.config.mjs           # Flat ESLint config
├── .prettierrc.json            # Prettier code formatting rules
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CLI usage
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Scaffold a new project&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-lambda-graphql-app &lt;span class="o"&gt;[&lt;/span&gt;project-name]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Add a handler to an existing project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run this command inside any project generated by &lt;code&gt;create-lambda-graphql-app&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-lambda-graphql-app add &amp;lt;handler-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens when you add a handler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a new directory structure under &lt;code&gt;handlers/&amp;lt;handler-name&amp;gt;/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Creates a local test payload runner under &lt;code&gt;local-test/&amp;lt;handler-name&amp;gt;/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Injects the &lt;code&gt;Function&lt;/code&gt;, &lt;code&gt;LogGroup&lt;/code&gt;, &lt;code&gt;DataSource&lt;/code&gt;, and &lt;code&gt;Resolver&lt;/code&gt; into &lt;code&gt;template.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Updates &lt;code&gt;schema/schema.graphql&lt;/code&gt; with matching Query/Mutation types and Input/Response shapes.&lt;/li&gt;
&lt;li&gt;Adds a debugging target to &lt;code&gt;.vscode/launch.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Handler conventions &amp;amp; architecture
&lt;/h3&gt;

&lt;p&gt;Handlers follow a strict pipeline architecture:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GraphQL Event → Validator → Transformer → Helper → DAL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naming conventions &amp;amp; schema inferences&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The CLI automatically infers GraphQL operation types based on handler naming:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Handler prefix / name&lt;/th&gt;
&lt;th&gt;Inferred operation type&lt;/th&gt;
&lt;th&gt;Generated GraphQL SDL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;get-*&lt;/code&gt;, &lt;code&gt;list-*&lt;/code&gt;, &lt;code&gt;fetch-*&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Query&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getOrders(input: GetOrdersInput!): GetOrdersResponse!&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any other name (e.g. &lt;code&gt;create-*&lt;/code&gt;, &lt;code&gt;cancel-*&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Mutation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;createOrder(input: CreateOrderInput!): CreateOrderResponse!&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Standard response envelope&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All handlers format their response into a standardized JSON payload structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ord_12345"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PROCESSING"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"responseDetail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SUCCESS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Order created successfully"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Available scripts
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Script&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sam build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compiles SAM template and builds Lambda dependencies.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deploy:assets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;node scripts/deploy-assets.mjs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Uploads &lt;code&gt;schema.graphql&lt;/code&gt; and VTL templates to S3.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;local&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sam local start-api&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Emulates API locally for testing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;eslint .&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs static code analysis.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;format&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;prettier --write .&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-formats code across the codebase.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js:&lt;/strong&gt; 18.x or higher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS SAM CLI:&lt;/strong&gt; installed and configured (&lt;code&gt;aws configure&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker:&lt;/strong&gt; required if building dependencies natively with &lt;code&gt;sam build --use-container&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Contributing
&lt;/h3&gt;

&lt;p&gt;Contributions are welcome! Please feel free to open issues or submit pull requests.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork the repository&lt;/li&gt;
&lt;li&gt;Create your feature branch (&lt;code&gt;git checkout -b feature/amazing-feature&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Commit your changes (&lt;code&gt;git commit -m 'Add amazing feature'&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Push to branch (&lt;code&gt;git push origin feature/amazing-feature&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Open a pull request&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  License
&lt;/h3&gt;

&lt;p&gt;Distributed under the MIT License. See &lt;code&gt;LICENSE&lt;/code&gt; for details.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>npm</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title># Building a Personal Notes Assistant with RAG, Amazon Bedrock, and Pinecone</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Wed, 26 Aug 2026 05:34:19 +0000</pubDate>
      <link>https://dev.to/d3vjamal/-building-a-personal-notes-assistant-with-rag-amazon-bedrock-and-pinecone-4jg3</link>
      <guid>https://dev.to/d3vjamal/-building-a-personal-notes-assistant-with-rag-amazon-bedrock-and-pinecone-4jg3</guid>
      <description>&lt;p&gt;Have you ever saved hundreds of digital notes only to spend twenty minutes hunting for one tiny detail? &lt;/p&gt;

&lt;p&gt;That exact frustration led me to build a custom notes assistant. I wanted a private API where I could upload my personal files, ask a question in plain English, and get an answer drawn directly from my notes—not just a generic guess from a public AI model.&lt;/p&gt;

&lt;p&gt;In this guide, I’ll break down how I built this project using Python, Flask, Amazon Bedrock, Pinecone, S3, AWS Lambda, and API Gateway. I’ll keep the explanations clear and conversational while walking through the real code and key takeaways.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Project Goal:&lt;/strong&gt; Upload plain text (&lt;code&gt;.txt&lt;/code&gt;) notes and receive accurate answers strictly grounded in their content.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What is RAG?
&lt;/h2&gt;

&lt;p&gt;RAG stands for &lt;strong&gt;Retrieval-Augmented Generation&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Normally, when you ask an AI model a question, it relies entirely on its training data. If your information is private, recent, or highly specific, the model won't know it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standard AI Flow:&lt;/strong&gt; &lt;code&gt;Question -&amp;gt; Model -&amp;gt; Answer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG AI Flow:&lt;/strong&gt; &lt;code&gt;Question -&amp;gt; Search My Notes -&amp;gt; Grab Relevant Snippets -&amp;gt; Model -&amp;gt; Answer&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By adding a retrieval step, we feed the model relevant passages from our own documents alongside our question. We aren't retraining the AI model; we're giving it an open-book test using documents we control.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real-Life Analogy
&lt;/h2&gt;

&lt;p&gt;Imagine walking into a library and asking a librarian: &lt;em&gt;"What do my project notes say about serverless memory limits?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The librarian doesn't read every book on the shelves from cover to cover. Instead, they:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify the core topic of your question.&lt;/li&gt;
&lt;li&gt;Check the library catalog for matching locations.&lt;/li&gt;
&lt;li&gt;Grab the top three relevant pages.&lt;/li&gt;
&lt;li&gt;Read those specific pages and summarize the answer for you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is how that physical library maps directly to our technical setup:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Physical Library&lt;/th&gt;
&lt;th&gt;RAG System Component&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Books on shelves&lt;/td&gt;
&lt;td&gt;Original text files stored in Amazon S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Individual pages&lt;/td&gt;
&lt;td&gt;Document chunks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catalog cards&lt;/td&gt;
&lt;td&gt;Embeddings (numerical representations of meaning)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Searching the catalog&lt;/td&gt;
&lt;td&gt;Pinecone similarity search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Top three selected pages&lt;/td&gt;
&lt;td&gt;Top three matching text chunks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Librarian giving the answer&lt;/td&gt;
&lt;td&gt;Amazon Nova Lite generating the response&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Understanding Embeddings
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;embedding&lt;/strong&gt; is just a snippet of text converted into a list of numbers (a vector) that represents its core meaning. Words or phrases with similar meanings end up near each other in digital space. &lt;/p&gt;

&lt;p&gt;For instance, a traditional keyword search might miss the connection between these two sentences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Where did I save the uploaded document?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Which service stores my note files?"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because they share few identical words, keyword search struggles. But a &lt;strong&gt;semantic search&lt;/strong&gt; using embeddings recognizes that both sentences ask about file storage.&lt;/p&gt;




&lt;h2&gt;
  
  
  System Architecture
&lt;/h2&gt;

&lt;p&gt;The application handles two main workflows: &lt;strong&gt;Ingestion&lt;/strong&gt; (saving and indexing notes) and &lt;strong&gt;Querying&lt;/strong&gt; (searching notes and answering questions).&lt;/p&gt;

&lt;h3&gt;
  
  
  How Notes Get Ingested
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Upload:&lt;/strong&gt; You send a &lt;code&gt;.txt&lt;/code&gt; file to the Flask backend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation:&lt;/strong&gt; Flask checks the file format, size, and character encoding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage:&lt;/strong&gt; The full original file goes to a private Amazon S3 bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking:&lt;/strong&gt; The document text is cut into smaller, overlapping snippets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding:&lt;/strong&gt; Amazon Titan converts each text snippet into a 512-dimensional vector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indexing:&lt;/strong&gt; Pinecone stores the vectors along with original text snippet metadata.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  How Questions Get Answered
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ask:&lt;/strong&gt; You send a question to the &lt;code&gt;/ask&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embed Question:&lt;/strong&gt; Amazon Titan converts your question into a vector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search:&lt;/strong&gt; Pinecone retrieves the top 3 closest matching note snippets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Assembly:&lt;/strong&gt; The question and the 3 snippets are combined into an instruction prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate Answer:&lt;/strong&gt; Amazon Nova Lite reads the prompt and writes a factual response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response:&lt;/strong&gt; Flask returns the final answer as JSON.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Code Walkthrough
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Step 1: Validating Incoming Uploads
&lt;/h3&gt;

&lt;p&gt;Security starts at the entry point. The &lt;code&gt;/ingest&lt;/code&gt; endpoint accepts multipart form data and runs several checks before touching the rest of our system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Check for file presence and secure filename
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;error_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MISSING_FILE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No file was provided&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;uploaded_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;secure_filename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uploaded_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;error_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INVALID_FILE_TYPE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Only UTF-8 .txt files are accepted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;415&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Validate encoding and content readability
&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;uploaded_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;error_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EMPTY_FILE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Uploaded text file is empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;decoded_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;UnicodeDecodeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;error_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INVALID_TEXT_ENCODING&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Text file must use UTF-8 encoding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;decoded_content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;decoded_content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;error_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INVALID_TEXT_CONTENT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;File must contain valid text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Catching bad requests early with specific errors like &lt;code&gt;INVALID_FILE_TYPE&lt;/code&gt; prevents corrupted files from crashing downstream services like Pinecone or S3.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Step 2: Saving Raw Files to S3
&lt;/h3&gt;

&lt;p&gt;Once validated, the file goes to S3. To avoid accidental overwrites when uploading multiple files with generic names like &lt;code&gt;notes.txt&lt;/code&gt;, the application generates a unique ID (UUID) for each storage key while keeping the real filename in S3 metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;upload_text_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original_filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3_DOCUMENT_BUCKET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Create a unique path key
&lt;/span&gt;    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uploads/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nb"&gt;hex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;upload_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ExtraArgs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ContentType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/plain; charset=utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Metadata&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;original-filename&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original_filename&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Step 3: Chunking Text for Precision
&lt;/h3&gt;

&lt;p&gt;Sending entire long documents directly into vector search reduces precision. We split text into chunks using LangChain's &lt;code&gt;RecursiveCharacterTextSplitter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;text_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text_splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why include overlap?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If a key idea gets split right at character 1,000, half of the context ends up in Chunk A and half in Chunk B. Overlapping neighboring chunks by 100 characters preserves complete sentences and context across boundaries.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Step 4: Vector Embedding &amp;amp; Indexing
&lt;/h3&gt;

&lt;p&gt;Next, we convert text chunks into numbers using Amazon Titan Text Embeddings V2 and save them into Pinecone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon.titan-embed-text-v2:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dimensions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ap-south-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;PineconeVectorStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Golden Rule:&lt;/em&gt; Your document chunks and your incoming search questions &lt;strong&gt;must&lt;/strong&gt; use the exact same embedding model, dimension count, and normalization settings. Otherwise, vector distances become meaningless.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Step 5 &amp;amp; 6: Retrieval &amp;amp; Answer Generation
&lt;/h3&gt;

&lt;p&gt;When asking a question via &lt;code&gt;/ask&lt;/code&gt;, Pinecone finds the three nearest chunks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Grab top 3 matching snippets
&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;docsearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_retriever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search_kwargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;context_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We pass those snippets into Amazon Nova Lite with strict prompt instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Answer the question using only the context below.

Context:
{context}

Question: {question}
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatBedrockConverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon.nova-lite-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Low temperature keeps answers factual
&lt;/span&gt;    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PROMPT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;StrOutputParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context_str&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Serverless Deployment Highlights
&lt;/h2&gt;

&lt;p&gt;For local development, Flask handles traditional HTTP calls. When deploying to AWS, we run Flask inside AWS Lambda behind an API Gateway using &lt;code&gt;serverless-wsgi&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serverless_wsgi&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;serverless_wsgi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The underlying infrastructure is configured in AWS CloudFormation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway:&lt;/strong&gt; Routes endpoint traffic (&lt;code&gt;/health&lt;/code&gt;, &lt;code&gt;/ingest&lt;/code&gt;, &lt;code&gt;/ask&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda:&lt;/strong&gt; Hosts the application logic on Python 3.12.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM Roles:&lt;/strong&gt; Grants minimal execution permissions for Bedrock, S3, and CloudWatch.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Takeaways &amp;amp; Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;RAG Is a Search System First:&lt;/strong&gt; If retrieval yields poor or irrelevant snippets, even the best LLM will fail to give a good answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency Is Critical:&lt;/strong&gt; Embedding settings during ingestion must match query settings perfectly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard Software Engineering Matters:&lt;/strong&gt; Machine learning features still rely on traditional tasks like request validation, error handling, file cleanup, and IAM security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Grounding Controls Hallucinations:&lt;/strong&gt; Explicit system prompts prevent the AI model from making up facts outside your uploaded notes.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;My GitHub repo : &lt;a href="https://github.com/d3vjamal/my-notes-rag" rel="noopener noreferrer"&gt;my-rag-notes-app&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>rag</category>
      <category>python</category>
    </item>
    <item>
      <title>LangChain vs Strands SDK with Amazon Bedrock</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Wed, 05 Aug 2026 12:51:47 +0000</pubDate>
      <link>https://dev.to/d3vjamal/langchain-vs-strands-sdk-with-amazon-bedrock-3n3i</link>
      <guid>https://dev.to/d3vjamal/langchain-vs-strands-sdk-with-amazon-bedrock-3n3i</guid>
      <description>&lt;p&gt;LangChain, LangGraph, and Strands: Concept Map&lt;/p&gt;

&lt;p&gt;This guide compares LangChain, LangGraph, and the Strands Agents SDK using the&lt;br&gt;
weather-agent examples in this repository. It is intended both for learning and&lt;br&gt;
for explaining the technologies to others.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. The short explanation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strands Agents SDK&lt;/strong&gt; provides a concise, model-driven way to build agents,
especially when working with Amazon Bedrock and AWS services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LangChain&lt;/strong&gt; provides standard abstractions for models, messages, prompts,
tools, retrieval, structured output, and agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LangGraph&lt;/strong&gt; provides explicit control over long-running, stateful agent
workflows using nodes, edges, state, and checkpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Bedrock&lt;/strong&gt; is the managed AWS service that hosts the foundation model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AgentCore&lt;/strong&gt; is an AWS platform for operating agents securely in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LangChain and Strands help construct an agent. LangGraph becomes especially&lt;br&gt;
useful when the workflow needs controlled routing, persistence, human approval,&lt;br&gt;
or multiple collaborating agents.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Technology-layer mapping
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Strands / AWS choice&lt;/th&gt;
&lt;th&gt;LangChain / LangGraph choice&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Foundation model&lt;/td&gt;
&lt;td&gt;Amazon Nova, Claude, or another Bedrock model&lt;/td&gt;
&lt;td&gt;The same model&lt;/td&gt;
&lt;td&gt;Generates responses and decides when to call tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model service&lt;/td&gt;
&lt;td&gt;Amazon Bedrock&lt;/td&gt;
&lt;td&gt;Amazon Bedrock&lt;/td&gt;
&lt;td&gt;Hosts and invokes the model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model adapter&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BedrockModel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChatBedrockConverse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Connects application code to Bedrock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent API&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Agent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;create_agent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs the model–tool reasoning loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool definition&lt;/td&gt;
&lt;td&gt;Strands &lt;code&gt;@tool&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;LangChain &lt;code&gt;@tool&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Exposes a Python function to the model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conversation input&lt;/td&gt;
&lt;td&gt;String or message objects&lt;/td&gt;
&lt;td&gt;Message dictionaries or message objects&lt;/td&gt;
&lt;td&gt;Carries user and assistant messages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent instructions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;system_prompt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;system_prompt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines the agent's role and behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow orchestration&lt;/td&gt;
&lt;td&gt;Agents, hooks, and custom application logic&lt;/td&gt;
&lt;td&gt;LangGraph nodes and edges&lt;/td&gt;
&lt;td&gt;Controls multi-step execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow state&lt;/td&gt;
&lt;td&gt;Agent/application state&lt;/td&gt;
&lt;td&gt;Typed LangGraph state&lt;/td&gt;
&lt;td&gt;Shares data between workflow steps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistence&lt;/td&gt;
&lt;td&gt;Application or runtime integration&lt;/td&gt;
&lt;td&gt;LangGraph checkpointer/store&lt;/td&gt;
&lt;td&gt;Saves conversation and workflow progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production runtime&lt;/td&gt;
&lt;td&gt;AgentCore Runtime&lt;/td&gt;
&lt;td&gt;AgentCore, containers, or another runtime&lt;/td&gt;
&lt;td&gt;Hosts and operates the agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;AWS tooling and Strands integrations&lt;/td&gt;
&lt;td&gt;LangSmith, callbacks, and AWS tooling&lt;/td&gt;
&lt;td&gt;Traces and evaluates executions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  3. Weather-agent mapping
&lt;/h2&gt;

&lt;p&gt;The files &lt;a href="//./strand-agent.py"&gt;&lt;code&gt;strand-agent.py&lt;/code&gt;&lt;/a&gt; and&lt;br&gt;
&lt;a href="//./langchain-agent.py"&gt;&lt;code&gt;langchain-agent.py&lt;/code&gt;&lt;/a&gt; implement the same use case.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Strands example&lt;/th&gt;
&lt;th&gt;LangChain example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Import the agent&lt;/td&gt;
&lt;td&gt;&lt;code&gt;from strands import Agent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;from langchain.agents import create_agent&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Import the tool decorator&lt;/td&gt;
&lt;td&gt;&lt;code&gt;from strands import tool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;from langchain.tools import tool&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configure Bedrock&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BedrockModel(...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChatBedrockConverse(...)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Declare a tool&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@tool&lt;/code&gt; above &lt;code&gt;get_weather&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@tool&lt;/code&gt; above &lt;code&gt;get_weather&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Register the tool&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools=[get_weather]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools=[get_weather]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Create the agent&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Agent(...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;create_agent(...)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invoke the agent&lt;/td&gt;
&lt;td&gt;&lt;code&gt;agent(question)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;agent.invoke({"messages": [...]})&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read the answer&lt;/td&gt;
&lt;td&gt;Returned result&lt;/td&gt;
&lt;td&gt;Last message in &lt;code&gt;result["messages"]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;@tool&lt;/code&gt; decorators look similar, but they belong to different SDKs. In both&lt;br&gt;
cases, the function name, type hints, and docstring help the model understand&lt;br&gt;
when and how to call the tool.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. How the weather agent works
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlencode&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlopen&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;certifi&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_aws&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatBedrockConverse&lt;/span&gt;


&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;SSL_CONTEXT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cafile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;certifi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Make a small JSON GET request using only the Python standard library.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;request_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SSL_CONTEXT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# noqa: S310
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get the current weather for a city. Use this for weather questions.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;places&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://geocoding-api.open-meteo.com/v1/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;places&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I could not find a location matching &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="n"&gt;place&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;places&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.open-meteo.com/v1/forecast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature_2m,apparent_temperature,weather_code,wind_speed_10m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timezone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Current weather in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temperature_2m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;°C, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feels like &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;apparent_temperature&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;°C, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wind speed &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wind_speed_10m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; km/h, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WMO weather code &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;weather_code&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Weather lookup failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatBedrockConverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BEDROCK_MODEL_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global.amazon.nova-2-lite-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a helpful weather assistant. Use the weather tool when needed.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is the weather in Kolkata, India?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;}]})&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;*&lt;em&gt;Strands SDK&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlencode&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlopen&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;certifi&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;


&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;SSL_CONTEXT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cafile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;certifi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Make a small JSON GET request using only the Python standard library.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;request_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SSL_CONTEXT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# noqa: S310
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get the current weather for a city.

    Args:
        city: City name, optionally including its state or country.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;places&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://geocoding-api.open-meteo.com/v1/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;places&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I could not find a location matching &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="n"&gt;place&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;places&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.open-meteo.com/v1/forecast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature_2m,apparent_temperature,weather_code,wind_speed_10m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timezone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Current weather in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temperature_2m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;°C, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feels like &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;apparent_temperature&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;°C, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wind speed &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wind_speed_10m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; km/h, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WMO weather code &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;weather_code&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Weather lookup failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BEDROCK_MODEL_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global.amazon.nova-2-lite-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a helpful weather assistant. Use the weather tool when needed.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;callback_handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is the weather in Kolkata, India?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User question
     |
     v
Agent sends the question and tool definition to the Bedrock model
     |
     v
Model selects get_weather(city="London")
     |
     v
Tool converts the city to latitude and longitude with Open-Meteo geocoding
     |
     v
Tool requests current weather from Open-Meteo
     |
     v
Tool result is returned to the model
     |
     v
Model produces a natural-language answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important distinction: the model does not directly access the weather service.&lt;br&gt;
It chooses a registered tool, and the application executes that Python function.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Core vocabulary
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Model
&lt;/h3&gt;

&lt;p&gt;The foundation model performs language understanding, response generation, and&lt;br&gt;
tool selection. In these examples, the model is accessed through Amazon Bedrock.&lt;/p&gt;
&lt;h3&gt;
  
  
  Prompt
&lt;/h3&gt;

&lt;p&gt;A prompt is the information sent to the model. It can include system&lt;br&gt;
instructions, conversation messages, tool descriptions, and tool results.&lt;/p&gt;
&lt;h3&gt;
  
  
  System prompt
&lt;/h3&gt;

&lt;p&gt;The system prompt defines high-level behavior, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a helpful weather assistant. Use the weather tool when needed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tool
&lt;/h3&gt;

&lt;p&gt;A tool is an application-controlled capability exposed to the model. Examples&lt;br&gt;
include calling an API, reading a database, searching documents, or creating a&lt;br&gt;
support ticket.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tool calling
&lt;/h3&gt;

&lt;p&gt;Tool calling is the process in which the model returns a structured request such&lt;br&gt;
as &lt;code&gt;get_weather(city="London")&lt;/code&gt;. The SDK validates and executes the request and&lt;br&gt;
returns the result to the model.&lt;/p&gt;
&lt;h3&gt;
  
  
  Agent
&lt;/h3&gt;

&lt;p&gt;An agent combines a model, instructions, and tools with an execution loop. The&lt;br&gt;
loop continues until the model returns a final answer or reaches a configured&lt;br&gt;
limit.&lt;/p&gt;
&lt;h3&gt;
  
  
  State
&lt;/h3&gt;

&lt;p&gt;State is data retained during a workflow. It may contain messages, tool results,&lt;br&gt;
user information, approval status, or intermediate calculations.&lt;/p&gt;
&lt;h3&gt;
  
  
  Memory
&lt;/h3&gt;

&lt;p&gt;Memory is information retained across interactions. Short-term memory commonly&lt;br&gt;
means conversation history; long-term memory may store facts across sessions.&lt;br&gt;
Memory is not the same as a model's context window.&lt;/p&gt;
&lt;h3&gt;
  
  
  Checkpoint
&lt;/h3&gt;

&lt;p&gt;A checkpoint is a persisted snapshot of workflow state. LangGraph checkpoints&lt;br&gt;
allow a workflow to pause, resume, recover, and maintain separate conversation&lt;br&gt;
threads.&lt;/p&gt;
&lt;h3&gt;
  
  
  Node and edge
&lt;/h3&gt;

&lt;p&gt;In LangGraph, a &lt;strong&gt;node&lt;/strong&gt; performs a unit of work and an &lt;strong&gt;edge&lt;/strong&gt; determines which&lt;br&gt;
node runs next. A conditional edge routes execution based on current state.&lt;/p&gt;
&lt;h3&gt;
  
  
  Human in the loop
&lt;/h3&gt;

&lt;p&gt;Human-in-the-loop design pauses execution before a sensitive action so a person&lt;br&gt;
can approve, reject, or edit it. LangGraph supports this through interrupts and&lt;br&gt;
persisted state.&lt;/p&gt;
&lt;h3&gt;
  
  
  Structured output
&lt;/h3&gt;

&lt;p&gt;Structured output asks the model to return data matching a schema instead of&lt;br&gt;
free-form prose. It is useful when downstream code needs reliable fields.&lt;/p&gt;
&lt;h3&gt;
  
  
  Retrieval-augmented generation (RAG)
&lt;/h3&gt;

&lt;p&gt;RAG retrieves relevant information from external sources and includes it in the&lt;br&gt;
model's context. Retrieval supplies knowledge; an agent decides and acts. A&lt;br&gt;
system can use both.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Similarities
&lt;/h2&gt;

&lt;p&gt;Both LangChain and Strands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;support Amazon Bedrock models;&lt;/li&gt;
&lt;li&gt;allow Python functions to become model-callable tools;&lt;/li&gt;
&lt;li&gt;run a model–tool–model loop;&lt;/li&gt;
&lt;li&gt;use system prompts to guide behavior;&lt;/li&gt;
&lt;li&gt;support streaming and conversation messages;&lt;/li&gt;
&lt;li&gt;can be extended with custom tools and production integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The central pattern is the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;model + instructions + tools + execution loop = agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Important differences
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;Strands&lt;/th&gt;
&lt;th&gt;LangChain / LangGraph&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary style&lt;/td&gt;
&lt;td&gt;Compact and agent-first&lt;/td&gt;
&lt;td&gt;Broad component ecosystem plus graph orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS alignment&lt;/td&gt;
&lt;td&gt;Designed with strong AWS integration&lt;/td&gt;
&lt;td&gt;Provider-neutral, with AWS integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simple agent setup&lt;/td&gt;
&lt;td&gt;Very concise&lt;/td&gt;
&lt;td&gt;Concise with &lt;code&gt;create_agent&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Explicit workflow control&lt;/td&gt;
&lt;td&gt;Usually application logic or SDK patterns&lt;/td&gt;
&lt;td&gt;A core LangGraph feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State graph&lt;/td&gt;
&lt;td&gt;Not a direct one-to-one abstraction&lt;/td&gt;
&lt;td&gt;Nodes, edges, reducers, and subgraphs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ecosystem&lt;/td&gt;
&lt;td&gt;Focused agent SDK and AWS ecosystem&lt;/td&gt;
&lt;td&gt;Large integration and retrieval ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production hosting&lt;/td&gt;
&lt;td&gt;Natural fit with AgentCore&lt;/td&gt;
&lt;td&gt;Multiple deployment choices, including AgentCore&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These differences do not mean one framework is universally better. The choice&lt;br&gt;
depends on the required integrations, workflow complexity, operating platform,&lt;br&gt;
and the team's preferred abstractions.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. When to introduce LangGraph
&lt;/h2&gt;

&lt;p&gt;A simple weather agent does not require a custom graph. Introduce LangGraph when&lt;br&gt;
the application needs one or more of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deterministic stages around the agent;&lt;/li&gt;
&lt;li&gt;conditional routing;&lt;/li&gt;
&lt;li&gt;durable conversation state;&lt;/li&gt;
&lt;li&gt;pause and resume;&lt;/li&gt;
&lt;li&gt;human approval before side effects;&lt;/li&gt;
&lt;li&gt;retry or recovery behavior;&lt;/li&gt;
&lt;li&gt;parallel branches;&lt;/li&gt;
&lt;li&gt;multiple specialized agents;&lt;/li&gt;
&lt;li&gt;a workflow that must be inspected and tested step by step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example controlled workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;START -&amp;gt; classify request -&amp;gt; retrieve data -&amp;gt; draft answer -&amp;gt; approval -&amp;gt; END
                  |                                  |
                  +-&amp;gt; reject unsupported request     +-&amp;gt; revise
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Bedrock and AgentCore are different layers
&lt;/h2&gt;

&lt;p&gt;It is useful to avoid combining these terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bedrock&lt;/strong&gt; supplies access to foundation models and related AI services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The SDK or framework&lt;/strong&gt; defines agent logic and connects models to tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AgentCore&lt;/strong&gt; supplies production capabilities for deploying and operating
agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A possible production stack is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User interface
      |
AgentCore Runtime
      |
LangChain/LangGraph or Strands application
      |
Amazon Bedrock model + application tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  10. Suggested presentation order
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Start with the problem: answer a live weather question.&lt;/li&gt;
&lt;li&gt;Explain why the model alone cannot know guaranteed current weather.&lt;/li&gt;
&lt;li&gt;Introduce the &lt;code&gt;get_weather&lt;/code&gt; tool.&lt;/li&gt;
&lt;li&gt;Show the agent deciding to call that tool.&lt;/li&gt;
&lt;li&gt;Compare the Strands and LangChain implementations line by line.&lt;/li&gt;
&lt;li&gt;Introduce LangGraph only after showing a need for controlled workflows.&lt;/li&gt;
&lt;li&gt;Finish by separating construction, model hosting, and production runtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  11. Learning path
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run both weather examples and compare their output.&lt;/li&gt;
&lt;li&gt;Add a second tool, such as a weather forecast tool.&lt;/li&gt;
&lt;li&gt;Return structured weather data using a schema.&lt;/li&gt;
&lt;li&gt;Add conversation history for follow-up questions like “How about tomorrow?”&lt;/li&gt;
&lt;li&gt;Build a LangGraph that routes current-weather and forecast requests.&lt;/li&gt;
&lt;li&gt;Add a human approval step before a tool with real-world side effects.&lt;/li&gt;
&lt;li&gt;Add persistence, tracing, evaluation, and deployment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  12. Commands for the examples
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run python strand-agent.py &lt;span class="s2"&gt;"What is the weather in London?"&lt;/span&gt;
uv run python langchain-agent.py &lt;span class="s2"&gt;"What is the weather in London?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both examples use the same Bedrock defaults and accept these environment&lt;br&gt;
variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"eu-west-2"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BEDROCK_MODEL_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"global.amazon.nova-2-lite-v1:0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normal AWS credentials must also be available through an AWS profile,&lt;br&gt;
environment variables, or an assigned IAM role.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>strandssdk</category>
      <category>bedrock</category>
      <category>langchain</category>
    </item>
    <item>
      <title># 🤖 Lab 07: Building Multi-Agent Systems with an Orchestrator | Strands Agentic AI</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Sun, 31 May 2026 06:06:09 +0000</pubDate>
      <link>https://dev.to/d3vjamal/-lab-07-building-multi-agent-systems-with-an-orchestrator-strands-agentic-ai-4o4h</link>
      <guid>https://dev.to/d3vjamal/-lab-07-building-multi-agent-systems-with-an-orchestrator-strands-agentic-ai-4o4h</guid>
      <description>&lt;p&gt;So far in this series, we've built agents, custom tools, MCP integrations, and MCP servers.&lt;/p&gt;

&lt;p&gt;But real-world AI applications often require multiple specialists working together.&lt;/p&gt;

&lt;p&gt;Instead of creating one giant agent responsible for everything, we can create multiple specialized agents and use a central orchestrator to route requests to the right expert.&lt;/p&gt;

&lt;p&gt;In this lab, we'll build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Study Assistant&lt;/li&gt;
&lt;li&gt;An Expense Assistant&lt;/li&gt;
&lt;li&gt;An Orchestrator Agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The orchestrator will decide which specialist should handle the user's request.&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you'll understand one of the most important patterns in Agentic AI: &lt;strong&gt;Multi-Agent Architectures&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Strands Agentic AI Lab Series
&lt;/h2&gt;

&lt;p&gt;⬅️ Previous: Lab 07: Build Your First MCP Server&lt;/p&gt;

&lt;p&gt;📍 Current: Lab 08: Building Multi-Agent Systems&lt;/p&gt;

&lt;p&gt;➡️ Next: Lab 09: Agent Collaboration &amp;amp; Sequential Workflows&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What You'll Learn
&lt;/h2&gt;

&lt;p&gt;In this lab, you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What multi-agent systems are&lt;/li&gt;
&lt;li&gt;Why specialized agents outperform general-purpose agents&lt;/li&gt;
&lt;li&gt;How to build reusable agents&lt;/li&gt;
&lt;li&gt;How to create an orchestrator agent&lt;/li&gt;
&lt;li&gt;How to route requests dynamically&lt;/li&gt;
&lt;li&gt;How to add logging for debugging&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤖 Why Multi-Agent Systems?
&lt;/h2&gt;

&lt;p&gt;Imagine building a personal assistant that can help with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Studying&lt;/li&gt;
&lt;li&gt;Budgeting&lt;/li&gt;
&lt;li&gt;Fitness&lt;/li&gt;
&lt;li&gt;Travel&lt;/li&gt;
&lt;li&gt;Career advice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You could create one massive prompt. Or you could create specialists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  ↓
Orchestrator
  ↓
 ├── Study Agent
 ├── Expense Agent
 ├── Fitness Agent
 └── Travel Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Easier to maintain&lt;/li&gt;
&lt;li&gt;✅ Easier to scale&lt;/li&gt;
&lt;li&gt;✅ Easier to test&lt;/li&gt;
&lt;li&gt;✅ More accurate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture is commonly used in enterprise AI systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;Strands SDK&lt;/li&gt;
&lt;li&gt;AWS account&lt;/li&gt;
&lt;li&gt;Amazon Bedrock access&lt;/li&gt;
&lt;li&gt;AWS credentials configured&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;uv&lt;/code&gt; installed&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏗️ Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Our application looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  ↓
Orchestrator Agent
  ↓
 ├── study_assistant()
 │      ↓
 │   Study Agent
 │
 └── expense_assistant()
        ↓
     Expense Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The orchestrator never answers directly. Its job is to decide which specialist should handle the request.&lt;/p&gt;




&lt;h2&gt;
  
  
  📜 The Complete Script
&lt;/h2&gt;

&lt;p&gt;This lab introduces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reusable agent creation&lt;/li&gt;
&lt;li&gt;Specialized agents&lt;/li&gt;
&lt;li&gt;Tool-based routing&lt;/li&gt;
&lt;li&gt;Agent orchestration&lt;/li&gt;
&lt;li&gt;Structured logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's break it down step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 1: Configure Logging
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%(asctime)s | %(levelname)s | %(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logging helps us understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which agent was selected&lt;/li&gt;
&lt;li&gt;Which tool was called&lt;/li&gt;
&lt;li&gt;What response was generated&lt;/li&gt;
&lt;li&gt;Any errors that occurred&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO | User query received
INFO | study_assistant called
DEBUG | Study response generated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This becomes incredibly useful when debugging complex multi-agent systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 2: Configure the Bedrock Model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All agents in this lab share the same Bedrock model. This keeps the architecture simple. In production, different agents may use different models.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 3: Create a Reusable Agent Factory
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helper function creates specialized agents.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less code duplication&lt;/li&gt;
&lt;li&gt;Consistent configuration&lt;/li&gt;
&lt;li&gt;Easier maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of repeating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we centralize the logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 4: Create Specialized Agents
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Study Agent
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;study_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;study_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    You are a study assistant.
    Help users create learning plans.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learning plans&lt;/li&gt;
&lt;li&gt;Courses&lt;/li&gt;
&lt;li&gt;Certifications&lt;/li&gt;
&lt;li&gt;Exams&lt;/li&gt;
&lt;li&gt;Technical concepts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Expense Agent
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;expense_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expense_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    You are an expense assistant.
    Help users manage budgets.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Budgeting&lt;/li&gt;
&lt;li&gt;Savings&lt;/li&gt;
&lt;li&gt;Spending analysis&lt;/li&gt;
&lt;li&gt;Cost reduction&lt;/li&gt;
&lt;li&gt;Financial planning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each agent becomes an expert in its own domain.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 5: Expose Agents as Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Study Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;study_assistant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This wraps the Study Agent as a tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tool Call
     ↓
Study Agent
     ↓
Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expense Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expense_assistant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This wraps the Expense Agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tool Call
     ↓
Expense Agent
     ↓
Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the orchestrator can invoke either specialist.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 6: Create the Orchestrator Prompt
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;orchestrator_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a router assistant.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prompt defines routing rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Study topics:&lt;/strong&gt; study, learning, courses, practice, certifications, exams&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expense topics:&lt;/strong&gt; budget, money, savings, spending, expenses, cost&lt;/p&gt;

&lt;p&gt;The orchestrator's job is not to answer — its job is to route. Think of it as a smart receptionist.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 7: Build the Orchestrator Agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;orchestrator_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;orchestrator_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;study_assistant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;expense_assistant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the brain of the system. It receives the user request and chooses the correct specialist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 ↓
Orchestrator
 ↓
Correct Tool
 ↓
Specialized Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ▶️ Run the Application
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run labs/08-multi-agent-orchestrator/agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Example Interaction #1
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Help me prepare for AWS Cloud Practitioner.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Routing:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Orchestrator → study_assistant → Study Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here's a 4-week AWS Cloud Practitioner study plan...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Example Interaction #2
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How can I save ₹5000 every month?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Routing:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Orchestrator → expense_assistant → Expense Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's review your monthly expenses and identify savings opportunities...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Example Interaction #3
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I have an exam next month and need a budget for training materials.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query touches multiple domains. The orchestrator may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask a clarification question&lt;/li&gt;
&lt;li&gt;Choose the dominant topic&lt;/li&gt;
&lt;li&gt;Route accordingly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This demonstrates why orchestration logic matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 What Happened Behind the Scenes?
&lt;/h2&gt;

&lt;p&gt;When a user submits a request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Query
     ↓
Orchestrator Agent
     ↓
Tool Selection
     ↓
Specialized Agent
     ↓
Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The orchestrator never becomes an expert — instead, it delegates expertise. This pattern is called &lt;strong&gt;Agent Orchestration&lt;/strong&gt;, and it's widely used in production AI systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Why Developers Love This Pattern
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Without multi-agent systems:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Huge prompts&lt;/li&gt;
&lt;li&gt;❌ Mixed responsibilities&lt;/li&gt;
&lt;li&gt;❌ Difficult maintenance&lt;/li&gt;
&lt;li&gt;❌ Poor scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;With multi-agent systems:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Specialized expertise&lt;/li&gt;
&lt;li&gt;✅ Easier debugging&lt;/li&gt;
&lt;li&gt;✅ Modular design&lt;/li&gt;
&lt;li&gt;✅ Independent evolution&lt;/li&gt;
&lt;li&gt;✅ Better scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each agent focuses on one job and does it well.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌍 Real-World Use Cases
&lt;/h2&gt;

&lt;p&gt;This same architecture powers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer Support&lt;/strong&gt; — Billing Agent, Technical Agent, Escalation Agent&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Healthcare&lt;/strong&gt; — Symptoms Agent, Insurance Agent, Appointment Agent&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enterprise Operations&lt;/strong&gt; — HR Agent, Finance Agent, IT Agent, Legal Agent&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Personal Assistants&lt;/strong&gt; — Study Agent, Budget Agent, Fitness Agent, Travel Agent&lt;/p&gt;

&lt;p&gt;The possibilities are endless.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Multi-agent systems separate responsibilities&lt;/li&gt;
&lt;li&gt;Specialized agents improve accuracy&lt;/li&gt;
&lt;li&gt;Orchestrators route requests intelligently&lt;/li&gt;
&lt;li&gt;Tools can act as wrappers around agents&lt;/li&gt;
&lt;li&gt;Logging makes orchestration easier to debug&lt;/li&gt;
&lt;li&gt;This pattern scales extremely well in production&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Source Code
&lt;/h2&gt;

&lt;p&gt;GitHub Repository: &lt;a href="https://github.com/d3vjamal/strands-agents-labs" rel="noopener noreferrer"&gt;d3vjamal/strands-agents-labs&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Continue Learning
&lt;/h2&gt;

&lt;p&gt;⬅️ Previous Lab: &lt;a href="https://dev.to/d3vjamal/-lab-06-build-your-first-mcp-server-with-streamable-http-strands-agentic-ai-1995"&gt;Lab 06: Build Your First MCP Server with Streamable HTTP | Strands Agentic AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;➡️ Next Lab: In the next tutorial, we'll move beyond simple routing and explore how multiple agents can collaborate together, passing information between each other to solve complex tasks that no single agent can handle alone.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>tutorial</category>
    </item>
    <item>
      <title># 🧮 Lab 06: Build Your First MCP Server with Streamable HTTP | Strands Agentic AI</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Sun, 31 May 2026 04:48:00 +0000</pubDate>
      <link>https://dev.to/d3vjamal/-lab-06-build-your-first-mcp-server-with-streamable-http-strands-agentic-ai-1995</link>
      <guid>https://dev.to/d3vjamal/-lab-06-build-your-first-mcp-server-with-streamable-http-strands-agentic-ai-1995</guid>
      <description>&lt;p&gt;In the previous labs, we connected a Strands Agent to an existing MCP server and used its tools.&lt;/p&gt;

&lt;p&gt;But what if you want to create your own MCP server?&lt;/p&gt;

&lt;p&gt;That's exactly what we'll do in this lab.&lt;/p&gt;

&lt;p&gt;We'll build a Calculator MCP Server that exposes arithmetic operations such as addition, subtraction, multiplication, and division. Then we'll connect a Strands Agent to that server using Streamable HTTP transport.&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you'll understand both sides of the MCP ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP Server&lt;/li&gt;
&lt;li&gt;MCP Client&lt;/li&gt;
&lt;li&gt;Strands Agent&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Strands Agentic AI Lab Series
&lt;/h2&gt;

&lt;p&gt;⬅️ Previous: Lab 06: Connecting to MCP with STDIO&lt;/p&gt;

&lt;p&gt;📍 Current: Lab 07: Build Your First MCP Server&lt;/p&gt;

&lt;p&gt;➡️ Next: Lab 08: Advanced MCP Tools &amp;amp; Multi-Tool Workflows&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What You'll Learn
&lt;/h2&gt;

&lt;p&gt;In this lab, you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to create an MCP Server&lt;/li&gt;
&lt;li&gt;How MCP tools are exposed&lt;/li&gt;
&lt;li&gt;How Streamable HTTP transport works&lt;/li&gt;
&lt;li&gt;How to connect a Strands Agent to a custom MCP server&lt;/li&gt;
&lt;li&gt;How agents invoke MCP tools automatically&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤖 Why Build Your Own MCP Server?
&lt;/h2&gt;

&lt;p&gt;Previously we consumed an existing MCP server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
AWS Documentation MCP Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we'll build one ourselves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
Your MCP Server
  ↓
Your Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to expose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal APIs&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Business Logic&lt;/li&gt;
&lt;li&gt;Enterprise Systems&lt;/li&gt;
&lt;li&gt;Custom Applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;through a standard MCP interface.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ Architecture
&lt;/h2&gt;

&lt;p&gt;Our solution looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  ↓
Strands Agent
  ↓
MCP Client
  ↓
Calculator MCP Server
  ↓
Calculator Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent doesn't perform calculations directly.&lt;/p&gt;

&lt;p&gt;Instead, it delegates them to MCP tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;Strands SDK&lt;/li&gt;
&lt;li&gt;MCP SDK&lt;/li&gt;
&lt;li&gt;AWS Bedrock access&lt;/li&gt;
&lt;li&gt;uv installed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;strands-agents
pip &lt;span class="nb"&gt;install &lt;/span&gt;mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📜 The Complete Script
&lt;/h2&gt;

&lt;p&gt;This example creates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An MCP Calculator Server&lt;/li&gt;
&lt;li&gt;Four calculator tools&lt;/li&gt;
&lt;li&gt;A Strands Agent&lt;/li&gt;
&lt;li&gt;An interactive chat loop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent automatically uses MCP tools whenever calculations are required.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 1: Create the MCP Server
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastMCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Calculator Server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This initializes a new MCP server.&lt;/p&gt;

&lt;p&gt;Think of it as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Web Framework
    ↓
Routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but for AI tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MCP Server
    ↓
Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚙️ Step 2: Create MCP Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Addition Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Add two numbers together&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Subtraction Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Subtract one number from another&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multiplication Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Multiply two numbers together&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Division Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Divide one number by another&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot divide by zero&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every tool becomes automatically discoverable through MCP.&lt;/p&gt;

&lt;p&gt;No additional registration is required.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 3: Start the MCP Server
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;streamable-http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This launches the MCP server using Streamable HTTP transport.&lt;/p&gt;

&lt;p&gt;Server endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now other MCP clients can connect.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 4: Run the Server in a Background Thread
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;server_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;start_calculator_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;daemon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Calculator Server
      +
Strands Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;running simultaneously.&lt;/p&gt;

&lt;p&gt;The background thread keeps the server alive while the agent runs.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 5: Connect the MCP Client
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_streamable_http_transport&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;streamablehttp_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8000/mcp/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates an MCP Client connection.&lt;/p&gt;

&lt;p&gt;Architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
   ↓
MCP Client
   ↓
HTTP Transport
   ↓
Calculator Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚙️ Step 6: Discover Available Tools
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;streamable_http_mcp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools_sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of MCP's biggest advantages.&lt;/p&gt;

&lt;p&gt;Instead of manually registering tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the client automatically discovers them.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Available MCP tools:

add
subtract
multiply
divide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚙️ Step 7: Create the Agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those tools came directly from the MCP Server.&lt;/p&gt;

&lt;p&gt;No custom integration required.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 8: Interactive Calculator Assistant
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Question: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a conversational calculator.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question:
What is 125 * 42?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5250
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
 ↓
multiply()
 ↓
5250
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ▶️ Run the Application
&lt;/h2&gt;

&lt;p&gt;Execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run labs/07-mcp-calculator-server/agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Example Interaction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is 25 + 17?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question
   ↓
Agent Reasoning
   ↓
add Tool
   ↓
42
   ↓
Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;25 + 17 = 42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔍 What Happened Behind the Scenes?
&lt;/h2&gt;

&lt;p&gt;When you asked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is 25 + 17?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understood the request.&lt;/li&gt;
&lt;li&gt;Found an MCP tool capable of addition.&lt;/li&gt;
&lt;li&gt;Invoked the tool.&lt;/li&gt;
&lt;li&gt;Received the result.&lt;/li&gt;
&lt;li&gt;Generated a response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The actual calculation happened in the MCP Server.&lt;/p&gt;

&lt;p&gt;Not in the LLM.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Why This Matters
&lt;/h2&gt;

&lt;p&gt;This simple calculator demonstrates a powerful concept.&lt;/p&gt;

&lt;p&gt;Today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add()
subtract()
multiply()
divide()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tomorrow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create Customer
Generate Invoice
Query Database
Deploy Lambda
Update CRM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact same MCP architecture scales to enterprise applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MCP Servers expose tools to AI agents&lt;/li&gt;
&lt;li&gt;FastMCP makes building servers simple&lt;/li&gt;
&lt;li&gt;Streamable HTTP enables remote communication&lt;/li&gt;
&lt;li&gt;Agents automatically discover tools&lt;/li&gt;
&lt;li&gt;MCP separates tool implementation from agent logic&lt;/li&gt;
&lt;li&gt;This pattern scales from calculators to enterprise systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Source Code
&lt;/h2&gt;

&lt;p&gt;Lab Source Code:&lt;br&gt;
Your GitHub Repository&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Continue Learning
&lt;/h2&gt;

&lt;p&gt;⬅️ Previous Lab&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/d3vjamal/-lab-06-connecting-to-an-mcp-server-with-stdio-transport-strands-agentic-ai-4c03"&gt;Lab 05: Connecting to an MCP Server with STDIO Transport | Strands Agentic AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;➡️ Next Lab&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/d3vjamal/-lab-07-building-multi-agent-systems-with-an-orchestrator-strands-agentic-ai-4o4h"&gt;Lab 07:  Building Multi-Agent Systems with an Orchestrator | Strands Agentic AI&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Next Lab
&lt;/h2&gt;

&lt;p&gt;In the next tutorial, we'll build more sophisticated MCP tools, explore tool schemas, and learn how agents can choose between multiple MCP capabilities to solve complex tasks.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>strands</category>
      <category>agenticai</category>
      <category>bedrockaws</category>
    </item>
    <item>
      <title># 🚀 Lab 05: Connecting to an MCP Server with STDIO Transport | Strands Agentic AI</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Sun, 31 May 2026 04:14:05 +0000</pubDate>
      <link>https://dev.to/d3vjamal/-lab-06-connecting-to-an-mcp-server-with-stdio-transport-strands-agentic-ai-4c03</link>
      <guid>https://dev.to/d3vjamal/-lab-06-connecting-to-an-mcp-server-with-stdio-transport-strands-agentic-ai-4c03</guid>
      <description>&lt;p&gt;In the previous lab, we learned what Model Context Protocol (MCP) is and why it is becoming the standard way for AI agents to access tools and external systems.&lt;/p&gt;

&lt;p&gt;Now it's time to build a real MCP-powered agent.&lt;/p&gt;

&lt;p&gt;In this lab, you'll connect a Strands Agent to the AWS Documentation MCP Server using STDIO transport and allow the agent to retrieve information directly from AWS documentation.&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you'll have an AWS Documentation Assistant capable of answering AWS questions using MCP-provided tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Strands Agentic AI Lab Series
&lt;/h2&gt;

&lt;p&gt;⬅️ Previous: Lab 05: Introduction to MCP&lt;/p&gt;

&lt;p&gt;📍 Current: Lab 06: Connecting to an MCP Server with STDIO Transport&lt;/p&gt;

&lt;p&gt;➡️ Next: Lab 07: Exploring MCP Tools and Capabilities&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What You'll Learn
&lt;/h2&gt;

&lt;p&gt;In this lab, you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What STDIO transport is&lt;/li&gt;
&lt;li&gt;How MCP clients communicate with MCP servers&lt;/li&gt;
&lt;li&gt;How to connect to an AWS Documentation MCP Server&lt;/li&gt;
&lt;li&gt;How to discover available tools dynamically&lt;/li&gt;
&lt;li&gt;How to build an AI assistant powered by MCP tools&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤖 Why STDIO Transport?
&lt;/h2&gt;

&lt;p&gt;MCP supports multiple communication methods.&lt;/p&gt;

&lt;p&gt;The simplest is STDIO.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
STDIO
  ↓
MCP Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of communicating over a network, the agent and MCP server communicate through standard input and output streams.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple setup&lt;/li&gt;
&lt;li&gt;Fast local development&lt;/li&gt;
&lt;li&gt;No network configuration&lt;/li&gt;
&lt;li&gt;Great for experimentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of STDIO as two applications having a direct private conversation.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;AWS credentials configured&lt;/li&gt;
&lt;li&gt;Amazon Bedrock access&lt;/li&gt;
&lt;li&gt;uv installed&lt;/li&gt;
&lt;li&gt;Strands SDK installed&lt;/li&gt;
&lt;li&gt;MCP SDK installed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;strands-agents
pip &lt;span class="nb"&gt;install &lt;/span&gt;mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📜 The Script
&lt;/h2&gt;

&lt;p&gt;Let's start with the complete example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.tools.mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;

&lt;span class="c1"&gt;# Bedrock
&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Connect to an MCP server using stdio transport
&lt;/span&gt;&lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;StdioServerParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;awslabs.aws-documentation-mcp-server@latest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools_sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        You are an AWS Documentation expert.
        Use the tools that are available to provide factual information.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is AWS Lambda?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's break it down.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 1: Import MCP Components
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.tools.mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These imports provide the building blocks for MCP communication.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCPClient
&lt;/h3&gt;

&lt;p&gt;Creates a bridge between Strands and the MCP server.&lt;/p&gt;

&lt;h3&gt;
  
  
  stdio_client
&lt;/h3&gt;

&lt;p&gt;Handles communication over standard input and output.&lt;/p&gt;

&lt;h3&gt;
  
  
  StdioServerParameters
&lt;/h3&gt;

&lt;p&gt;Defines how the MCP server should start.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 2: Configure the Bedrock Model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This model performs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reasoning&lt;/li&gt;
&lt;li&gt;Tool selection&lt;/li&gt;
&lt;li&gt;Response generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The MCP server provides tools.&lt;/p&gt;

&lt;p&gt;The LLM decides how to use them.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 3: Configure the MCP Server
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;StdioServerParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;awslabs.aws-documentation-mcp-server@latest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This launches the AWS Documentation MCP Server.&lt;/p&gt;

&lt;p&gt;Architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strands Agent
       ↓
MCP Client
       ↓
AWS Documentation MCP Server
       ↓
AWS Documentation Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server automatically exposes tools to the agent.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 4: Platform Differences
&lt;/h2&gt;

&lt;h3&gt;
  
  
  macOS/Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;awslabs.aws-documentation-mcp-server@latest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--from&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;awslabs.aws-documentation-mcp-server@latest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;awslabs.aws-documentation-mcp-server.exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server package is the same.&lt;/p&gt;

&lt;p&gt;Only the launch syntax changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 5: Start the MCP Session
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts the MCP server session.&lt;/p&gt;

&lt;p&gt;Once inside the context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server launches&lt;/li&gt;
&lt;li&gt;Connection is established&lt;/li&gt;
&lt;li&gt;Tools become available&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When execution completes, resources are cleaned up automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 6: Discover Available Tools
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools_sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where MCP becomes powerful.&lt;/p&gt;

&lt;p&gt;Instead of manually creating tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_docs&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can simply discover tools provided by the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connect
    ↓
Discover
    ↓
Use
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No custom tool implementation required.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 7: Create the Agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    You are an AWS Documentation expert.
    Use the tools that are available to provide factual information.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These tools come directly from the MCP server.&lt;/p&gt;

&lt;p&gt;The agent now has access to AWS documentation capabilities without any additional coding.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 8: Ask a Question
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is AWS Lambda?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Question
       ↓
Agent Analysis
       ↓
MCP Tool Selection
       ↓
AWS Documentation Search
       ↓
Information Retrieved
       ↓
Final Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent uses official AWS documentation instead of relying only on model memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  ▶️ Run the Agent
&lt;/h2&gt;

&lt;p&gt;Execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run labs/06-mcp-stdio-client/agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Example Interaction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is AWS Lambda?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question Received
       ↓
Discover Documentation Tool
       ↓
Query AWS Documentation
       ↓
Retrieve Results
       ↓
Generate Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Lambda is a serverless compute service that allows you to run code without provisioning or managing servers.

Lambda automatically scales your application and charges only for the compute time used.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔍 What Happened Behind the Scenes?
&lt;/h2&gt;

&lt;p&gt;When the question was asked:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The LLM analyzed the request.&lt;/li&gt;
&lt;li&gt;It discovered documentation tools.&lt;/li&gt;
&lt;li&gt;It selected the most relevant tool.&lt;/li&gt;
&lt;li&gt;The MCP server retrieved AWS documentation.&lt;/li&gt;
&lt;li&gt;Results were returned to the model.&lt;/li&gt;
&lt;li&gt;The model generated the final answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent never needed a custom Python function.&lt;/p&gt;

&lt;p&gt;The MCP server supplied everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Why Developers Love MCP
&lt;/h2&gt;

&lt;p&gt;Without MCP:&lt;/p&gt;

&lt;p&gt;❌ Build custom integrations&lt;/p&gt;

&lt;p&gt;❌ Maintain tools manually&lt;/p&gt;

&lt;p&gt;❌ Write wrappers for every service&lt;/p&gt;

&lt;p&gt;With MCP:&lt;/p&gt;

&lt;p&gt;✅ Connect once&lt;/p&gt;

&lt;p&gt;✅ Discover tools automatically&lt;/p&gt;

&lt;p&gt;✅ Reuse existing integrations&lt;/p&gt;

&lt;p&gt;✅ Build agents faster&lt;/p&gt;

&lt;p&gt;MCP turns integrations into plug-and-play components.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;STDIO is the simplest MCP transport&lt;/li&gt;
&lt;li&gt;MCP servers expose tools dynamically&lt;/li&gt;
&lt;li&gt;Agents can discover tools automatically&lt;/li&gt;
&lt;li&gt;AWS Documentation MCP Server provides factual AWS information&lt;/li&gt;
&lt;li&gt;MCP dramatically reduces integration effort&lt;/li&gt;
&lt;li&gt;Strands Agents integrate seamlessly with MCP&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Source Code
&lt;/h2&gt;

&lt;p&gt;GitHub Repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/d3vjamal/strands-agents-labs" rel="noopener noreferrer"&gt;https://github.com/d3vjamal/strands-agents-labs&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Continue Learning
&lt;/h2&gt;

&lt;p&gt;⬅️ Previous Lab&lt;/p&gt;

&lt;p&gt;Lab 05: Introduction to MCP&lt;/p&gt;

&lt;p&gt;➡️ Next Lab&lt;/p&gt;

&lt;p&gt;Lab 07: Exploring MCP Tools and Capabilities&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Next Lab
&lt;/h2&gt;

&lt;p&gt;In the next tutorial, we'll inspect the tools exposed by an MCP server, understand their schemas, and learn how agents choose the right tool for a given task.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agenticai</category>
      <category>strands</category>
      <category>bedrockai</category>
    </item>
    <item>
      <title># 🔌 Lab 05: Using MCP (Model Context Protocol) with Strands Agents | Strands Agentic AI</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Sun, 31 May 2026 04:05:33 +0000</pubDate>
      <link>https://dev.to/d3vjamal/-lab-05-using-mcp-model-context-protocol-with-strands-agents-strands-agentic-ai-49ca</link>
      <guid>https://dev.to/d3vjamal/-lab-05-using-mcp-model-context-protocol-with-strands-agents-strands-agentic-ai-49ca</guid>
      <description>&lt;p&gt;So far in this series, we've built custom tools and taught agents how to interact with the outside world.&lt;/p&gt;

&lt;p&gt;But what if someone else has already built the tools you need?&lt;/p&gt;

&lt;p&gt;Instead of writing every integration yourself, you can connect your AI agent to an MCP Server.&lt;/p&gt;

&lt;p&gt;Model Context Protocol (MCP) is an open standard that allows AI agents to discover and use tools provided by external systems.&lt;/p&gt;

&lt;p&gt;In this lab, you'll connect a Strands Agent to the AWS Documentation MCP Server and allow the agent to retrieve factual AWS documentation directly from official sources.&lt;/p&gt;

&lt;p&gt;By the end of this lab, you'll have an AWS Documentation Assistant powered by MCP.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What You'll Learn
&lt;/h2&gt;

&lt;p&gt;In this lab, you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What MCP (Model Context Protocol) is&lt;/li&gt;
&lt;li&gt;Why MCP is becoming important in Agentic AI&lt;/li&gt;
&lt;li&gt;How to connect to an MCP server&lt;/li&gt;
&lt;li&gt;How to use STDIO transport&lt;/li&gt;
&lt;li&gt;How agents automatically discover MCP tools&lt;/li&gt;
&lt;li&gt;How to build an AWS Documentation Assistant&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤖 What is MCP?
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol (MCP) is an open protocol that allows AI models and agents to connect to external tools and data sources.&lt;/p&gt;

&lt;p&gt;Think of MCP as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USB for AI Agents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just as USB allows computers to connect to keyboards, printers, and storage devices, MCP allows AI agents to connect to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentation systems&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;Search engines&lt;/li&gt;
&lt;li&gt;Internal tools&lt;/li&gt;
&lt;li&gt;Enterprise applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without MCP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
Custom Tool
  ↓
External System
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With MCP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
MCP Server
  ↓
Many Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One connection can expose dozens of tools instantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;Amazon Bedrock access&lt;/li&gt;
&lt;li&gt;AWS credentials configured&lt;/li&gt;
&lt;li&gt;uv installed&lt;/li&gt;
&lt;li&gt;MCP SDK installed&lt;/li&gt;
&lt;li&gt;Strands SDK installed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;strands-agents
pip &lt;span class="nb"&gt;install &lt;/span&gt;mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🌟 Why MCP Matters
&lt;/h2&gt;

&lt;p&gt;Imagine you're building an AWS assistant.&lt;/p&gt;

&lt;p&gt;Without MCP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build Tool #1
Build Tool #2
Build Tool #3
Build Tool #4
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You must create and maintain every integration yourself.&lt;/p&gt;

&lt;p&gt;With MCP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connect MCP Server
Discover Tools
Start Using Them
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server handles the heavy lifting.&lt;/p&gt;

&lt;p&gt;Your agent simply consumes the available tools.&lt;/p&gt;

&lt;p&gt;This dramatically reduces development effort.&lt;/p&gt;




&lt;h2&gt;
  
  
  📜 The Script
&lt;/h2&gt;

&lt;p&gt;Let's start by looking at the complete example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.tools.mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;

&lt;span class="c1"&gt;# Bedrock
&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Connect to an MCP server using stdio transport
&lt;/span&gt;&lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;StdioServerParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;awslabs.aws-documentation-mcp-server@latest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools_sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        You are an AWS Documentation expert.
        Use the tools that are available to provide factual information.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is AWS Lambda?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's break it down.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 1: Import MCP Components
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.tools.mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These imports provide everything required to communicate with an MCP server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Components
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MCPClient&lt;/td&gt;
&lt;td&gt;Connects Strands to MCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stdio_client&lt;/td&gt;
&lt;td&gt;Uses standard input/output transport&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;StdioServerParameters&lt;/td&gt;
&lt;td&gt;Configures the MCP server&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 2: Configure Amazon Bedrock
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the reasoning engine behind our agent.&lt;/p&gt;

&lt;p&gt;The model decides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which tool to use&lt;/li&gt;
&lt;li&gt;What information to retrieve&lt;/li&gt;
&lt;li&gt;How to respond&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 3: Create the MCP Connection
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;StdioServerParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;awslabs.aws-documentation-mcp-server@latest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This establishes a connection to the AWS Documentation MCP Server.&lt;/p&gt;

&lt;p&gt;Think of it as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
MCP Client
  ↓
AWS Documentation MCP Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server exposes AWS documentation tools automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 4: Understanding STDIO Transport
&lt;/h2&gt;

&lt;p&gt;This lab uses STDIO transport.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent Process
      ⇅
Standard Input/Output
      ⇅
MCP Server Process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STDIO is ideal for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local development&lt;/li&gt;
&lt;li&gt;Local testing&lt;/li&gt;
&lt;li&gt;Lightweight integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because communication happens through process streams, no network setup is required.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 5: Start the MCP Session
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This opens a connection to the MCP server.&lt;/p&gt;

&lt;p&gt;Once inside the context manager:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server starts&lt;/li&gt;
&lt;li&gt;Tools become available&lt;/li&gt;
&lt;li&gt;Agent can access them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When execution finishes, the connection closes automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 6: Discover Available Tools
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools_sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of the most powerful MCP features.&lt;/p&gt;

&lt;p&gt;Instead of manually creating tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stdio_mcp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools_sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent automatically discovers everything exposed by the MCP server.&lt;/p&gt;

&lt;p&gt;Think of it like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connect
    ↓
Discover Tools
    ↓
Use Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No additional coding required.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 7: Create the Agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    You are an AWS Documentation expert.
    Use the tools that are available to provide factual information.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice something interesting.&lt;/p&gt;

&lt;p&gt;We aren't manually registering tools.&lt;/p&gt;

&lt;p&gt;Instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;contains every tool discovered from the MCP server.&lt;/p&gt;

&lt;p&gt;The agent now has access to AWS documentation capabilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 8: Ask a Question
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is AWS Lambda?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Question
       ↓
Agent Analysis
       ↓
MCP Tool Selection
       ↓
AWS Documentation Search
       ↓
Documentation Retrieved
       ↓
Final Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The answer comes from official AWS documentation rather than relying solely on model memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  ▶️ Run the Agent
&lt;/h2&gt;

&lt;p&gt;Execute the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run labs/05-mcp-introduction/agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Example Interaction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is AWS Lambda?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question Received
       ↓
Discover Documentation Tool
       ↓
Query AWS Documentation
       ↓
Retrieve Information
       ↓
Generate Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Lambda is a serverless compute service that lets you run code without provisioning or managing servers.

You pay only for the compute time consumed and can automatically scale applications in response to demand.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact response may vary depending on the documentation version and model.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 What Makes MCP Different?
&lt;/h2&gt;

&lt;p&gt;Traditional Tool Approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build Tool
Register Tool
Maintain Tool
Update Tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MCP Approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connect Server
Discover Tools
Use Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server owns the implementation.&lt;/p&gt;

&lt;p&gt;Your agent simply consumes capabilities.&lt;/p&gt;

&lt;p&gt;This dramatically improves scalability.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Real-World MCP Use Cases
&lt;/h2&gt;

&lt;p&gt;MCP is useful for connecting agents to:&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation Systems
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Documentation
Azure Documentation
Internal Knowledge Bases
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Databases
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PostgreSQL
MySQL
MongoDB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Development Tools
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub
GitLab
Jira
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cloud Services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS
Azure
Google Cloud
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enterprise Systems
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CRM
ERP
HR Systems
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The possibilities are nearly endless.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Why Developers Love MCP
&lt;/h2&gt;

&lt;p&gt;Without MCP:&lt;/p&gt;

&lt;p&gt;❌ Build every integration yourself&lt;/p&gt;

&lt;p&gt;❌ Maintain tool definitions&lt;/p&gt;

&lt;p&gt;❌ Handle protocol changes&lt;/p&gt;

&lt;p&gt;❌ Create custom wrappers&lt;/p&gt;

&lt;p&gt;With MCP:&lt;/p&gt;

&lt;p&gt;✅ Discover tools automatically&lt;/p&gt;

&lt;p&gt;✅ Reuse existing integrations&lt;/p&gt;

&lt;p&gt;✅ Standardized communication&lt;/p&gt;

&lt;p&gt;✅ Faster development&lt;/p&gt;

&lt;p&gt;✅ Easier maintenance&lt;/p&gt;

&lt;p&gt;MCP shifts focus from integration work to solving business problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MCP stands for Model Context Protocol&lt;/li&gt;
&lt;li&gt;MCP allows agents to connect to external tool providers&lt;/li&gt;
&lt;li&gt;STDIO transport is perfect for local development&lt;/li&gt;
&lt;li&gt;Agents can automatically discover available tools&lt;/li&gt;
&lt;li&gt;MCP significantly reduces integration effort&lt;/li&gt;
&lt;li&gt;The AWS Documentation MCP Server provides direct access to official AWS information&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Source Code
&lt;/h2&gt;

&lt;p&gt;GitHub Repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/d3vjamal/strands-agents-labs" rel="noopener noreferrer"&gt;https://github.com/d3vjamal/strands-agents-labs&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Next Lab
&lt;/h2&gt;

&lt;p&gt;In the next lab, we'll explore remote MCP servers and learn how agents can connect to tools running on different machines and services across the network.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Continue Learning
&lt;/h2&gt;

&lt;p&gt;⬅️ &lt;strong&gt;Previous Lab&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/d3vjamal/-lab-04b-building-a-web-search-tool-for-ai-agents-strands-agentic-ai-5b30"&gt;Lab 04B: Building a Web Search Tool for AI Agents&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;➡️ &lt;strong&gt;Next Lab&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.toNEXT_ARTICLE_URL"&gt;Lab 06: Remote MCP Servers&lt;/a&gt;&lt;/p&gt;




</description>
      <category>strandsagent</category>
      <category>bedrockaws</category>
      <category>agentai</category>
    </item>
    <item>
      <title># 🌐 Lab 04B: Building a Web Search Tool for AI Agents | Strands Agentic AI</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Sun, 31 May 2026 03:52:57 +0000</pubDate>
      <link>https://dev.to/d3vjamal/-lab-04b-building-a-web-search-tool-for-ai-agents-strands-agentic-ai-5b30</link>
      <guid>https://dev.to/d3vjamal/-lab-04b-building-a-web-search-tool-for-ai-agents-strands-agentic-ai-5b30</guid>
      <description>&lt;p&gt;Large Language Models are powerful, but they have one major limitation:&lt;/p&gt;

&lt;p&gt;They only know what they were trained on.&lt;/p&gt;

&lt;p&gt;What if you want your AI agent to access the latest information from the web?&lt;/p&gt;

&lt;p&gt;That's where custom tools become incredibly useful.&lt;/p&gt;

&lt;p&gt;In this lab, you'll build a custom web search tool using DuckDuckGo Search (DDGS) and connect it to a Strands Agent. This allows the agent to retrieve up-to-date information and provide responses based on real-time search results.&lt;/p&gt;

&lt;p&gt;By the end of this lab, you'll have a Recipe Assistant that can search the web for recipes and cooking information.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What You'll Learn
&lt;/h2&gt;

&lt;p&gt;In this lab, you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to create a custom web search tool&lt;/li&gt;
&lt;li&gt;How to integrate third-party Python libraries into Strands tools&lt;/li&gt;
&lt;li&gt;How agents use tools to access live information&lt;/li&gt;
&lt;li&gt;How to handle API errors gracefully&lt;/li&gt;
&lt;li&gt;How to build a specialized AI assistant&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤖 Why Web Search Matters
&lt;/h2&gt;

&lt;p&gt;LLMs have knowledge cutoffs.&lt;/p&gt;

&lt;p&gt;For example, an LLM may know:&lt;/p&gt;

&lt;p&gt;✅ How recipes work&lt;/p&gt;

&lt;p&gt;✅ Common cooking techniques&lt;/p&gt;

&lt;p&gt;✅ Popular dishes&lt;/p&gt;

&lt;p&gt;But it may not know:&lt;/p&gt;

&lt;p&gt;❌ Latest recipes&lt;/p&gt;

&lt;p&gt;❌ Current food trends&lt;/p&gt;

&lt;p&gt;❌ Newly published cooking content&lt;/p&gt;

&lt;p&gt;❌ Real-time information&lt;/p&gt;

&lt;p&gt;A web search tool solves this problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Question
      ↓
Agent Analysis
      ↓
Web Search Tool
      ↓
Search Results
      ↓
Agent Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of relying only on training data, the agent can retrieve fresh information from the web.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;Amazon Bedrock access&lt;/li&gt;
&lt;li&gt;AWS credentials configured&lt;/li&gt;
&lt;li&gt;uv installed&lt;/li&gt;
&lt;li&gt;DDGS package installed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install DDGS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;ddgs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📜 The Script
&lt;/h2&gt;

&lt;p&gt;Let's start by looking at the complete example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ddgs&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DDGS&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ddgs.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RatelimitException&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;

&lt;span class="c1"&gt;# Configure logging
&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;strands&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Define a websearch tool
&lt;/span&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;websearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search the web to get updated information.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DDGS&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_results&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No results found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;RatelimitException&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RatelimitException: Please try again after a short delay.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exception: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="c1"&gt;# Bedrock
&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Create a recipe assistant agent
&lt;/span&gt;&lt;span class="n"&gt;recipe_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    You are RecipeBot, a helpful cooking assistant.
    Help users find recipes based on ingredients and answer cooking questions.
    Use the websearch tool to find recipes when users mention ingredients or to look up cooking information.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;websearch&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;recipe_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Suggest a recipe with chicken and capsicum.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Metrics : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's break it down step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 1: Import Dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ddgs&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DDGS&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ddgs.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RatelimitException&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're importing:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Import&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent&lt;/td&gt;
&lt;td&gt;Creates the AI agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tool&lt;/td&gt;
&lt;td&gt;Converts a Python function into a Strands tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DDGS&lt;/td&gt;
&lt;td&gt;Performs DuckDuckGo searches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RatelimitException&lt;/td&gt;
&lt;td&gt;Handles search rate limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;logging&lt;/td&gt;
&lt;td&gt;Displays runtime information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BedrockModel&lt;/td&gt;
&lt;td&gt;Connects to Amazon Bedrock&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 2: Configure Logging
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;strands&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logging helps us understand what the agent is doing during execution.&lt;/p&gt;

&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO | strands.agent | Processing user request
INFO | strands.tools | Executing websearch tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During development, logs provide valuable visibility into agent behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 3: Create the Web Search Tool
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;websearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function becomes a Strands tool through the &lt;code&gt;@tool&lt;/code&gt; decorator.&lt;/p&gt;

&lt;p&gt;The agent can now call this function whenever it needs information from the web.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;keywords&lt;/td&gt;
&lt;td&gt;Search query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;region&lt;/td&gt;
&lt;td&gt;Search region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;max_results&lt;/td&gt;
&lt;td&gt;Maximum number of results&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;websearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chicken capsicum recipe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚙️ Step 4: Search Using DDGS
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DDGS&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_results&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DDGS performs a DuckDuckGo search and returns matching results.&lt;/p&gt;

&lt;p&gt;These results are then sent back to the agent.&lt;/p&gt;

&lt;p&gt;The agent uses them to generate an informed response.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 5: Handle Errors Gracefully
&lt;/h2&gt;

&lt;p&gt;Production-ready tools should always handle failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rate Limit Handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;RatelimitException&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If too many requests are made, DDGS may temporarily block searches.&lt;/p&gt;

&lt;p&gt;Instead of crashing, the tool returns a helpful message.&lt;/p&gt;

&lt;h3&gt;
  
  
  General Error Handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unexpected failures are captured and returned safely.&lt;/p&gt;

&lt;p&gt;This improves reliability and user experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Why the Docstring Matters
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search the web to get updated information.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The docstring helps the LLM understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the tool does&lt;/li&gt;
&lt;li&gt;When it should use it&lt;/li&gt;
&lt;li&gt;What kind of information it can retrieve&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of the docstring as instructions for the AI.&lt;/p&gt;

&lt;p&gt;A clear description leads to better tool selection.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 6: Configure Amazon Bedrock
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This model powers the reasoning and decision-making process.&lt;/p&gt;

&lt;p&gt;The agent determines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether web search is needed&lt;/li&gt;
&lt;li&gt;What search query to generate&lt;/li&gt;
&lt;li&gt;How to interpret results&lt;/li&gt;
&lt;li&gt;How to respond to users&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 7: Create a Specialized Recipe Agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;recipe_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    You are RecipeBot...
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;websearch&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This agent has a clear responsibility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find recipes
Answer cooking questions
Search the web when necessary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system prompt defines the agent's personality and capabilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 8: Ask the Agent a Question
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;recipe_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Suggest a recipe with chicken and capsicum.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent receives the request and reasons about how to solve it.&lt;/p&gt;

&lt;p&gt;Because recipe information may require fresh data, it can choose to invoke the web search tool.&lt;/p&gt;




&lt;h2&gt;
  
  
  ▶️ Run the Agent
&lt;/h2&gt;

&lt;p&gt;Execute the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run labs/04b-websearch-tool/agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Example Interaction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Suggest a recipe with chicken and capsicum.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Request
      ↓
Agent Analysis
      ↓
Web Search Tool
      ↓
Recipe Search Results
      ↓
Response Generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You can make a Chicken Capsicum Stir Fry.

Ingredients:
- Chicken breast
- Capsicum
- Onion
- Garlic
- Soy sauce

Instructions:
1. Sauté garlic and onion.
2. Add chicken and cook thoroughly.
3. Add sliced capsicum.
4. Stir in soy sauce.
5. Serve hot with rice.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actual responses may vary depending on model and search results.&lt;/p&gt;




&lt;h2&gt;
  
  
  📈 Understanding Agent Metrics
&lt;/h2&gt;

&lt;p&gt;At the end of the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Metrics : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Metrics help monitor agent performance.&lt;/p&gt;

&lt;p&gt;You may see information such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input Tokens
Output Tokens
Latency
Tool Calls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These metrics become extremely useful when optimizing production agents.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 How Tool Calling Works
&lt;/h2&gt;

&lt;p&gt;When a user asks a question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Prompt
      ↓
Agent Reasoning
      ↓
Tool Selection
      ↓
Web Search
      ↓
Results Returned
      ↓
Final Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent automatically decides whether the tool should be used.&lt;/p&gt;

&lt;p&gt;You don't need to manually call the function.&lt;/p&gt;

&lt;p&gt;This is what makes agentic systems powerful.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Real-World Use Cases
&lt;/h2&gt;

&lt;p&gt;The same approach can be used for:&lt;/p&gt;

&lt;h3&gt;
  
  
  News Assistant
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search latest headlines
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Research Assistant
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search technical documentation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Travel Assistant
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search destinations and hotels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Shopping Assistant
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search products and reviews
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Support Assistant
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search knowledge bases
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A web search tool unlocks countless possibilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Custom tools allow agents to access live information&lt;/li&gt;
&lt;li&gt;DDGS provides a simple web search capability&lt;/li&gt;
&lt;li&gt;Error handling improves reliability&lt;/li&gt;
&lt;li&gt;Docstrings help the LLM understand tool functionality&lt;/li&gt;
&lt;li&gt;Agents automatically decide when to invoke tools&lt;/li&gt;
&lt;li&gt;Tool-based architectures make AI assistants far more useful&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Source Code
&lt;/h2&gt;

&lt;p&gt;GitHub Repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/d3vjamal/strands-agents-labs" rel="noopener noreferrer"&gt;https://github.com/d3vjamal/strands-agents-labs&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Previous Lab
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/d3vjamal/-lab-04a-creating-your-first-custom-tool-strands-agentic-ai-l7"&gt; Lab 04A: Creating Your First Custom Tool | Strands Agentic AI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>stands</category>
      <category>awsbedrock</category>
      <category>agenticai</category>
    </item>
    <item>
      <title># 🛠️ Lab 04A: Creating Your First Custom Tool | Strands Agentic AI</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Sun, 31 May 2026 03:48:47 +0000</pubDate>
      <link>https://dev.to/d3vjamal/-lab-04a-creating-your-first-custom-tool-strands-agentic-ai-l7</link>
      <guid>https://dev.to/d3vjamal/-lab-04a-creating-your-first-custom-tool-strands-agentic-ai-l7</guid>
      <description>&lt;p&gt;AI agents become truly powerful when they can perform actions beyond generating text.&lt;/p&gt;

&lt;p&gt;While large language models are great at reasoning, tools allow them to interact with the real world, process data, and execute custom logic.&lt;/p&gt;

&lt;p&gt;In this lab, you'll learn how to create your first custom tool using the &lt;code&gt;@tool&lt;/code&gt; decorator in Strands and expose it to an AI agent.&lt;/p&gt;

&lt;p&gt;By the end, your agent will be able to count words using your own Python function.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What You'll Learn
&lt;/h2&gt;

&lt;p&gt;In this lab, you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What tools are in Strands Agents&lt;/li&gt;
&lt;li&gt;How the &lt;code&gt;@tool&lt;/code&gt; decorator works&lt;/li&gt;
&lt;li&gt;How to create your own custom tool&lt;/li&gt;
&lt;li&gt;How agents automatically discover and use tools&lt;/li&gt;
&lt;li&gt;How tool docstrings help the LLM understand capabilities&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤖 Why Custom Tools Matter
&lt;/h2&gt;

&lt;p&gt;Without tools, an AI agent can only generate responses based on its training and reasoning.&lt;/p&gt;

&lt;p&gt;With tools, agents can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query databases&lt;/li&gt;
&lt;li&gt;Call APIs&lt;/li&gt;
&lt;li&gt;Read files&lt;/li&gt;
&lt;li&gt;Write files&lt;/li&gt;
&lt;li&gt;Perform calculations&lt;/li&gt;
&lt;li&gt;Execute business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of a language model as a brain.&lt;/p&gt;

&lt;p&gt;Tools are its hands.&lt;/p&gt;

&lt;p&gt;The brain can think about counting words, but a tool can perform the counting accurately and consistently.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;Amazon Bedrock access&lt;/li&gt;
&lt;li&gt;Access to a model such as &lt;code&gt;amazon.nova-2-lite-v1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AWS credentials configured&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;uv&lt;/code&gt; installed&lt;/li&gt;
&lt;li&gt;Completed Lab 01 and Lab 02&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📜 The Script
&lt;/h2&gt;

&lt;p&gt;Let's start by looking at the complete example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Just an example of using creating your custom tool
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;

&lt;span class="c1"&gt;# Bedrock
&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;# Set your preferred model ID here
&lt;/span&gt;    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Count words in text.

    This docstring is used by the LLM to understand the tool&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s purpose.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How many words are in this sentence?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's break it down step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 1: Import Required Modules
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're importing:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Import&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent&lt;/td&gt;
&lt;td&gt;Creates the AI agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tool&lt;/td&gt;
&lt;td&gt;Converts a Python function into a Strands tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BedrockModel&lt;/td&gt;
&lt;td&gt;Connects the agent to Amazon Bedrock&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;tool&lt;/code&gt; decorator is the star of this lab.&lt;/p&gt;

&lt;p&gt;It allows Strands to expose a Python function to the language model.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 2: Configure Amazon Bedrock
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the model that powers the agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;model_id&lt;/td&gt;
&lt;td&gt;Bedrock model identifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;region_name&lt;/td&gt;
&lt;td&gt;AWS region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;temperature&lt;/td&gt;
&lt;td&gt;Controls creativity and randomness&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For utility tools, lower temperatures often produce more predictable results.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 3: Create a Custom Tool
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Count words in text.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where the magic happens.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@tool&lt;/code&gt; decorator transforms a normal Python function into a tool that the agent can invoke.&lt;/p&gt;

&lt;h3&gt;
  
  
  Function Breakdown
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function simply splits text into words and returns the total count.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello world&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Why the Docstring Matters
&lt;/h2&gt;

&lt;p&gt;One of the most important parts of a custom tool is the docstring.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Count words in text.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM reads this description to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the tool does&lt;/li&gt;
&lt;li&gt;When it should use it&lt;/li&gt;
&lt;li&gt;What inputs it expects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of the docstring as instructions for the AI.&lt;/p&gt;

&lt;p&gt;A clear docstring helps the model choose the correct tool at the correct time.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 4: Register the Tool
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we provide the tool to the agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent now knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The tool exists&lt;/li&gt;
&lt;li&gt;What it does&lt;/li&gt;
&lt;li&gt;How to call it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From this point forward, the model can decide when to use it.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 5: Ask the Agent a Question
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How many words are in this sentence?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the agent receives this request, it reasons about the task.&lt;/p&gt;

&lt;p&gt;The model recognizes that counting words is exactly what the &lt;code&gt;word_count&lt;/code&gt; tool is designed to do.&lt;/p&gt;

&lt;p&gt;Instead of guessing, it invokes the tool and uses the result.&lt;/p&gt;




&lt;h2&gt;
  
  
  ▶️ Run the Agent
&lt;/h2&gt;

&lt;p&gt;Execute the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run labs/04a-custom-tool/agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Example Interaction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How many words are in this sentence?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Reasoning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This task requires counting words.
A tool named word_count is available.
I'll use the tool.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tool Execution
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How many words are in this sentence?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agent Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There are 7 words in the sentence.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔍 How Tool Calling Works
&lt;/h2&gt;

&lt;p&gt;When a user sends a request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Prompt
     ↓
Agent Analysis
     ↓
Tool Selection
     ↓
Tool Execution
     ↓
Result Returned
     ↓
Final Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent automatically decides whether a tool should be used.&lt;/p&gt;

&lt;p&gt;You don't explicitly call the function yourself.&lt;/p&gt;

&lt;p&gt;The LLM handles that decision-making process.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Real-World Tool Examples
&lt;/h2&gt;

&lt;p&gt;The same pattern can be used to build more powerful tools:&lt;/p&gt;

&lt;h3&gt;
  
  
  Calculator Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Date Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;current_date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Database Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AWS Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_s3_buckets&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the foundation of building production-ready AI agents.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tools extend the capabilities of AI agents&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;@tool&lt;/code&gt; decorator converts Python functions into agent tools&lt;/li&gt;
&lt;li&gt;Docstrings help the LLM understand tool functionality&lt;/li&gt;
&lt;li&gt;Agents automatically decide when to use tools&lt;/li&gt;
&lt;li&gt;Custom tools are the foundation of real-world agent workflows&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Source Code
&lt;/h2&gt;

&lt;p&gt;Lab Source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/d3vjamal/strands-agents-labs/tree/master/labs/04a-custom-tool" rel="noopener noreferrer"&gt;https://github.com/d3vjamal/strands-agents-labs/tree/master/labs/04a-custom-tool&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Next Lab
&lt;/h2&gt;

&lt;p&gt;In the next lab, we'll create more advanced tools with parameters and learn how agents can chain multiple tool calls together to solve complex tasks.&lt;/p&gt;

</description>
      <category>agenticai</category>
      <category>agents</category>
      <category>strandsagent</category>
      <category>awsbedrock</category>
    </item>
    <item>
      <title># 🔍 Lab 03: Logging and Debugging | Strands Agentic AI</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Fri, 29 May 2026 19:32:16 +0000</pubDate>
      <link>https://dev.to/d3vjamal/-lab-03-logging-and-debugging-strands-agentic-ai-mk5</link>
      <guid>https://dev.to/d3vjamal/-lab-03-logging-and-debugging-strands-agentic-ai-mk5</guid>
      <description>&lt;p&gt;AI agents can perform complex tasks, call tools, and interact with external services. But what happens when something goes wrong?&lt;/p&gt;

&lt;p&gt;Without logging, debugging an AI agent can feel like trying to solve a puzzle with half the pieces missing.&lt;/p&gt;

&lt;p&gt;In this lab, you'll learn how to enable logging in Strands Agents so you can observe what's happening behind the scenes, understand agent behavior, and troubleshoot issues more effectively.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What You'll Learn
&lt;/h2&gt;

&lt;p&gt;By the end of this lab, you'll understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How logging works in Strands Agents&lt;/li&gt;
&lt;li&gt;How to enable DEBUG logs&lt;/li&gt;
&lt;li&gt;How to inspect agent execution flow&lt;/li&gt;
&lt;li&gt;How to monitor tool invocations&lt;/li&gt;
&lt;li&gt;How logging helps troubleshoot agent issues&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤖 Why Logging Matters in Agentic AI
&lt;/h2&gt;

&lt;p&gt;Traditional applications usually follow a predictable flow.&lt;/p&gt;

&lt;p&gt;AI agents are different.&lt;/p&gt;

&lt;p&gt;A single prompt can trigger multiple reasoning steps, tool calls, and external API requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Prompt
     ↓
Agent Reasoning
     ↓
Tool Selection
     ↓
HTTP Request
     ↓
Response Processing
     ↓
Final Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If something fails during this process, logs help us understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which tool was selected&lt;/li&gt;
&lt;li&gt;What requests were sent&lt;/li&gt;
&lt;li&gt;What responses were received&lt;/li&gt;
&lt;li&gt;Where failures occurred&lt;/li&gt;
&lt;li&gt;How the agent reached its final answer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of logging as the flight recorder for your AI agent.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;Amazon Bedrock access&lt;/li&gt;
&lt;li&gt;Access to a model such as &lt;code&gt;amazon.nova-2-lite-v1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AWS credentials configured&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;uv&lt;/code&gt; installed&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📜 The Script
&lt;/h2&gt;

&lt;p&gt;Let's start by looking at the complete example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This lab is to teach you about logging
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http_request&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="c1"&gt;# Configure the root strands logger
&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;strands&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Add a handler to display logs in the terminal
&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%(levelname)s | %(name)s | %(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StreamHandler&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Configure the Bedrock model
&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Weather Information
    - You can also make HTTP requests to the National Weather Service API.
    - Process and display weather forecast data for locations in the United States.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="c1"&gt;# Create the agent with tools
&lt;/span&gt;&lt;span class="n"&gt;local_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;http_request&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Ask the agent a question
&lt;/span&gt;&lt;span class="nf"&gt;local_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what is the weather in new york?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's break it down.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 1: Configure Logging
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;strands&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%(levelname)s | %(name)s | %(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StreamHandler&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What is happening here?
&lt;/h3&gt;

&lt;p&gt;First, we configure Python's built-in logging module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;strands&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Strands to emit detailed debugging information.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;DEBUG&lt;/code&gt; level provides maximum visibility into agent execution.&lt;/p&gt;

&lt;p&gt;We then configure how logs appear in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%(levelname)s | %(name)s | %(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEBUG | strands.agent | Processing user request
INFO | strands.tools | Executing HTTP request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes logs easy to read and troubleshoot.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 2: Configure the Bedrock Model
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we create the LLM that powers our agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;model_id&lt;/td&gt;
&lt;td&gt;Bedrock model identifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;region_name&lt;/td&gt;
&lt;td&gt;AWS Region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;temperature&lt;/td&gt;
&lt;td&gt;Controls response randomness&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A lower temperature produces more consistent and predictable responses.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 3: Define the Agent's Role
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Weather Information
    - You can also make HTTP requests to the National Weather Service API.
    - Process and display weather forecast data for locations in the United States.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system prompt acts as the agent's instructions.&lt;/p&gt;

&lt;p&gt;It tells the model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What task it should perform&lt;/li&gt;
&lt;li&gt;Which information sources are available&lt;/li&gt;
&lt;li&gt;How it should behave&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case, the agent is focused on retrieving weather information.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 4: Add the HTTP Tool
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;http_request&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;http_request&lt;/code&gt; tool gives the agent the ability to access external APIs.&lt;/p&gt;

&lt;p&gt;Without tools, the agent can only rely on its training data.&lt;/p&gt;

&lt;p&gt;With tools, it can fetch live information from the internet.&lt;/p&gt;

&lt;p&gt;For weather data, the agent can query APIs and process real-time forecasts.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 5: Create the Agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;local_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;http_request&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model&lt;/li&gt;
&lt;li&gt;The instructions&lt;/li&gt;
&lt;li&gt;The available tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;into a working AI agent.&lt;/p&gt;




&lt;h2&gt;
  
  
  ▶️ Run the Agent
&lt;/h2&gt;

&lt;p&gt;Invoke the agent using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;local_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what is the weather in new york?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Analyze the request&lt;/li&gt;
&lt;li&gt;Decide whether a tool is needed&lt;/li&gt;
&lt;li&gt;Call the HTTP tool&lt;/li&gt;
&lt;li&gt;Retrieve weather information&lt;/li&gt;
&lt;li&gt;Generate a final response&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📊 Example Debug Output
&lt;/h2&gt;

&lt;p&gt;When running the script, you'll see logs similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEBUG | strands.agent | Processing user request
DEBUG | strands.agent | Selecting tool
INFO  | strands.tools | Executing HTTP request
INFO  | strands.tools | Response received
DEBUG | strands.agent | Generating final answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact output may vary depending on the model and SDK version.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Understanding the Log Levels
&lt;/h2&gt;

&lt;h3&gt;
  
  
  DEBUG
&lt;/h3&gt;

&lt;p&gt;Most detailed level.&lt;/p&gt;

&lt;p&gt;Useful during development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEBUG | Agent selecting tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  INFO
&lt;/h3&gt;

&lt;p&gt;General execution information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO | HTTP request executed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  WARNING
&lt;/h3&gt;

&lt;p&gt;Something unexpected happened, but execution continues.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WARNING | Missing optional parameter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ERROR
&lt;/h3&gt;

&lt;p&gt;Execution failed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR | Failed to call external API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💡 Why Developers Love Logs
&lt;/h2&gt;

&lt;p&gt;Imagine your agent gives an incorrect answer.&lt;/p&gt;

&lt;p&gt;Without logs:&lt;/p&gt;

&lt;p&gt;❌ No idea what happened.&lt;/p&gt;

&lt;p&gt;With logs:&lt;/p&gt;

&lt;p&gt;✅ See which tool was selected&lt;/p&gt;

&lt;p&gt;✅ Inspect API requests&lt;/p&gt;

&lt;p&gt;✅ Inspect responses&lt;/p&gt;

&lt;p&gt;✅ Find failures quickly&lt;/p&gt;

&lt;p&gt;✅ Improve prompts and tools&lt;/p&gt;

&lt;p&gt;Logs dramatically reduce debugging time.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Logging provides visibility into agent execution&lt;/li&gt;
&lt;li&gt;DEBUG logs help trace reasoning and tool usage&lt;/li&gt;
&lt;li&gt;Python's built-in logging module works seamlessly with Strands&lt;/li&gt;
&lt;li&gt;Logs make troubleshooting faster and easier&lt;/li&gt;
&lt;li&gt;Observability is essential for production-ready AI agents&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Source Code
&lt;/h2&gt;

&lt;p&gt;GitHub Repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/d3vjamal/strands-agents-labs" rel="noopener noreferrer"&gt;https://github.com/d3vjamal/strands-agents-labs&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Next Lab
&lt;/h2&gt;

&lt;p&gt;In the next lab, we'll explore custom tools and learn how to extend Strands Agents with capabilities tailored to your own applications.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agenticai</category>
      <category>strands</category>
    </item>
    <item>
      <title>Lab 02 — HTTP Tools Integration; Strands Agentic AI</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Fri, 29 May 2026 19:21:09 +0000</pubDate>
      <link>https://dev.to/d3vjamal/lab-02-http-tools-integration-strands-agentic-ai-415p</link>
      <guid>https://dev.to/d3vjamal/lab-02-http-tools-integration-strands-agentic-ai-415p</guid>
      <description>&lt;p&gt;Building My First AI Agent with Strands Agents: &lt;a href="https://dev.to/d3vjamal/building-my-first-ai-agent-with-strands-agents-3m0l"&gt;Part 1 link&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Objective
&lt;/h2&gt;

&lt;p&gt;Give your agent the ability to &lt;strong&gt;fetch live data from the internet&lt;/strong&gt; using the &lt;code&gt;http_request&lt;/code&gt; tool. In this lab the agent calls the US National Weather Service API to answer a weather question.&lt;/p&gt;

&lt;h2&gt;
  
  
  📖 Background
&lt;/h2&gt;

&lt;p&gt;Most useful agents need to reach out to external services. The &lt;code&gt;http_request&lt;/code&gt; tool lets an agent make GET/POST/PUT/DELETE requests to any URL. The agent decides &lt;em&gt;which&lt;/em&gt; URL to call, parses the response, and presents it in natural language.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔑 Key Concepts
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;http_request&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Built-in Strands tool for making HTTP calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System Prompt&lt;/td&gt;
&lt;td&gt;Guides the agent on which APIs to use and how to interpret responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API chaining&lt;/td&gt;
&lt;td&gt;The agent may make multiple HTTP calls (e.g. get coordinates → get forecast)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  ⚙️ Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;AWS credentials configured&lt;/li&gt;
&lt;li&gt;Internet connectivity (the agent calls &lt;code&gt;api.weather.gov&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Dependencies installed (&lt;code&gt;uv sync&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Lab 02 : Agentic ai with http_request tool&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This lab is to teach you about http_request tool
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http_request&lt;/span&gt;

&lt;span class="c1"&gt;# Configure the Bedrock model
&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;# Set your preferred model ID here (e.g., "global.amazon.nova-2-lite-v1:0")
&lt;/span&gt;    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Weather Information
    - You can also make HTTP requests to the National Weather Service API.
    - Process and display weather forecast data for locations in the United States.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="c1"&gt;# - When retrieving weather information, first get coordinates using https://api.weather.gov/points/{latitude},{longitude},  or
#         https://api.weather.gov/points/{zipcode}, then use the returned forecast URL. You can make additional http requests as well.
&lt;/span&gt;
&lt;span class="c1"&gt;# Create the agent with tools
&lt;/span&gt;&lt;span class="n"&gt;local_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Define a system Prompt
&lt;/span&gt;    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;http_request&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# Add your custom tools here
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nf"&gt;local_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what is the weather in new york?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ▶️ How to Run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run labs/02-http-tools/agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧪 Exercises
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Try a different city&lt;/strong&gt; — Change &lt;code&gt;"new york"&lt;/code&gt; to another US city and see if the agent resolves the correct API endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine tools&lt;/strong&gt; — Add &lt;code&gt;file_write&lt;/code&gt; so the agent saves the weather report to a file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-US weather&lt;/strong&gt; — The NWS API only covers the US. Modify the system prompt to use a global weather API like OpenWeatherMap instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error handling&lt;/strong&gt; — Disconnect from the internet and observe how the agent reacts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ALL LAB EXCERSIZE &lt;a href="https://github.com/d3vjamal/strands-agents-labs" rel="noopener noreferrer"&gt;GitHub Notes&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://strandsagents.com/latest/" rel="noopener noreferrer"&gt;Strands Tools — http_request&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.weather.gov/documentation/services-web-api" rel="noopener noreferrer"&gt;National Weather Service API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>agenticai</category>
      <category>strands</category>
      <category>aibuilding</category>
    </item>
    <item>
      <title>Building My First AI Agent with Strands Agents</title>
      <dc:creator>Jamal</dc:creator>
      <pubDate>Fri, 29 May 2026 19:06:35 +0000</pubDate>
      <link>https://dev.to/d3vjamal/building-my-first-ai-agent-with-strands-agents-3m0l</link>
      <guid>https://dev.to/d3vjamal/building-my-first-ai-agent-with-strands-agents-3m0l</guid>
      <description>&lt;p&gt;An agent is a program that uses a large-language model (LLM) to decide which actions to take based on a user's request. Strands Agents wraps this loop into a simple Python API.&lt;/p&gt;

&lt;p&gt;If you've been trying to build Agentic AI applications recently, you've probably noticed a major problem: &lt;strong&gt;boilerplate overload&lt;/strong&gt;. Frameworks like LangChain or LangGraph are incredibly powerful, but sometimes you just want a clean, fast, lightweight, and model-agnostic way to build production-ready agents.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Strands Agents&lt;/strong&gt;—a lean, modern open-source SDK designed to let developers build robust AI agents without the architectural bloat.&lt;/p&gt;

&lt;p&gt;In this 4-part series, we are going to explore how to take Strands from a blank screen to a production-grade multi-agent system. Let's get our hands dirty with Part 1!&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Quick Start
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1. 🛠️ Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we write code, let's set up a clean playground.&lt;/p&gt;

&lt;p&gt;Make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;AWS account with access credentials (&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;) and access granted to the &lt;code&gt;amazon.nova-2-lite-v1&lt;/code&gt; (or another Bedrock model) on Amazon Bedrock&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.astral.sh/uv/getting-started/installation/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; package manager&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. 🤖 What Is Agentic AI?
&lt;/h2&gt;

&lt;p&gt;Agentic AI refers to autonomous software systems powered by artificial intelligence that can perceive their environment, make decisions, and take actions independently to achieve specific goals.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. 📦 Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Clone the Repository
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/d3vjamal/strands-agents-labs.git
&lt;span class="nb"&gt;cd &lt;/span&gt;strands-agents-labs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;Lab 1: Run your first agent&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_write&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models.bedrock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="n"&gt;bedrock_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;# Set your preferred model ID here (e.g., "global.amazon.nova-2-lite-v1:0")
&lt;/span&gt;    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_MODEL_ID&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a an agent which can read and write files to current directory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Create the agent with tools
&lt;/span&gt;&lt;span class="n"&gt;local_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Define a system Prompt
&lt;/span&gt;    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bedrock_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_write&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# Add your custom tools here
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nf"&gt;local_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;can you create a weather.md file, with the content about current temperature in kolkata India right now?, if not able find weather put reason of it&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your first lab :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run labs/01-your-first-agent/agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📖 Background
&lt;/h2&gt;

&lt;p&gt;In this lab the agent is asked to create a markdown file with weather information. Because the agent does not have internet access, it must reason about what it &lt;em&gt;can&lt;/em&gt; do (write a file) and what it &lt;em&gt;cannot&lt;/em&gt; do (fetch live data) — a great first lesson in tool-aware reasoning.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔑 Key Concepts
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Agent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The core class that ties together a model, tools, and a system prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;system_prompt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Instructions that shape the agent's personality and capabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BedrockModel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Model provider connecting to Amazon Bedrock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;file_read&lt;/code&gt; / &lt;code&gt;file_write&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Built-in Strands tools for local file operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;load_dotenv()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Loads AWS credentials from a &lt;code&gt;.env&lt;/code&gt; file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Part 2 : &lt;a href="https://dev.to/d3vjamal/lab-02-http-tools-integration-strands-agentic-ai-415p"&gt;HTTP tool integration&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agentic</category>
      <category>ai</category>
      <category>strandsagents</category>
    </item>
  </channel>
</rss>
