* feat(cdk): reorganize CDK samples into python/ and typescript/ folders - Move existing Python CDK samples to cdk/python/ - Add TypeScript CDK samples folder with knowledge-base-rag-agent - Update cdk/README.md with language comparison table - Update parent README with new paths and TypeScript mention - Add cdk/python/README.md for Python-specific guidance 🤖 Assisted by Amazon Q Developer * docs: add Jerad Engebreth to CONTRIBUTORS.md 🤖 Assisted by Amazon Q Developer * fix(cdk/typescript): document known vulnerabilities and fix npm workspaces build - Add Known Dependency Vulnerabilities section to README documenting upstream issues in aws-amplify (fast-xml-parser, lodash) - Add build/test scripts to Lambda layer package.json to fix npm workspaces build command 🤖 Assisted by Amazon Q Developer * fix(security): add HEALTHCHECK and non-root USER to Dockerfile - Add HEALTHCHECK instruction for container orchestration - Create non-root appuser for security best practices - Addresses CKV_DOCKER_2, CKV_DOCKER_3 security findings * fix(security): address CodeQL findings for insecure randomness and HTML sanitization - Replace Math.random() with crypto.randomBytes() for session ID generation - Use iterative sanitization loop to handle nested/obfuscated HTML tags - Addresses CodeQL insecure randomness and incomplete sanitization findings * fix(security): improve HTML sanitization to address CodeQL findings - Handle closing tags with spaces like </script > - Add data: and vbscript: URL scheme blocking - Use tag-based approach instead of content-matching regex - Add more dangerous tags (form, input, button, etc.) * remove unused import * fix(lint): fix import ordering and remove extra blank lines - Sort imports alphabetically (logging before os) - Remove extra blank line in knowledge_base.py - Consistent import grouping (stdlib, then third-party) * fix(security): use HTML entity encoding instead of regex-based sanitization - Replace regex-based tag stripping with HTML entity encoding - Encode all special characters (&, <, >, ", ', /, `, =) - This approach is CodeQL-compliant and more secure - Regex-based HTML filtering is inherently flawed * fix(lint): add __all__ to fix F401 unused import warnings - Add __all__ exports to infra_utils/__init__.py files - Explicitly declares AgentCoreRole as public API * style: apply ruff formatting to all Python files in 04-infrastructure-as-code - Format 32 Python files with ruff - Includes CDK Python samples, Terraform samples, and TypeScript agent code * refactor: rename project from bedrock-agentcore-template to knowledge-base-rag-agent - Update package.json names for root and infrastructure packages - Update README and docs with new project name and paths - Update CloudWatch, SNS, KMS, and Cognito resource names - Regenerate package-lock.json with new package names * refactor: complete project rename to knowledge-base-rag-agent - Update README title and all documentation headers - Update TypeScript stack descriptions and resource names - Update Python agent module docstrings - Update Dockerfile header comment - Update Lambda function package description - Rename runtime to knowledge_base_rag_agent - Rename memory to knowledge_base_rag_agent_memory - Rename API to Knowledge Base RAG Agent API - Update Secrets Manager secret name * fix: correct Docker references and fix Lambda bundling - Update README and docs to clarify Docker is for AgentCore Runtime container, not Lambda bundling - Add @aws-lambda-powertools/logger dependency for Lambda function - Add esbuild as dev dependency for NodejsFunction bundling - Fix S3 bucket deployment to use single deployment with auto content-type detection - Deploy config.json separately with prune:false to preserve other files --------- Co-authored-by: Jerad Engebreth <awsjerad@amazon.com>
MCP Server on AgentCore Runtime - Terraform
This pattern demonstrates deploying an MCP (Model Context Protocol) server on Amazon Bedrock AgentCore Runtime using Terraform. It creates an MCP server with JWT authentication and three custom tools.
Table of Contents
- Overview
- Architecture
- Prerequisites
- Quick Start
- Testing the MCP Server
- Sample Tool Invocations
- Customization
- File Structure
- Troubleshooting
- Cleanup
- Pricing
- Next Steps
- Resources
- 🤝 Contributing
- 📄 License
Overview
This Terraform configuration creates an MCP server deployment that includes:
- MCP Server: Hosts three custom tools (add_numbers, multiply_numbers, greet_user)
- JWT Authentication: Cognito User Pool for secure access
- AgentCore Runtime: Serverless hosting with MCP protocol support
- ECR Repository: Stores the Docker container image
- CodeBuild Project: Automatically builds the ARM64 Docker image
The stack uses the Amazon Bedrock AgentCore Python SDK to wrap agent functions as an MCP server compatible with Amazon Bedrock AgentCore. When hosting tools, the SDK implements the Stateless Streamable HTTP transport protocol with the MCP-Session-Id header for session isolation.
This makes it ideal for:
- Learning MCP protocol with AgentCore Runtime
- Building secure MCP servers with JWT authentication
- Understanding MCP tool development patterns
- Creating custom tools for AI agents
Tutorial Details
| Information | Details |
|---|---|
| Tutorial type | Hosting Tools |
| Tool type | MCP server |
| Tutorial components | Terraform, AgentCore Runtime, MCP server, Cognito |
| Tutorial vertical | Cross-vertical |
| Example complexity | Intermediate |
| SDK used | Amazon BedrockAgentCore Python SDK and MCP Client |
Architecture
The architecture consists of:
- User/MCP Client: Sends requests to the MCP server with JWT authentication
- Amazon Cognito: Provides JWT-based authentication
- User Pool with pre-created test user (testuser/MyPassword123!)
- User Pool Client for application access
- AWS CodeBuild: Builds the ARM64 Docker container image with the MCP server
- Amazon ECR Repository: Stores the container image
- AgentCore Runtime: Hosts the MCP Server
- MCP Server: Exposes three tools via HTTP transport on port 8000
add_numbers: Adds two numbersmultiply_numbers: Multiplies two numbersgreet_user: Greets a user by name
- Validates JWT tokens from Cognito
- Processes MCP tool invocations
- MCP Server: Exposes three tools via HTTP transport on port 8000
- IAM Roles:
- IAM role for CodeBuild (builds and pushes images)
- IAM role for AgentCore Runtime (runtime permissions)
What's Included
This Terraform configuration creates:
- S3 Bucket: Stores MCP server source code for version-controlled builds
- ECR Repository: Container registry for the MCP server Docker image
- CodeBuild Project: Automated Docker image building and pushing
- Cognito User Pool: JWT authentication with pre-configured test user
- Cognito User Pool Client: Application client for authentication
- IAM Roles: Execution roles for AgentCore, CodeBuild, and Cognito operations
- AgentCore Runtime: Serverless MCP server runtime with JWT validation
MCP Server Code Management
The mcp-server-code/ directory contains your MCP server's source files:
mcp_server.py- MCP server implementation with three toolsDockerfile- Container configurationrequirements.txt- Python dependencies (mcp>=1.10.0, boto3, bedrock-agentcore)
Automatic Change Detection:
- Terraform archives the
mcp-server-code/directory - Uploads to S3 with MD5-based versioning
- CodeBuild pulls from S3 and builds the Docker image
- Any changes to files trigger automatic rebuild (new files, modifications, deletions)
Prerequisites
Required Tools
-
Terraform (>= 1.6)
- Recommended: tfenv for version management
- Or download directly: terraform.io/downloads
Note:
brew install terraformprovides v1.5.7 (deprecated). Use tfenv or direct download for >= 1.6. -
AWS CLI (configured with credentials)
aws configure -
Python 3.11+ (for testing scripts)
python --version # Verify Python 3.11 or later pip install boto3 mcp -
Docker (for local testing, optional)
AWS Account Requirements
- AWS Account with appropriate permissions
- Access to Amazon Bedrock AgentCore service
- Permissions to create:
- ECR repositories
- CodeBuild projects
- Cognito User Pools
- IAM roles and policies
- AgentCore Runtime resources
Quick Start
1. Configure Variables
Copy the example variables file and customize:
cp terraform.tfvars.example terraform.tfvars
Edit terraform.tfvars with your preferred values.
2. Initialize Terraform
See State Management Options in the main README for detailed guidance on local vs. remote state.
Quick start with local state:
terraform init
For team collaboration, use remote state - see the main README for setup instructions.
3. Review the Plan
terraform plan
4. Deploy
Method 1: Using Deploy Script (Recommended)
Make the script executable (first-time only):
chmod +x deploy.sh
Then deploy:
./deploy.sh
The deploy script:
- Validates Terraform configuration
- Shows deployment plan
- Prompts for confirmation
- Applies changes
Method 2: Direct Terraform Commands
terraform apply
When prompted, type yes to confirm the deployment.
Note: The deployment process includes:
- Creating ECR repository
- Building Docker image via CodeBuild
- Creating Cognito User Pool and test user
- Creating AgentCore Runtime with MCP protocol
Total deployment time: ~5-10 minutes
5. Get Outputs
After deployment completes:
terraform output
Example output:
agent_runtime_id = "AGENT1234567890"
agent_runtime_arn = "arn:aws:bedrock-agentcore:us-west-2:123456789012:agent-runtime/AGENT1234567890"
cognito_user_pool_id = "us-west-2_AbCdEfGhI"
cognito_user_pool_client_id = "1234567890abcdefghijklmno"
cognito_discovery_url = "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_AbCdEfGhI/.well-known/openid-configuration"
test_username = "testuser"
get_token_command = "python get_token.py 1234567890abcdefghijklmno testuser MyPassword123! us-west-2"
Authentication Model
This pattern uses Cognito JWT-based authentication:
- JWT Tokens: Cognito User Pool issues JWT tokens for authentication
- Custom JWT Authorizer: Runtime validates JWT tokens against Cognito discovery URL
- Test User: Pre-configured user (testuser/MyPassword123!) for testing
- Token Expiry: JWT tokens expire after 1 hour
- Discovery URL: OpenID Connect discovery endpoint for token validation
Authentication Flow:
- User authenticates with Cognito User Pool
- Cognito issues JWT access token
- Client includes JWT token in MCP request headers
- Runtime validates token using Cognito's OIDC discovery endpoint
- Authorized requests processed by MCP server
Note: This is a backend authentication pattern for MCP tool access. For user-facing applications, integrate with your identity provider or use Cognito hosted UI for end-user authentication.
Testing the MCP Server
Prerequisites for Testing
Before testing, ensure you have the required packages installed:
Option A: Using uv (Recommended)
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv pip install boto3 mcp # Both required for MCP server testing
Option B: System-wide installation
pip install boto3 mcp # Both required for MCP server testing
Note: Both boto3 (for AWS API calls) and mcp (for MCP protocol) are required for testing the MCP server.
Step 1: Get Authentication Token
First, get a JWT token from Cognito:
# Use the command from terraform outputs
terraform output -raw get_token_command | bash
Or manually:
# Get the Client ID
CLIENT_ID=$(terraform output -raw cognito_user_pool_client_id)
REGION=$(terraform output -raw aws_region)
# Get authentication token
python get_token.py $CLIENT_ID testuser MyPassword123! $REGION
This will output a JWT token. Copy the token for the next step.
Step 2: Test the MCP Server
# Get the Runtime ARN
RUNTIME_ARN=$(terraform output -raw agent_runtime_arn)
REGION=$(terraform output -raw aws_region)
# Test the MCP server (replace YOUR_JWT_TOKEN with the token from step 1)
python test_mcp_server.py $RUNTIME_ARN YOUR_JWT_TOKEN $REGION
Expected Output
🔄 Initializing MCP session...
✓ MCP session initialized
🔄 Listing available tools...
📋 Available MCP Tools:
==================================================
🔧 add_numbers: Add two numbers together
🔧 multiply_numbers: Multiply two numbers together
🔧 greet_user: Greet a user by name
🧪 Testing MCP Tools:
==================================================
➕ Testing add_numbers(5, 3)...
Result: 8
✖️ Testing multiply_numbers(4, 7)...
Result: 28
👋 Testing greet_user('Alice')...
Result: Hello, Alice! Nice to meet you.
✅ MCP tool testing completed!
Sample Tool Invocations
Try these MCP tool calls:
-
Add Numbers:
# Tool: add_numbers # Parameters: {"a": 10, "b": 25} # Expected Result: 35 -
Multiply Numbers:
# Tool: multiply_numbers # Parameters: {"a": 6, "b": 7} # Expected Result: 42 -
Greet User:
# Tool: greet_user # Parameters: {"name": "John"} # Expected Result: "Hello, John! Nice to meet you."
Customization
Modify MCP Server Code
Edit files in mcp-server-code/ and deploy:
Adding New Tools:
Edit mcp-server-code/mcp_server.py:
@mcp.tool()
def subtract_numbers(a: int, b: int) -> int:
"""Subtract two numbers"""
return a - b
Update Dependencies:
Edit mcp-server-code/requirements.txt:
mcp>=1.10.0
boto3
bedrock-agentcore
your-new-package>=1.0.0
Changes are automatically detected and trigger rebuild. Run terraform apply to deploy.
Modify Authentication
To change Cognito password policy, edit cognito.tf:
password_policy {
minimum_length = 12
require_uppercase = true
require_lowercase = true
require_numbers = true
require_symbols = true
}
Environment Variables
Add to terraform.tfvars:
environment_variables = {
LOG_LEVEL = "DEBUG"
CUSTOM_VAR = "value"
}
Network Mode
Set network_mode = "PRIVATE" for VPC deployment (requires additional VPC configuration).
File Structure
mcp-server-agentcore-runtime/
├── main.tf # AgentCore runtime with MCP protocol
├── variables.tf # Input variables
├── outputs.tf # Output values (includes Cognito)
├── versions.tf # Provider configuration
├── iam.tf # IAM roles and policies
├── s3.tf # S3 bucket for MCP server source
├── ecr.tf # ECR repository
├── codebuild.tf # Docker build automation
├── cognito.tf # Cognito User Pool & Client
├── buildspec.yml # CodeBuild build specification
├── terraform.tfvars.example # Example configuration
├── backend.tf.example # Remote state example
├── mcp-server-code/ # MCP server source code
│ ├── mcp_server.py # MCP server with 3 tools
│ ├── Dockerfile # Container configuration
│ └── requirements.txt # Python dependencies
├── scripts/ # Build automation scripts
│ └── build-image.sh # CodeBuild trigger & verification
├── get_token.py # Cognito JWT token retrieval
├── test_mcp_server.py # MCP server testing script
├── deploy.sh # Deployment helper script
├── destroy.sh # Cleanup helper script
├── architecture.png # Architecture diagram
├── .gitignore # Git ignore patterns
└── README.md # This file
Troubleshooting
CodeBuild Fails
If the Docker build fails:
-
Check CodeBuild logs:
PROJECT_NAME=$(terraform output -raw codebuild_project_name) aws codebuild batch-get-builds \ --ids $PROJECT_NAME -
Common issues:
- Network connectivity issues
- ECR authentication problems
- Python dependency conflicts in requirements.txt
Runtime Creation Fails
If the runtime creation fails:
-
Verify the Docker image exists:
REPO_NAME=$(terraform output -raw ecr_repository_url | cut -d'/' -f2) aws ecr describe-images --repository-name $REPO_NAME -
Check IAM role permissions
-
Verify Bedrock AgentCore service quotas
-
Ensure MCP protocol is properly configured
Authentication Issues
If JWT authentication fails:
-
Verify Cognito user exists:
USER_POOL_ID=$(terraform output -raw cognito_user_pool_id) aws cognito-idp admin-get-user \ --user-pool-id $USER_POOL_ID \ --username testuser -
Check token expiration (tokens expire after 1 hour)
-
Verify the discovery URL is accessible
-
Ensure allowed_clients matches the client ID
MCP Server Connection Fails
If MCP tool invocations fail:
- Check runtime status in AWS Console
- Review CloudWatch Logs for the runtime
- Verify JWT token is valid and not expired
- Check that MCP protocol is configured correctly
- Ensure the runtime is in ACTIVE state
Cleanup
Destroy All Resources
Make the script executable (first-time only):
chmod +x destroy.sh
Then cleanup:
./destroy.sh
Or use Terraform directly:
terraform destroy
Note: This will delete:
- AgentCore Runtime
- ECR Repository (and all images)
- Cognito User Pool (and all users)
- S3 Bucket (and all source code archives)
- All IAM roles and policies
Verify Cleanup
Confirm all resources are deleted:
# Check AgentCore runtimes
aws bedrock-agentcore list-agent-runtimes
# Check ECR repositories
aws ecr describe-repositories | grep mcp-server
# Check Cognito User Pools
aws cognito-idp list-user-pools --max-results 10
Pricing
For current pricing information, please refer to:
- Amazon Bedrock Pricing
- Amazon ECR Pricing
- AWS CodeBuild Pricing
- Amazon Cognito Pricing
- Amazon S3 Pricing
- Amazon CloudWatch Pricing
- AWS Lambda Pricing
Note: Actual costs depend on your usage patterns, AWS region, and specific services consumed.
Next Steps
Explore More Patterns
- Basic Runtime - Simpler deployment without MCP protocol
- Multi-Agent Runtime - Deploy multiple coordinating agents
- End-to-End Weather Agent - Full-featured agent with tools
Extend This Pattern
- Add more MCP tools to
mcp-server-code/mcp_server.py - Integrate with external APIs
- Add persistent storage (DynamoDB, S3)
- Implement custom authentication logic
- Add monitoring and alerting
- Deploy to VPC for private networking
Learn More About MCP
Resources
- Terraform AWS Provider Documentation
- AWS Bedrock AgentCore Documentation
- Model Context Protocol (MCP)
- Amazon Cognito Documentation
- AgentCore Samples Repository
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
