Skip to main content

AWS API Gateway transport adapter for mcpbytes-lambda-core

Project description

mcpbytes-lambda-apigw

Python 3.12+ MCP 2025-06-18 License: Apache 2.0

Production-ready AWS API Gateway transport adapter for Model Context Protocol (MCP) servers. Seamlessly converts between HTTP requests and MCP JSON-RPC with enterprise-grade authentication and CORS handling.

๐Ÿš€ Quick Start

from mcpbytes_lambda.core import MCPServer
from mcpbytes_lambda.apigw import ApiGatewayAdapter

# Create your MCP server with tools
mcp = MCPServer(name="my-server", version="1.0.0")

@mcp.tool(name="example.tool")
def my_tool(message: str) -> str:
    return f"Processed: {message}"

# Zero-boilerplate Lambda handler
def lambda_handler(event, context):
    adapter = ApiGatewayAdapter()
    return adapter.handle(event, mcp)  # That's it!

โœจ Features

  • ๐Ÿ”’ Smart Authentication - Auto-detects Lambda Authorizers, supports custom token validation
  • ๐ŸŒ CORS Compliance - Full preflight handling with configurable origins
  • ๐Ÿ“ก MCP Streamable HTTP - Compliant with MCP 2025-06-18 transport specification
  • โšก High Performance - Optimized for AWS Lambda cold starts and execution
  • ๐Ÿ›ก๏ธ Input Validation - JSON-RPC 2.0 validation with detailed error responses
  • ๐Ÿ“Š Production Logging - Structured logging for debugging and monitoring
  • ๐Ÿ”„ Base64 Support - Automatic handling of API Gateway base64 encoding

๐Ÿ” Authentication

The API Gateway adapter provides flexible authentication with smart auto-detection:

Authentication Flow

  1. Lambda Authorizer Detection: Auto-detects and uses existing Lambda Authorizer context
  2. Token Format Validation: Validates Bearer token format when auth is required
  3. Custom Validation: Executes custom token validation logic (if provided)
  4. User Context Access: Provides unified access to authentication context

Usage Patterns

Lambda Authorizer (Auto-detected)

def lambda_handler(event, context):
    adapter = ApiGatewayAdapter(require_auth=True)
    user_info = adapter.get_user_context(event)  # From Lambda Authorizer
    return adapter.handle(event, mcp_server)

Custom Token Validation

import jwt
from typing import Dict, Any, Union

def validate_jwt_token(token: str) -> Union[Dict[str, Any], bool]:
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        return {"user_id": payload["sub"], "role": payload["role"]}
    except jwt.InvalidTokenError:
        return False

def lambda_handler(event, context):
    adapter = ApiGatewayAdapter(require_auth=True, token_validator=validate_jwt_token)
    user_info = adapter.get_user_context(event)  # From custom validator
    return adapter.handle(event, mcp_server)

โš™๏ธ Configuration

adapter = ApiGatewayAdapter(
    cors_origin="https://myapp.com",           # CORS origin header
    require_auth=True,                         # Enable authentication
    auth_header="Authorization",               # Auth header name  
    token_validator=my_custom_validator        # Custom validation function
)

Parameters:

  • cors_origin: CORS origin header value (default: "*")
  • require_auth: Whether to require Bearer token authentication (default: False)
  • auth_header: Header name for authentication token (default: "Authorization")
  • token_validator: Optional custom token validation function
    • Should return Dict[str, Any] for user context on success
    • Should return False for explicit rejection
    • Should return True for acceptance without context
    • May raise exceptions for validation errors

๐Ÿ“‹ Requirements

  • Python 3.12+
  • mcpbytes-lambda-core package
  • AWS API Gateway Lambda Proxy Integration
  • Bearer token authentication (via Lambda Authorizer or custom validation)

๐Ÿ—๏ธ Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   API Gateway   โ”‚โ”€โ”€โ”€โ–ถโ”‚  APIGW Adapter  โ”‚โ”€โ”€โ”€โ–ถโ”‚   MCP Core      โ”‚
โ”‚   HTTP Request  โ”‚    โ”‚  (Transport)    โ”‚    โ”‚   JSON-RPC      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                       โ”‚                       โ”‚
         โ”‚                       โ–ผ                       โ”‚
         โ”‚              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”‚
         โ”‚              โ”‚  Authentication โ”‚              โ”‚
         โ”‚              โ”‚  CORS Handling  โ”‚              โ”‚
         โ”‚              โ”‚  Error Mapping  โ”‚              โ”‚
         โ”‚              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜              โ”‚
         โ”‚                                                โ”‚
         โ–ผ                                                โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   HTTP Response โ”‚โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚   Tool Results  โ”‚
โ”‚   (200/500)     โ”‚                              โ”‚   JSON-RPC      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ› ๏ธ Usage Examples

Basic Lambda Handler

def lambda_handler(event, context):
    adapter = ApiGatewayAdapter()
    return adapter.handle(event, mcp)

Lambda Authorizer Integration

def lambda_handler(event, context):
    adapter = ApiGatewayAdapter(require_auth=True)
    
    # Access user context from Lambda Authorizer
    user_info = adapter.get_user_context(event)
    if user_info:
        print(f"User: {user_info.get('principalId')}")
    
    return adapter.handle(event, mcp)

JWT Token Validation

import jwt
import os
from typing import Dict, Any, Union
from mcpbytes_lambda.core.exceptions import AuthenticationError

def validate_jwt(token: str) -> Union[Dict[str, Any], bool]:
    try:
        payload = jwt.decode(token, os.environ["JWT_SECRET"], algorithms=["HS256"])
        return {
            "user_id": payload["sub"],
            "email": payload["email"],
            "role": payload.get("role", "user")
        }
    except jwt.ExpiredSignatureError:
        raise AuthenticationError("Token has expired")
    except jwt.InvalidTokenError:
        return False

def lambda_handler(event, context):
    adapter = ApiGatewayAdapter(
        require_auth=True,
        token_validator=validate_jwt
    )
    
    user_context = adapter.get_user_context(event)
    return adapter.handle(event, mcp)

Multi-Server Routing

# Route to different MCP servers based on path
def lambda_handler(event, context):
    path = event.get("path", "")
    
    if path.startswith("/math"):
        server = math_mcp_server
    elif path.startswith("/weather"):
        server = weather_mcp_server
    else:
        server = default_mcp_server
    
    adapter = ApiGatewayAdapter(require_auth=True)
    return adapter.handle(event, server)

๐Ÿ“ก MCP Protocol Compliance

Streamable HTTP Transport (2025-06-18)

โœ… HTTP POST for JSON-RPC requests/notifications/responses
โœ… HTTP GET for optional Server-Sent Events (SSE) streams
โœ… Proper status codes: 200 OK, 202 Accepted, 4xx/5xx errors
โœ… MCP-Protocol-Version header support
โœ… Bearer token authentication (RFC 6750)
โœ… Session management with Mcp-Session-Id
โœ… CORS preflight handling
โœ… Content negotiation (application/json + text/event-stream)

Lambda Limitations

โŒ Server-Sent Events (SSE) streaming not supported
โŒ Real-time server-to-client notifications not supported
โŒ HTTP GET for stream initiation not supported
โŒ Stream resumability not supported

For full streaming support, deploy as a long-running server process.

Required Headers

Client must send:

POST /your-endpoint HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream #BOTH headers
Authorization: Bearer <token> #if needed/enabled
MCP-Protocol-Version: 2025-06-18 / multiple supported

Server responds with:

HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: https://example.com

JSON-RPC Format

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "example.tool",
    "arguments": {"message": "Hello MCP!"}
  },
  "id": "request-1"
}

๐Ÿ” Error Handling

HTTP Status Codes

  • 200 OK - CORS preflight successful, JSON-RPC requests processed
  • 400 Bad Request - Malformed requests, unsupported protocol versions
  • 401 Unauthorized - Missing or invalid Bearer token
  • 403 Forbidden - Origin not allowed (CORS violation)
  • 406 Not Acceptable - Accept header doesn't include required content types
  • 415 Unsupported Media Type - Content-Type is not application/json
  • 500 Internal Server Error - JSON-RPC error or server failure

JSON-RPC Error Codes

# Standard JSON-RPC 2.0 error codes
-32700  # Parse error (invalid JSON)
-32600  # Invalid request (missing method, bad headers)
-32601  # Method not found  
-32602  # Invalid params
-32603  # Internal error

๐Ÿ›ก๏ธ Security Best Practices

Authentication Strategies

  1. Lambda Authorizer (Recommended for production)

    • Centralized authentication logic
    • Automatic caching and performance optimization
    • Built-in AWS integration
  2. Custom Token Validation

    • Flexible validation logic
    • Support for JWT, API keys, custom tokens
    • Direct integration with your auth system

Environment Variables

# Production CORS configuration
ALLOWED_ORIGINS="https://example.com,https://app.example.com"

# JWT Secret for token validation
JWT_SECRET="your-secret-key"

# Development (allows all origins - not recommended for production)
# ALLOWED_ORIGINS=""  # Empty = allow all

API Gateway Setup

# SAM Template example
Resources:
  McpApi:
    Type: AWS::Serverless::Api
    Properties:
      Cors:
        AllowMethods: "'POST,OPTIONS'"
        AllowHeaders: "'Content-Type,Authorization,MCP-Protocol-Version'"
        AllowOrigin: "'*'"  # Override with adapter's origin validation
      Auth:
        DefaultAuthorizer: TokenAuth
        Authorizers:
          TokenAuth:
            FunctionArn: !GetAtt AuthFunction.Arn

๐Ÿš€ Deployment

SAM Template

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  McpFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: .
      Handler: handler.lambda_handler
      Runtime: python3.12
      Environment:
        Variables:
          ALLOWED_ORIGINS: "https://myapp.com,https://admin.myapp.com"
          JWT_SECRET: !Ref JWTSecret
      Events:
        McpApi:
          Type: Api
          Properties:
            Path: /mcp
            Method: any

CDK Deployment

from aws_cdk import aws_lambda as lambda_
from aws_cdk import aws_apigateway as apigw

lambda_function = lambda_.Function(
    self, "McpFunction",
    runtime=lambda_.Runtime.PYTHON_3_12,
    handler="handler.lambda_handler",
    code=lambda_.Code.from_directory("src/"),
    environment={
        "ALLOWED_ORIGINS": "https://myapp.com",
        "JWT_SECRET": jwt_secret.secret_value_from_json("secret").to_string()
    }
)

api = apigw.RestApi(self, "McpApi")
api.root.add_proxy(default_integration=apigw.LambdaIntegration(lambda_function))

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Make your changes and add tests
  4. Run tests: python -m pytest
  5. Submit a pull request

๐Ÿ“„ License

Apache 2.0 License - see LICENSE for details.

๐Ÿ”— Related Packages

๐Ÿ“š Documentation


Built with โค๏ธ for the MCP ecosystem

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcpbytes_lambda_apigw-0.1.0.tar.gz (10.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcpbytes_lambda_apigw-0.1.0-py3-none-any.whl (11.7 kB view details)

Uploaded Python 3

File details

Details for the file mcpbytes_lambda_apigw-0.1.0.tar.gz.

File metadata

  • Download URL: mcpbytes_lambda_apigw-0.1.0.tar.gz
  • Upload date:
  • Size: 10.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mcpbytes_lambda_apigw-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7d7a7ab9b6c8f756932434040bbaf1e48fd4890876860a27b416a4618441b4f1
MD5 9c06147b3df8cbefe0febf49a927ba94
BLAKE2b-256 b1dc24f3010e1cfaab9b2b19351f468eb8d89269fc201ffe25a5dedebe6d7a56

See more details on using hashes here.

File details

Details for the file mcpbytes_lambda_apigw-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for mcpbytes_lambda_apigw-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 90f56a4c555355e5d5a6e833a947482d36d71d50be38d0630e62800373075ea5
MD5 7c4662574dab5d4eb96f12956d2af46d
BLAKE2b-256 f918c24e58daf0561b7e4878f678c5ebc18379a27706d0922c89f41707f10729

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page