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.
- Overview
- Architecture
- Prerequisites
- Quick Start
- Testing the MCP Server
- Sample Tool Invocations
- Customization
- File Structure
- Troubleshooting
- Cleanup
- Pricing
- Next Steps
- Resources
- 🤝 Contributing
- 📄 License
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
| 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 |
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)
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
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)
-
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 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
Copy the example variables file and customize:
cp terraform.tfvars.example terraform.tfvarsEdit terraform.tfvars with your preferred values.
See State Management Options in the main README for detailed guidance on local vs. remote state.
Quick start with local state:
terraform initFor team collaboration, use remote state - see the main README for setup instructions.
terraform planMethod 1: Using Deploy Script (Recommended)
Make the script executable (first-time only):
chmod +x deploy.shThen deploy:
./deploy.shThe deploy script:
- Validates Terraform configuration
- Shows deployment plan
- Prompts for confirmation
- Applies changes
Method 2: Direct Terraform Commands
terraform applyWhen 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
After deployment completes:
terraform outputExample 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"
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.
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 testingOption B: System-wide installation
pip install boto3 mcp # Both required for MCP server testingNote: Both boto3 (for AWS API calls) and mcp (for MCP protocol) are required for testing the MCP server.
First, get a JWT token from Cognito:
# Use the command from terraform outputs
terraform output -raw get_token_command | bashOr 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! $REGIONThis will output a JWT token. Copy the token for the next step.
# 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🔄 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!
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."
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 - bUpdate 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.
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
}Add to terraform.tfvars:
environment_variables = {
LOG_LEVEL = "DEBUG"
CUSTOM_VAR = "value"
}Set network_mode = "PRIVATE" for VPC deployment (requires additional VPC configuration).
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
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
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
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
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
Make the script executable (first-time only):
chmod +x destroy.shThen cleanup:
./destroy.shOr use Terraform directly:
terraform destroyNote: 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
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 10For 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.
- Basic Runtime - Simpler deployment without MCP protocol
- Multi-Agent Runtime - Deploy multiple coordinating agents
- End-to-End Weather Agent - Full-featured agent with tools
- 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
- Terraform AWS Provider Documentation
- AWS Bedrock AgentCore Documentation
- Model Context Protocol (MCP)
- Amazon Cognito Documentation
- AgentCore Samples Repository
We welcome contributions! Please see our Contributing Guide for details.
This project is licensed under the MIT License - see the LICENSE file for details.
