saitharun14/mcp-server-lambda
If you are the rightful owner of mcp-server-lambda and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
A Model Context Protocol (MCP) server built with Java Spring Boot and GraalVM, deployed as an AWS Lambda function with API Gateway.
MCP Server with Spring AI and AWS Cognito
A Model Context Protocol (MCP) server built with Spring AI MCP, Spring Boot, GraalVM, and AWS Cognito OAuth2, deployed on AWS EC2 with Google SSO and Streaming HTTP/SSE support.
Overview
This project implements a production-ready MCP server using the Spring AI MCP Server library (spring-ai-starter-mcp-server-webmvc:1.1.0-M4) that provides tools for AI assistants to interact with through the JSON-RPC 2.0 protocol with Server-Sent Events (SSE) streaming. The server leverages:
- Spring AI MCP - Automatic tool discovery and registration with
@Toolannotations - AWS Cognito - Enterprise-grade OAuth2 authentication
- Google SSO - Seamless user authentication via Google accounts
- Spring Boot 3.3.x - Modern Java framework with production-ready features
- GraalVM - Optional native image compilation for faster startup
- EC2 Deployment - Runs on EC2 with embedded Tomcat for full Spring MVC support
- CloudFormation - Infrastructure as Code for reproducible deployments
Features
- ✅ OAuth2 Authentication - AWS Cognito with Google SSO integration
- ✅ Spring Security - Enterprise-grade security with OAuth2 Client support
- ✅ Streamable HTTP Transport - MCP spec 2025-03-26 (implemented using SSE)
- ✅ Spring AI MCP Server - Official Spring AI MCP library
- ✅ Automatic Tool Discovery - @Tool annotated methods auto-registered
- ✅ Spring Boot 3.3.x - Latest Spring framework with enhanced features
- ✅ EC2 Deployment - Full CloudFormation template with VPC, security groups
- ✅ GraalVM Native Image - Optional native compilation for faster startup
- ✅ Web UI - Thymeleaf template showing user info and authentication status
- ✅ Example Tools - Pre-built tools (add, multiply, echo, calculator, getCurrentTime)
- ✅ Rich Documentation - Tools with markdown descriptions
- ✅ Extensible Architecture - Add tools by defining @Tool methods
Architecture
Streaming HTTP/SSE Architecture (Recommended)
┌─────────────┐
│ Client │
│ (Claude) │
└─────┬───────┘
│ HTTPS + SSE Streaming
│
┌─────▼──────────────┐
│ Lambda Function │
│ URL (Streaming) │
└─────┬──────────────┘
│
┌─────▼──────────┐
│ Lambda │
│ Function │
│ ┌──────────┐ │
│ │ Spring │ │
│ │ AI MCP │ │
│ │ Server │ │
│ │ (SSE) │ │
│ └──────────┘ │
└────────────────┘
Note: This architecture has been replaced with EC2 deployment (see below).
Current Architecture: EC2 with OAuth2 and Streamable HTTP
┌──────────────┐
│ User │
│ (Browser) │
└──────┬───────┘
│ 1. Login with Google
│
┌──────▼────────────────┐
│ AWS Cognito │
│ User Pool │
│ ┌─────────────────┐ │
│ │ Google Identity │ │
│ │ Provider │ │
│ └─────────────────┘ │
└──────┬────────────────┘
│ 2. OAuth2 Tokens
│
┌──────▼────────────────────────┐
│ EC2 Instance │
│ ┌─────────────────────────┐ │
│ │ Spring Boot App │ │
│ │ ┌───────────────────┐ │ │
│ │ │ Spring Security │ │ │
│ │ │ OAuth2 Client │ │ │
│ │ └────────┬──────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼──────────┐ │ │
│ │ │ Spring AI MCP │ │ │
│ │ │ Server │ │ │
│ │ │ (Streamable HTTP) │ │ │
│ │ │ /mcp/messages │ │ │
│ │ └────────┬──────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼──────────┐ │ │
│ │ │ @Tool Services │ │ │
│ │ │ (Auto-discovered) │ │ │
│ │ └───────────────────┘ │ │
│ └─────────────────────────┘ │
└────────────────────────────────┘
┌──────────────┐
│ AI Client │
│ (Claude) │
└──────┬───────┘
│ 3. MCP Requests via Streamable HTTP
│ (JSON-RPC over SSE)
│
└──────► /mcp/messages (Streamable HTTP endpoint)
Key Components
-
AWS Cognito User Pool
- Manages user authentication
- Integrates Google as identity provider
- Issues OAuth2 tokens (ID token, access token, refresh token)
-
Spring Security OAuth2
- Validates OAuth2 tokens
- Manages user sessions
- Protects MCP endpoints
-
Spring AI MCP Server
- Auto-configured via
spring-ai-starter-mcp-server-webmvc - Handles JSON-RPC 2.0 protocol
- Uses Streamable HTTP transport (implemented via SSE)
- Endpoint:
/mcp/messagesfor Streamable HTTP - Automatically discovers
@Toolannotated methods
- Auto-configured via
-
EC2 Instance
- Runs embedded Tomcat server
- Deployed via CloudFormation
- Configured with security groups and IAM roles
Transport Protocol
This server uses Streamable HTTP transport (MCP spec 2025-03-26):
- Protocol: Streamable HTTP (the MCP transport mode)
- Implementation: Server-Sent Events (SSE) technology
- Endpoint:
/mcp/messages - Benefits: Real-time streaming, better for long-running operations
- Support: Full Spring MVC with servlet container
Prerequisites
- Java 21 or higher
- Gradle 8.x or higher
- AWS CLI configured with appropriate credentials
- EC2 Key Pair for SSH access
- Google Cloud account for OAuth2 credentials (Client ID and Secret)
- GraalVM (optional, for native image compilation)
- jq (optional, for testing scripts)
Project Structure
mcp-server-lambda/
├── src/
│ ├── main/
│ │ ├── java/com/example/mcp/
│ │ │ ├── service/tools/ # MCP tool definitions (@Tool methods)
│ │ │ │ ├── BasicMcpTools.java
│ │ │ │ └── AdvancedMcpTools.java
│ │ │ ├── controller/ # Spring MVC controllers
│ │ │ │ └── AuthController.java
│ │ │ ├── config/ # Spring configuration
│ │ │ │ └── SecurityConfig.java
│ │ │ └── McpServerApplication.java
│ │ └── resources/
│ │ ├── templates/ # Thymeleaf templates
│ │ │ └── index.html
│ │ ├── META-INF/native-image/ # GraalVM configs
│ │ └── application.yml # Application config with OAuth2
│ └── test/
│ └── java/com/example/mcp/
│ └── McpToolsTest.java
├── build.gradle # Gradle build with Spring AI MCP and OAuth2
├── cloudformation-ec2.yaml # CloudFormation template for EC2
├── deploy-ec2.sh # EC2 deployment script
├── build-and-deploy-app.sh # Build and deploy application
├── QUICKSTART.md # Quick start guide
└── README.md
Available Tools
The server comes with several example tools:
-
add - Adds two numbers
- Parameters:
a(number),b(number) - Returns: Result of a + b
- Parameters:
-
multiply - Multiplies two numbers
- Parameters:
a(number),b(number) - Returns: Result of a × b
- Parameters:
-
echo - Echoes back a message
- Parameters:
message(string) - Returns: "Echo: {message}"
- Parameters:
-
calculator - Performs arithmetic operations
- Parameters:
operation(add/subtract/multiply/divide),a(number),b(number) - Returns: Result of the operation
- Parameters:
-
get_current_time - Returns current time in timezone
- Parameters:
timezone(string, default: "UTC") - Returns: Current time in the specified timezone
- Parameters:
Quick Start
For a quick 10-minute setup, see .
Building
Standard JAR Build
# Build the project
./gradlew clean build
This creates a Spring Boot executable JAR at: build/libs/mcp-server-lambda-1.0.0.jar
GraalVM Native Image Build
For faster startup times (optional):
# Install GraalVM first
# Then run native build
./gradlew nativeCompile
This creates a native executable at: build/native/nativeCompile/mcp-server
Deployment
Step 1: Set Up Google OAuth Credentials
- Go to Google Cloud Console
- Create an OAuth 2.0 Client ID
- Note down the Client ID and Client Secret
- You'll update redirect URIs after deployment
Step 2: Create EC2 Key Pair (if needed)
aws ec2 create-key-pair --key-name mcp-server-key \
--query 'KeyMaterial' --output text > mcp-server-key.pem
chmod 400 mcp-server-key.pem
Step 3: Deploy Infrastructure
Set environment variables:
export GOOGLE_CLIENT_ID="your-google-client-id"
export GOOGLE_CLIENT_SECRET="your-google-client-secret"
export KEY_PAIR_NAME="mcp-server-key"
Deploy the CloudFormation stack:
./deploy-ec2.sh dev us-east-1
This will create:
- VPC with public subnet
- EC2 instance with Java 21
- Security groups for HTTP/HTTPS
- AWS Cognito User Pool with Google identity provider
- OAuth2 configuration
Step 4: Update Google OAuth Redirect URIs
After deployment, add these redirect URIs in Google Cloud Console:
http://[EC2_PUBLIC_DNS]:8080/login/oauth2/code/cognito
http://[EC2_PUBLIC_IP]:8080/login/oauth2/code/cognito
Step 5: Build and Deploy Application
./build-and-deploy-app.sh dev us-east-1
This will:
- Build the Spring Boot JAR
- Retrieve Cognito Client Secret
- Upload JAR to EC2
- Configure systemd service
- Start the application
Testing
Access the Web UI
Open your browser and navigate to:
http://[EC2_PUBLIC_DNS]:8080
Click "Login with Google via Cognito" to authenticate.
Test Health Endpoint
curl http://[EC2_PUBLIC_IP]:8080/actuator/health
Manual Testing Examples
Replace [EC2_PUBLIC_IP] with your EC2 instance's public IP address.
Initialize the MCP server:
curl -X POST http://[EC2_PUBLIC_IP]:8080/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {}
}'
List available tools:
curl -X POST http://[EC2_PUBLIC_IP]:8080/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
Call the addition tool:
curl -X POST http://[EC2_PUBLIC_IP]:8080/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "add",
"arguments": {
"a": 10,
"b": 5
}
}
}'
View Application Logs
SSH into EC2 and view logs:
ssh -i mcp-server-key.pem ec2-user@[EC2_PUBLIC_IP]
sudo journalctl -u mcp-server -f
Creating Custom Tools
With Spring AI MCP, adding a new tool is as simple as creating a method annotated with @Tool. The method is automatically discovered and registered as an MCP tool.
Example: Creating a Custom Tool
package com.example.mcp.service.tools;
import org.springframework.ai.mcp.server.Tool;
import org.springframework.ai.mcp.server.ToolParam;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class MyCustomTools {
@Tool(name = "toUppercase", description = """
Converts the provided text to uppercase.
**Use Cases:**
- Format text for headers or titles
- Normalize text case
- Text processing operations
**Returns:**
A map containing:
- text: The original text
- uppercased: The text converted to uppercase
""")
public Map<String, Object> toUppercase(
@ToolParam(description = "The text to convert to uppercase") String text) {
String uppercased = text.toUpperCase();
return Map.of(
"text", text,
"uppercased", uppercased
);
}
@Tool(name = "reverseString", description = """
Reverses the provided text string.
**Use Cases:**
- String manipulation demos
- Text processing operations
- Palindrome checking
**Returns:**
A map containing:
- original: The original text
- reversed: The text reversed
""")
public Map<String, Object> reverseString(
@ToolParam(description = "The text to reverse") String text) {
String reversed = new StringBuilder(text).reverse().toString();
return Map.of(
"original", text,
"reversed", reversed
);
}
}
Key Points:
- Use
@Serviceto make the class a Spring component - Use
@Toolannotation on methods to define MCP toolsname: The tool name (how it's called via MCP)description: Detailed description with use cases and return format (supports markdown)
- Use
@ToolParamto describe each parameter - Return
Map<String, Object>with structured results - Spring AI automatically discovers and registers
@Toolmethods as MCP tools - Support rich descriptions with markdown formatting
The tools will be automatically registered and available via the MCP protocol with no additional configuration needed!
Configuration
Environment Variables
The application is configured via environment variables set in the systemd service:
SERVER_PORT- Application port (default: 8080)COGNITO_CLIENT_ID- AWS Cognito User Pool Client IDCOGNITO_CLIENT_SECRET- AWS Cognito User Pool Client SecretCOGNITO_ISSUER_URI- Cognito issuer URI (e.g.,https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXX)COGNITO_USER_POOL_ID- AWS Cognito User Pool IDCOGNITO_DOMAIN- Cognito domain for authenticationAWS_REGION- AWS region (e.g., us-east-1)
Application Configuration (application.yml)
Key configuration sections:
spring:
security:
oauth2:
client:
registration:
cognito:
client-id: ${COGNITO_CLIENT_ID}
client-secret: ${COGNITO_CLIENT_SECRET}
scope: [openid, profile, email]
ai:
mcp:
server:
protocol: STREAMABLE # MCP spec 2025-03-26
type: ASYNC # For streaming
sse:
endpoint: "/mcp/messages"
AWS EC2 Configuration
- Instance Type: t3.small (or configurable via CloudFormation parameter)
- Runtime: Java 21 (Amazon Corretto)
- Service: systemd service (
mcp-server.service) - Auto-start: Enabled on boot
GraalVM Native Image Settings
Native image configuration files are located in:
src/main/resources/META-INF/native-image/reflect-config.jsonsrc/main/resources/META-INF/native-image/resource-config.jsonsrc/main/resources/META-INF/native-image/native-image.properties
Performance Considerations
Standard JAR on EC2
- Startup time: ~10-15 seconds
- Memory usage: ~300-400MB
- Response time: <100ms
- JAR size: ~80-100MB
GraalVM Native Image on EC2
- Startup time: ~1-2 seconds
- Memory usage: ~100-150MB
- Response time: <50ms
- Binary size: ~40-60MB
GraalVM Native Image (Legacy)
- Cold start: ~500ms-1s
- Warm execution: <50ms
- Package size: ~30-40MB
Troubleshooting
Build Issues
Problem: Gradle build fails
# Clean and rebuild
./gradlew clean build --refresh-dependencies
Problem: Native image compilation fails
# Ensure GraalVM is properly installed
java -version # Should show GraalVM
# Check native-image tool
which native-image
Deployment Issues
Problem: CloudFormation stack creation fails
- Check AWS CloudFormation console for detailed errors
- Verify Google OAuth credentials are correct
- Ensure EC2 key pair exists in the region
Problem: Application won't start on EC2
- SSH into EC2:
ssh -i mcp-server-key.pem ec2-user@[EC2_IP] - Check service status:
sudo systemctl status mcp-server - View logs:
sudo journalctl -u mcp-server -n 100 --no-pager
Problem: OAuth2 login fails
- Verify Google OAuth redirect URIs are configured correctly
- Check Cognito User Pool and Client configuration
- Verify Cognito Client Secret in systemd service file
Problem: Can't connect to EC2
- Verify security group allows inbound traffic on port 8080
- Check EC2 instance is running
- Verify public IP/DNS is correct
Testing Issues
Problem: Connection refused
- Verify EC2 instance is running
- Check application is running:
sshinto EC2 and runsudo systemctl status mcp-server - Verify security group allows inbound traffic
Problem: CORS errors
- Check SecurityConfig.java CORS configuration
- Verify allowed origins are configured correctly
Monitoring and Logs
View Application Logs
SSH into EC2 and view real-time logs:
ssh -i mcp-server-key.pem ec2-user@[EC2_PUBLIC_IP]
sudo journalctl -u mcp-server -f
View last 100 log lines:
sudo journalctl -u mcp-server -n 100 --no-pager
Service Management
Restart application:
ssh -i mcp-server-key.pem ec2-user@[EC2_PUBLIC_IP]
sudo systemctl restart mcp-server
Stop application:
sudo systemctl stop mcp-server
Check service status:
sudo systemctl status mcp-server
CloudWatch (Optional)
Configure CloudWatch agent on EC2 for centralized logging:
- Agent is pre-installed via UserData script
- Configure log groups in CloudWatch console
Cost Estimation
EC2 pricing (approximate for t3.small in us-east-1):
- On-Demand: ~$0.0208/hour = ~$15/month
- Data transfer: First 100GB/month free, then $0.09/GB
- Cognito: Free tier: 50,000 MAUs (Monthly Active Users)
- CloudWatch: Basic monitoring free, detailed monitoring $0.14/instance/month
For typical development usage:
- Monthly cost: ~$15-20 (EC2 instance running 24/7)
- Can reduce costs by stopping instance when not needed
Security Considerations
- OAuth2 Authentication: All endpoints protected by AWS Cognito
- EC2 Security Groups: Configure to allow only necessary traffic
- SSH Access: Limit SSH access to specific IP ranges
- HTTPS: Configure SSL/TLS with AWS Certificate Manager (recommended for production)
- Secrets: Cognito Client Secret managed via systemd environment variables
- IAM Roles: EC2 instance uses least-privilege IAM role
- VPC: Instance deployed in dedicated VPC with public subnet
Contributing
To contribute to this project:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
This project is licensed under the MIT License.
Resources
Documentation
- Model Context Protocol Documentation
- Spring AI MCP Documentation
- Spring Boot Documentation
- Spring Security OAuth2 Client
- GraalVM Native Image
AWS Services
OAuth2 & SSO
Support
For issues and questions:
- Open an issue on GitHub
- Check the Troubleshooting section
- View application logs on EC2:
sudo journalctl -u mcp-server -f - Check AWS CloudFormation console for deployment issues