Skip to main content
Glama

Hello MCP Server

by mfang0126
README-FARGATE.md13.9 kB
# Hello MCP Server - Fargate ECS Version (FastMCP) Lightweight MCP server for AWS Fargate ECS deployment using FastMCP with built-in HTTP streaming. ## Overview This is a containerized version of the Hello MCP Server using **FastMCP** - a TypeScript framework that simplifies MCP server development. No Express.js needed! ## Features - ✅ **FastMCP Framework**: Built-in HTTP streaming and SSE support - ✅ **Ultra Simple**: Only ~50 lines of code (vs 210+ with Express) - ✅ **MCP Protocol Compliant**: JSON-RPC 2.0 with streaming - ✅ **Bearer Token Authentication**: Secure API access - ✅ **Stateless Mode**: Perfect for containerized deployments - ✅ **Always On**: No cold starts - ✅ **Minimal Dependencies**: Just fastmcp + zod ## Quick Start ### Local Development ```bash # Install dependencies npm install # Start server npm start # Server runs on http://localhost:3000 ``` ### Testing ```bash # Test local server with MCP Inspector npm run test:local # Test deployed Fargate server with MCP Inspector npm run test:fargate ``` ### Test Endpoints FastMCP requires the `Accept` header for streaming: ```bash # Initialize MCP curl -X POST http://localhost:3000/mcp \ -H "Authorization: Bearer mcp-secret-token-12345" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' # List tools curl -X POST http://localhost:3000/mcp \ -H "Authorization: Bearer mcp-secret-token-12345" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' # Call sayHello tool curl -X POST http://localhost:3000/mcp \ -H "Authorization: Bearer mcp-secret-token-12345" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"sayHello","arguments":{"name":"World"}}}' ``` ## Docker ### Build Image ```bash docker build -t hello-mcp-fargate . ``` ### Run Container ```bash docker run -p 3000:3000 \ -e BEARER_TOKEN=mcp-secret-token-12345 \ hello-mcp-fargate ``` ## FastMCP Benefits ### Before (Express.js - 210 lines) ```typescript import express from 'express'; // ... 200+ lines of boilerplate ``` ### After (FastMCP - 50 lines) ```typescript import { FastMCP } from "fastmcp"; const server = new FastMCP({ name: "hello-mcp-fargate", version: "1.0.0", }); server.addTool({ name: "sayHello", description: "Greet someone by name", parameters: z.object({ name: z.string(), }), execute: async (args) => `Hello, ${args.name}! 👋`, }); server.start({ transportType: "httpStream", httpStream: { port: 3000, stateless: true } }); ``` **Improvements**: - 🎯 75% less code - ✅ Built-in HTTP streaming - ✅ Built-in SSE support - ✅ No Express dependency - ✅ Automatic JSON-RPC handling - ✅ Built-in authentication - ✅ Stateless mode for containers ## AWS Fargate ECS Deployment Tutorial ### Prerequisites - AWS CLI configured with appropriate credentials - Docker installed locally - AWS account with permissions for ECR, ECS, ALB, and IAM ### Step-by-Step Deployment Guide #### 1. Create ECR Repository ```bash # Set your AWS region REGION="ap-southeast-2" # Create ECR repository aws ecr create-repository \ --repository-name hello-mcp-fargate \ --region $REGION ``` #### 2. Build and Push Docker Image **Important**: Build for AMD64 platform (Fargate requirement): ```bash # Get your AWS account ID ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) # Build for AMD64 platform docker buildx build --platform linux/amd64 \ -t ${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/hello-mcp-fargate:latest . \ --load # Login to ECR aws ecr get-login-password --region $REGION | \ docker login --username AWS --password-stdin ${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com # Push image docker push ${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/hello-mcp-fargate:latest ``` #### 3. Create ECS Cluster ```bash aws ecs create-cluster \ --cluster-name hello-mcp-cluster \ --region $REGION ``` #### 4. Create Security Groups ```bash # Get default VPC ID VPC_ID=$(aws ec2 describe-vpcs \ --filters "Name=isDefault,Values=true" \ --query 'Vpcs[0].VpcId' \ --output text \ --region $REGION) # Create ALB security group ALB_SG=$(aws ec2 create-security-group \ --group-name hello-mcp-alb-sg \ --description "Security group for Hello MCP ALB" \ --vpc-id $VPC_ID \ --region $REGION \ --query 'GroupId' \ --output text) # Allow HTTP traffic to ALB aws ec2 authorize-security-group-ingress \ --group-id $ALB_SG \ --protocol tcp \ --port 80 \ --cidr 0.0.0.0/0 \ --region $REGION # Create ECS security group ECS_SG=$(aws ec2 create-security-group \ --group-name hello-mcp-ecs-sg \ --description "Security group for Hello MCP ECS tasks" \ --vpc-id $VPC_ID \ --region $REGION \ --query 'GroupId' \ --output text) # Allow traffic from ALB to ECS on port 3000 aws ec2 authorize-security-group-ingress \ --group-id $ECS_SG \ --protocol tcp \ --port 3000 \ --source-group $ALB_SG \ --region $REGION ``` #### 5. Create Application Load Balancer ```bash # Get default subnets SUBNETS=$(aws ec2 describe-subnets \ --filters "Name=vpc-id,Values=$VPC_ID" \ --query 'Subnets[*].SubnetId' \ --output text \ --region $REGION | tr '\t' ' ') # Create ALB ALB_ARN=$(aws elbv2 create-load-balancer \ --name hello-mcp-alb \ --subnets $SUBNETS \ --security-groups $ALB_SG \ --region $REGION \ --query 'LoadBalancers[0].LoadBalancerArn' \ --output text) # Get ALB DNS name ALB_DNS=$(aws elbv2 describe-load-balancers \ --load-balancer-arns $ALB_ARN \ --query 'LoadBalancers[0].DNSName' \ --output text \ --region $REGION) echo "ALB DNS: http://$ALB_DNS" # Create target group TG_ARN=$(aws elbv2 create-target-group \ --name hello-mcp-tg \ --protocol HTTP \ --port 3000 \ --vpc-id $VPC_ID \ --target-type ip \ --health-check-path /mcp \ --health-check-interval-seconds 30 \ --health-check-timeout-seconds 5 \ --healthy-threshold-count 2 \ --unhealthy-threshold-count 3 \ --matcher HttpCode=200-499 \ --region $REGION \ --query 'TargetGroups[0].TargetGroupArn' \ --output text) # Create listener aws elbv2 create-listener \ --load-balancer-arn $ALB_ARN \ --protocol HTTP \ --port 80 \ --default-actions Type=forward,TargetGroupArn=$TG_ARN \ --region $REGION ``` #### 6. Create IAM Role for ECS Task Execution ```bash # Create trust policy file cat > ecs-trust-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF # Create IAM role aws iam create-role \ --role-name ecsTaskExecutionRole \ --assume-role-policy-document file://ecs-trust-policy.json # Attach managed policy aws iam attach-role-policy \ --role-name ecsTaskExecutionRole \ --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy ``` #### 7. Create CloudWatch Log Group ```bash aws logs create-log-group \ --log-group-name /ecs/hello-mcp \ --region $REGION ``` #### 8. Register Task Definition Update `task-definition.json` with your account ID and region, then: ```bash aws ecs register-task-definition \ --cli-input-json file://task-definition.json \ --region $REGION ``` #### 9. Create ECS Service ```bash # Get subnet IDs for service SUBNET_IDS=$(echo $SUBNETS | tr ' ' ',') # Create service aws ecs create-service \ --cluster hello-mcp-cluster \ --service-name hello-mcp-service \ --task-definition hello-mcp-task \ --desired-count 1 \ --launch-type FARGATE \ --network-configuration "awsvpcConfiguration={subnets=[$SUBNET_IDS],securityGroups=[$ECS_SG],assignPublicIp=ENABLED}" \ --load-balancers "targetGroupArn=$TG_ARN,containerName=hello-mcp-container,containerPort=3000" \ --region $REGION ``` #### 10. Test the Deployment Wait 2-3 minutes for the service to start, then test: **With MCP Inspector** (easiest): ```bash # Update inspector-fargate-config.json with your ALB DNS, then: npm run test:fargate ``` **With curl**: ```bash # Test tools/list curl -X POST "http://$ALB_DNS/mcp" \ -H "Authorization: Bearer mcp-secret-token-12345" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # Test sayHello tool curl -X POST "http://$ALB_DNS/mcp" \ -H "Authorization: Bearer mcp-secret-token-12345" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"sayHello","arguments":{"name":"World"}}}' ``` ### Cleanup To delete all AWS resources and avoid charges: ```bash chmod +x cleanup-aws.sh ./cleanup-aws.sh ``` ## AWS Deployment Options ### Option 1: AWS App Runner (Recommended - Simplest) **Cost**: ~$12/month **Complexity**: Low **Setup Time**: < 10 minutes App Runner is the simplest way to deploy this container: ```bash # Build and push to ECR aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin YOUR_ECR_URL docker tag hello-mcp-fargate:latest YOUR_ECR_URL/hello-mcp-fargate:latest docker push YOUR_ECR_URL/hello-mcp-fargate:latest # Create App Runner service via console or CLI ``` ### Option 2: AWS Fargate ECS **Cost**: ~$26/month **Complexity**: Medium **Setup Time**: ~30 minutes For full ECS deployment with ALB, use CDK (see FARGATE_PLAN.md). ## Environment Variables - `PORT`: Server port (default: 3000) - `BEARER_TOKEN`: Authentication token (default: mcp-secret-token-12345) - `NODE_ENV`: Environment (production/development) ## MCP Protocol ### Supported Methods 1. **initialize**: Server handshake and capability negotiation 2. **tools/list**: List available tools 3. **tools/call**: Execute a tool ### Available Tools - `sayHello`: Greet someone by name - Input: `{ name: string }` - Output: `Hello, {name}! 👋` ## Architecture ``` Internet ↓ Application Load Balancer (ALB) ↓ Target Group ↓ Fargate Task (ECS) ├── Container: FastMCP Server ├── Port: 3000 └── Endpoints: /mcp, /sse ``` ## FastMCP Features ### HTTP Streaming FastMCP provides native HTTP streaming support with SSE fallback: - Primary endpoint: `/mcp` (HTTP streaming) - Fallback endpoint: `/sse` (Server-Sent Events) **📖 For detailed transport usage examples, see [TRANSPORT_GUIDE.md](./TRANSPORT_GUIDE.md)** ### Stateless Mode Perfect for containerized deployments: ```typescript httpStream: { stateless: true, // No session persistence } ``` ### Authentication Built-in authentication support: ```typescript authenticate: async (headers) => { const token = headers.authorization?.replace("Bearer ", ""); if (token !== BEARER_TOKEN) { throw new Error("Invalid token"); } return true; } ``` ## Testing with MCP Inspector ### Local Testing Test the local server (requires `npm start` running): ```bash npm run test:local ``` This opens MCP Inspector connected to `http://localhost:3000/mcp`. ### Fargate Testing Test the deployed Fargate server: ```bash npm run test:fargate ``` This opens MCP Inspector connected to your ALB endpoint. ### Manual Configuration **Local Server** (`inspector-config.json`): ```json { "mcpServers": { "hello-mcp-local": { "url": "http://localhost:3000/mcp", "transport": "http", "headers": { "Authorization": "Bearer mcp-secret-token-12345" } } } } ``` **Fargate Server** (`inspector-fargate-config.json`): ```json { "mcpServers": { "hello-mcp-fargate": { "url": "http://hello-mcp-alb-661567224.ap-southeast-2.elb.amazonaws.com/mcp", "transport": "http", "headers": { "Authorization": "Bearer mcp-secret-token-12345" } } } } ``` ## Comparison: Express vs FastMCP | Feature | Express | FastMCP | |---------|---------|---------| | **Lines of Code** | ~210 | ~50 | | **Dependencies** | 3 | 2 | | **HTTP Streaming** | Manual | ✅ Built-in | | **SSE Support** | Manual | ✅ Built-in | | **JSON-RPC** | Manual | ✅ Built-in | | **Authentication** | Manual | ✅ Built-in | | **Stateless Mode** | Manual | ✅ Built-in | | **MCP Inspector** | ✅ Works | ✅ Works | ## Development ### Project Structure ``` . ├── server.ts # FastMCP server (~50 lines!) ├── Dockerfile # Container definition ├── package.json # Dependencies (fastmcp, zod) └── README-FARGATE.md # This file ``` ### Scripts - `npm start`: Run server with tsx - `npm run build`: Compile TypeScript - `npm run start:prod`: Build and run production server ## Why FastMCP? FastMCP was specifically designed for MCP servers and provides: 1. **Less Boilerplate**: Framework handles all protocol details 2. **Better MCP Support**: Built for MCP protocol from the ground up 3. **Easier Maintenance**: Less code = fewer bugs 4. **Better DX**: Simple, intuitive API 5. **Container-Ready**: Stateless mode perfect for Fargate/K8s ## Security - Bearer token authentication on all MCP endpoints - Environment variable configuration - Stateless mode prevents session-based attacks - No sensitive data in logs ## Monitoring FastMCP provides built-in logging: ``` [FastMCP info] Starting server in stateless mode 🚀 FastMCP Server running on port 3000 📍 MCP endpoint: http://localhost:3000/mcp 📍 SSE endpoint: http://localhost:3000/sse 📍 Stateless mode: enabled ``` ## License MIT

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mfang0126/ts-mcp-fargate-ecs-starter'

If you have feedback or need assistance with the MCP directory API, please join our Discord server