Human-in-the-Loop (HITL) for Agentic Workflows
March 17, 2026 · View on GitHub
Sample code accompanying the blog post on implementing Human-in-the-Loop constructs for AI agents in healthcare and life sciences using Strands Agents, Amazon Bedrock AgentCore Runtime, and the Model Context Protocol (MCP).
Overview
Four standalone methods for adding human oversight to sensitive agent tool calls:
| Method | Approach | Approval Model |
|---|---|---|
| 1 — Hook System | Agent framework hook intercepts tool calls before execution | Centralized, blanket policy |
| 2 — Tool Context | Approval logic embedded inside each tool with role-based access | Per-tool, fine-grained |
| 3 — Step Functions | Async workflow sends email to external approver via SNS | Third-party, asynchronous |
| 4 — MCP Elicitation | MCP server uses ctx.elicit() for real-time interactive approval | Protocol-native, real-time |
Prerequisites
- Python 3.11+
- uv package manager
- AWS account with permissions for AgentCore, Lambda, Step Functions, SNS, Cognito
- AgentCore CLI (
agentcore)
Setup
-
Configure AWS credentials
Create a
.envfile in the project root:AWS_PROFILE=your-profile AWS_REGION=us-west-2 NOTIFICATION_EMAIL=approver@example.com -
Install dependencies
uv sync -
Deploy infrastructure (Lambda, Step Functions, SNS, Cognito)
cd infra && bash deploy.shThis deploys a CloudFormation stack (
hitl-stack) with:- A Lambda function simulating a sensitive patient vitals tool
- A Step Functions state machine for external approval workflows (Method 3)
- An SNS topic for email notifications (Method 3)
- A Cognito User Pool for MCP server authentication (Method 4)
Architecture
Methods 1 & 2: Hook System / Tool Context

Method 3: Step Functions

Method 4: MCP Elicitation

Deploying & Testing Each Method
Each method has its own directory with an agent.py (AgentCore entrypoint), deploy.sh, and test.py.
Method 1: Hook System
bash method1_hook/deploy.sh
uv run method1_hook/test.py
Method 2: Tool Context
bash method2_tool_context/deploy.sh
uv run method2_tool_context/test.py
Method 3: Step Functions
bash method3_remote_sfn/deploy.sh
uv run method3_remote_sfn/test.py
When the agent requests a discharge, an email is sent to the configured NOTIFICATION_EMAIL. Use the approval script to approve/deny:
uv run method3_remote_sfn/approve.py
Method 4: MCP Elicitation
Deploy the MCP server first, then the agent:
bash method4_mcp_elicitation/deploy.sh # MCP server
bash method4_mcp_elicitation/agent_deploy.sh # Agent (WebSocket)
uv run method4_mcp_elicitation/test.py
A local-only version (no AgentCore deployment needed) is also available:
uv run method4_mcp_elicitation/main.py
Project Structure
├── images/
│ ├── method1_2.png # Architecture diagram for Methods 1 & 2
│ ├── method3.png # Architecture diagram for Method 3
│ └── method4.png # Architecture diagram for Method 4
├── infra/
│ ├── cloudformation.yaml # Lambda, Step Functions, SNS, Cognito
│ └── deploy.sh
├── method1_hook/
│ ├── agent.py # BeforeToolCallEvent hook
│ ├── deploy.sh
│ └── test.py
├── method2_tool_context/
│ ├── agent.py # tool_context.interrupt() with RBAC
│ ├── deploy.sh
│ └── test.py
├── method3_remote_sfn/
│ ├── agent.py # Step Functions + SNS async approval
│ ├── approve.py # CLI script to approve/deny pending executions
│ ├── deploy.sh
│ └── test.py
├── method4_mcp_elicitation/
│ ├── server.py # MCP server with ctx.elicit()
│ ├── agent.py # WebSocket agent relaying elicitation
│ ├── main.py # Local version (no deployment needed)
│ ├── deploy.sh # MCP server deploy
│ ├── agent_deploy.sh # Agent deploy
│ └── test.py
└── pyproject.toml
Cleanup
To remove deployed agents:
uv run agentcore delete --agent <agent_name>
To remove infrastructure:
aws cloudformation delete-stack --stack-name hitl-stack --region us-west-2