Hello everyone. I want to create fraud detection MCP server using Amazon Elastic Kubernetes Service (Amazon EKS). Amazon EKS is a fully managed Kubernetes service that build, run and scale Kubernetes applications such as generative AI, agentic AI and physical AI.
In this blog tutorial, I using SageMaker Studio as my online IDE, Amazon ECR to containerize vLLM server and MCP server, Amazon EKS for vLLM service and MCP server load balancer, Amazon VPC for EKS networking and Amazon DynamoDB for transaction data.
REQUIREMENTS :
- AWS account, you can sign up/sign in here
- vLLM image for inference and serving, you can see this link
- Gemma 4 model for open-source LLM, you can see this link
- Terraform AWS provider for Infrastructure as Code, you can see this link
- FastMCP for create MCP server, you can see this link
STEP-BY-STEP :
Open Amazon SageMaker AI like this screenshot then click "Set up for a single user" for create SageMaker Studio.
Wait until SageMaker Studio is ready. After SageMaker Studio is ready, click "Open Studio".
This is what SageMaker Studio looks like. Click JupyterLab logo top left corner then click "Create JupyterLab space".
After space is created, click "Run space" then wait until show "Open JupyterLab" is available and status is Running.
Open SageMaker AI (not SageMaker Studio) console then click your Quick setup domain. Click "User profiles" -> click "default-..." then copy execution role for create SageMaker Endpoint step. For app configuration, click "Enable Docker on this domain" to can pull vLLM image and push to Amazon ECR.
Click "Open JupyterLab" that automatically open a new tab. For this use case, Terraform can automatically create and delete AWS services such as EKS, VPC and DynamoDB with just one line of code. In the Launcher, click Terminal to install Terraform and kubectl, among other things.
Install Terraform with run this shell script.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv bash)"
brew install gcc
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
terraform --version
Install kubectl with run this shell script.
curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.35.3/2026-04-08/bin/linux/amd64/kubectl
chmod +x ./kubectl
mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
kubectl version --client
Search "0.25.0-gpu-py312-cu130-ubuntu22.04-ec2" in image tags of vLLM because vLLM 0.25.0 version already support Gemma 4 and use EC2/EKS version. Pull the vLLM image and push it to Amazon ECR with one shell script. In the terminal, run this shell script.
cd scripts
chmod +x vllm-to-ecr.sh
./vllm-to-ecr.sh
Open and check Amazon ECR private repository "vllm-gemma-4-eks".
This ECR vLLM server image will be used for the next step using Amazon Elastic Kubernetes Service (Auto Mode on EC2) in next blog tutorial.
Open AWS IAM console then click Roles, search your IAM execution role that already copy before and add some policies because SageMaker Studio as a IDE needs to connect to AWS services. But what happens if you don't add some policies? Yes, access to AWS services is denied.
Create MCP server using FastMCP, create app.py file, Dockerfile and requirements.txt file in ONE folder (available on GitHub, "mcp-server" folder) then containerize this MCP server folder using Amazon ECR.
Then create Amazon ECR private repository "mcp-server-gemma-4" with run this shell script.
cd ..
cd mcp-server
aws ecr create-repository \
--repository-name "mcp-server-gemma-4" \
--image-scanning-configuration scanOnPush=false \
--image-tag-mutability MUTABLE \
--region "us-west-2" 2>/dev/null || echo "Repository already exists, skipping creation."
However, when want to build MCP server and push to Amazon ECR private repository, display error like this screenshot.
To fix this error, use SageMaker Docker Build. SageMaker Docker Build is CLI tool for building Docker images in SageMaker Studio using AWS CodeBuild.
Install SageMaker Docker Build with run this shell script.
pip install sagemaker-studio-image-build
After SageMaker Docker Build is installed, run this shell script to build and push to ECR and wait until finished.
sm-docker build . --repository mcp-server-gemma-4:latest
This ECR fraud detection image will be used for next step using Amazon Elastic Kubernetes Service (Auto Mode on EC2) in next blog tutorial.
Then go to AWS Service Quotas to request EC2 G instance quota, then search "Amazon EC2" then click "View quotas".
Write "On-demand G" then click "Request increase at account level".
However, you can view EC2 G6 NVIDIA GPU instance and then look at the vCPU to fill in the number. In my use case, enter "8" in the Increase quota value and click "Request".
In my case, my request was automatically "Case Opened" that means you need explain what you need for this GPU instance. So why must request an EC2 GPU instance quota? If don't request an EC2 GPU instance quota, will receive an error during the EC2 GPU instance creation process such as your EC2 GPU instance are 0 and you need to request a Service Quota.
Then create Terraform files such as main.tf, eks.tf, vpc.tf and dynamodb.tf in ONE folder (available on GitHub, "terraform" folder).
- main.tf for Terraform AWS version, AWS region and Terraform VPC module
- eks.tf for create EKS Auto Mode cluster, IAM role for EKS node and IAM role for EKS cluster.
- vpc.tf for create EKS networking using Terraform VPC module that make simple configuration.
- dynamodb.tf for create DynamoDB table.
main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "6.45.0"
}
}
}
provider "aws" {
region = "us-west-2"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "6.6.0"
}
eks.tf
resource "aws_eks_cluster" "cluster" {
name = "vllm-mcp-server"
role_arn = aws_iam_role.cluster.arn
version = "1.35"
access_config {
authentication_mode = "API"
}
bootstrap_self_managed_addons = false
compute_config {
enabled = true
node_pools = ["system"]
node_role_arn = aws_iam_role.node.arn
}
kubernetes_network_config {
elastic_load_balancing {
enabled = true
}
}
storage_config {
block_storage {
enabled = true
}
}
vpc_config {
subnet_ids = module.vpc-eks.private_subnets
endpoint_private_access = true
endpoint_public_access = true
}
depends_on = [
aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy,
aws_iam_role_policy_attachment.cluster_AmazonEKSComputePolicy,
aws_iam_role_policy_attachment.cluster_AmazonEKSBlockStoragePolicy,
aws_iam_role_policy_attachment.cluster_AmazonEKSLoadBalancingPolicy,
aws_iam_role_policy_attachment.cluster_AmazonEKSNetworkingPolicy
]
}
resource "aws_iam_role" "node" {
name = "eks-auto-node-iam"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = ["sts:AssumeRole"]
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
},
]
})
}
resource "aws_iam_role_policy_attachment" "node_AmazonEKSWorkerNodeMinimalPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodeMinimalPolicy"
role = aws_iam_role.node.name
}
resource "aws_iam_role_policy_attachment" "node_AmazonEC2ContainerRegistryPullOnly" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly"
role = aws_iam_role.node.name
}
resource "aws_iam_role" "cluster" {
name = "eks-cluster-iam"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"sts:AssumeRole",
"sts:TagSession"
]
Effect = "Allow"
Principal = {
Service = "eks.amazonaws.com"
}
},
]
})
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSComputePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSComputePolicy"
role = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSBlockStoragePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSBlockStoragePolicy"
role = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSLoadBalancingPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSLoadBalancingPolicy"
role = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSNetworkingPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSNetworkingPolicy"
role = aws_iam_role.cluster.name
}
vpc.tf
module "vpc-eks" {
source = "terraform-aws-modules/vpc/aws"
version = "6.6.0"
name = "eks-gemma-vllm-vpc"
cidr = "10.0.0.0/16"
azs = ["us-west-2a", "us-west-2b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_vpn_gateway = false
one_nat_gateway_per_az = false
public_subnet_tags = {
"kubernetes.io/role/elb" = "1"
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = "1"
}
}
dynamodb.tf
resource "aws_dynamodb_table" "transactions_table" {
name = "Transactions"
billing_mode = "PROVISIONED"
read_capacity = 5
write_capacity = 5
hash_key = "userId"
range_key = "transactionId"
attribute {
name = "userId"
type = "S"
}
attribute {
name = "transactionId"
type = "S"
}
attribute {
name = "location"
type = "S"
}
attribute {
name = "timestamp"
type = "S"
}
global_secondary_index {
name = "LocationTimestampIndex"
key_schema {
attribute_name = "location"
key_type = "HASH"
}
key_schema {
attribute_name = "timestamp"
key_type = "RANGE"
}
write_capacity = 5
read_capacity = 5
projection_type = "ALL"
}
}
After 4 Terraform files is available, write and run this Terraform script.
terraform init
terraform init is initialize Terraform latest version in main.tf
terraform plan
terraform plan is check make sure your Terraform file is true and right format. If false and wrong format, you must check your Terraform file again.
terraform apply --auto-approve
terraform apply is apply/create all AWS service resources based all Terraform file. If not write --auto-approve, you must write/enter "yes" every want to apply Terraform file.
Wait until all AWS service that created to become available. The result of this Terraform process are shown in screenshot below.
The name of this EKS cluster is "vllm-mcp-server" that means vLLM server is a Kubernetes service and MCP server is a ingress/load balancer within a single Kubernetes cluster. The Kubernetes version is 1.35
This EKS cluster show EKS Auto Mode is enabled, also IAM role for cluster and node is available. EKS Auto Mode means AWS manage infrastructure such as compute autoscaling, pod and service networking, application load balancing (in EKS without Auto Mode, must install application load balancing using Helm or eksctl), block storage and etc.
This EKS cluster is connected to VPC networking that already created. To view VPC resources such as subnets, security groups and etc, click the VPC name.
NAT gateway is a Network Address Translation (NAT) service. Instance in private subnet can connect to service outside your VPC but external service can not connect with those instance. In this use case, NAT gateway is used to download Gemma 4 model from HuggingFace to Elastic Block Store (EBS) Persistent Volume Claim (PVC) that will be explained in next blog tutorial.
Security group control the traffic is allowed to reach and leave the resources that it is associated with. For example, after you associate a security group with an EC2 instance, it controls the inbound and outbound traffic for the instance. In this use case, this security group is associated with EKS cluster.
Make sure DynamoDB "Transactions" table is available.
Generate data and upload data to DynamoDB "Transactions" table with write this shell script.
cd ..
cd scripts
python generate-data.py
I wrote the second part of the MCP server tutorial blog is Kubernetes manifest, Load Balancer and MCP Client are here.
CONCLUSION :
- SageMaker Studio can be used as a online IDE. If you have a laptop with limited specifications, I recommended this online IDE.
- vLLM can be used for inference and serving on ECR.
- Gemma 4 can running in Kubernetes service.
- Terraform help create automatically EKS, VPC and DynamoDB resources faster and also destroy/delete all resources faster.
- FastMCP help create MCP server for fraud detection.
DOCUMENTATION :
- Amazon Elastic Kubernetes Service (EKS) documentation
- Amazon Virtual Private Cloud (VPC) documentation
- Amazon DynamoDB documentation
- vLLM Gemma 4 documentation
- Gemma 4 model documentation
- Terraform Amazon VPC module documentation
- Terraform Amazon EKS documentation
- Terraform Amazon DynamoDB documentation
- FastMCP documentation is same as above requirements.
GITHUB REPOSITORY :
https://github.com/budionosanai/google-gemma-eks-vllm-dynamodb-fastmcp-fraud-detection
Thank you,
Budi
Top comments (0)