mcpbytes-lambda-apigw


Namemcpbytes-lambda-apigw JSON
Version 0.1.0 PyPI version JSON
download
home_pageNone
SummaryAWS API Gateway transport adapter for mcpbytes-lambda-core
upload_time2025-09-01 01:42:36
maintainerNone
docs_urlNone
authorNone
requires_python>=3.12
licenseNone
keywords api-gateway aws-lambda cors mcp model-context-protocol serverless transport
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # mcpbytes-lambda-apigw

[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![MCP 2025-06-18](https://img.shields.io/badge/MCP-2025--06--18-green.svg)](https://spec.modelcontextprotocol.io/)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

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

## πŸš€ **Quick Start**

```python
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)
```python
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
```python
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**

```python
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**

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

### **Lambda Authorizer Integration**

```python
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**

```python
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**

```python
# 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:**
```http
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
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: https://example.com
```

### **JSON-RPC Format**

```json
{
  "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**

```python
# 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**

```bash
# 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**

```yaml
# 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**

```yaml
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**

```python
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](../../LICENSE) for details.

## πŸ”— **Related Packages**

- [`mcpbytes-lambda-core`](../core/) - Transport-agnostic MCP server core
- [`mcpbytes-lambda-stdio`](../stdio/) - Stdio transport adapter

## πŸ“š **Documentation**

- [MCP Specification](https://spec.modelcontextprotocol.io/)
- [AWS API Gateway Documentation](https://docs.aws.amazon.com/apigateway/)
- [AWS Lambda Proxy Integration](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html)
- [Project Examples](../../examples/)

---

Built with ❀️ for the MCP ecosystem

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "mcpbytes-lambda-apigw",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "api-gateway, aws-lambda, cors, mcp, model-context-protocol, serverless, transport",
    "author": null,
    "author_email": "\"MCPBytes.com\" <hello@mcpbytes.com>",
    "download_url": "https://files.pythonhosted.org/packages/b1/dc/24f3010e1cfaab9b2b19351f468eb8d89269fc201ffe25a5dedebe6d7a56/mcpbytes_lambda_apigw-0.1.0.tar.gz",
    "platform": null,
    "description": "# mcpbytes-lambda-apigw\n\n[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)\n[![MCP 2025-06-18](https://img.shields.io/badge/MCP-2025--06--18-green.svg)](https://spec.modelcontextprotocol.io/)\n[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\nProduction-ready AWS API Gateway transport adapter for [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers. Seamlessly converts between HTTP requests and MCP JSON-RPC with enterprise-grade authentication and CORS handling.\n\n## \ud83d\ude80 **Quick Start**\n\n```python\nfrom mcpbytes_lambda.core import MCPServer\nfrom mcpbytes_lambda.apigw import ApiGatewayAdapter\n\n# Create your MCP server with tools\nmcp = MCPServer(name=\"my-server\", version=\"1.0.0\")\n\n@mcp.tool(name=\"example.tool\")\ndef my_tool(message: str) -> str:\n    return f\"Processed: {message}\"\n\n# Zero-boilerplate Lambda handler\ndef lambda_handler(event, context):\n    adapter = ApiGatewayAdapter()\n    return adapter.handle(event, mcp)  # That's it!\n```\n\n## \u2728 **Features**\n\n- **\ud83d\udd12 Smart Authentication** - Auto-detects Lambda Authorizers, supports custom token validation\n- **\ud83c\udf10 CORS Compliance** - Full preflight handling with configurable origins\n- **\ud83d\udce1 MCP Streamable HTTP** - Compliant with MCP 2025-06-18 transport specification\n- **\u26a1 High Performance** - Optimized for AWS Lambda cold starts and execution\n- **\ud83d\udee1\ufe0f Input Validation** - JSON-RPC 2.0 validation with detailed error responses\n- **\ud83d\udcca Production Logging** - Structured logging for debugging and monitoring\n- **\ud83d\udd04 Base64 Support** - Automatic handling of API Gateway base64 encoding\n\n## \ud83d\udd10 **Authentication**\n\nThe API Gateway adapter provides flexible authentication with smart auto-detection:\n\n### Authentication Flow\n1. **Lambda Authorizer Detection**: Auto-detects and uses existing Lambda Authorizer context\n2. **Token Format Validation**: Validates Bearer token format when auth is required  \n3. **Custom Validation**: Executes custom token validation logic (if provided)\n4. **User Context Access**: Provides unified access to authentication context\n\n### Usage Patterns\n\n#### Lambda Authorizer (Auto-detected)\n```python\ndef lambda_handler(event, context):\n    adapter = ApiGatewayAdapter(require_auth=True)\n    user_info = adapter.get_user_context(event)  # From Lambda Authorizer\n    return adapter.handle(event, mcp_server)\n```\n\n#### Custom Token Validation\n```python\nimport jwt\nfrom typing import Dict, Any, Union\n\ndef validate_jwt_token(token: str) -> Union[Dict[str, Any], bool]:\n    try:\n        payload = jwt.decode(token, SECRET_KEY, algorithms=[\"HS256\"])\n        return {\"user_id\": payload[\"sub\"], \"role\": payload[\"role\"]}\n    except jwt.InvalidTokenError:\n        return False\n\ndef lambda_handler(event, context):\n    adapter = ApiGatewayAdapter(require_auth=True, token_validator=validate_jwt_token)\n    user_info = adapter.get_user_context(event)  # From custom validator\n    return adapter.handle(event, mcp_server)\n```\n\n## \u2699\ufe0f **Configuration**\n\n```python\nadapter = ApiGatewayAdapter(\n    cors_origin=\"https://myapp.com\",           # CORS origin header\n    require_auth=True,                         # Enable authentication\n    auth_header=\"Authorization\",               # Auth header name  \n    token_validator=my_custom_validator        # Custom validation function\n)\n```\n\n### Parameters:\n- `cors_origin`: CORS origin header value (default: \"*\")\n- `require_auth`: Whether to require Bearer token authentication (default: False)\n- `auth_header`: Header name for authentication token (default: \"Authorization\")\n- `token_validator`: Optional custom token validation function\n  - Should return `Dict[str, Any]` for user context on success\n  - Should return `False` for explicit rejection\n  - Should return `True` for acceptance without context\n  - May raise exceptions for validation errors\n\n## \ud83d\udccb **Requirements**\n\n- Python 3.12+\n- `mcpbytes-lambda-core` package\n- AWS API Gateway Lambda Proxy Integration\n- Bearer token authentication (via Lambda Authorizer or custom validation)\n\n## \ud83c\udfd7\ufe0f **Architecture**\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502   API Gateway   \u2502\u2500\u2500\u2500\u25b6\u2502  APIGW Adapter  \u2502\u2500\u2500\u2500\u25b6\u2502   MCP Core      \u2502\n\u2502   HTTP Request  \u2502    \u2502  (Transport)    \u2502    \u2502   JSON-RPC      \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n         \u2502                       \u2502                       \u2502\n         \u2502                       \u25bc                       \u2502\n         \u2502              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510              \u2502\n         \u2502              \u2502  Authentication \u2502              \u2502\n         \u2502              \u2502  CORS Handling  \u2502              \u2502\n         \u2502              \u2502  Error Mapping  \u2502              \u2502\n         \u2502              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518              \u2502\n         \u2502                                                \u2502\n         \u25bc                                                \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502   HTTP Response \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502   Tool Results  \u2502\n\u2502   (200/500)     \u2502                              \u2502   JSON-RPC      \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n## \ud83d\udee0\ufe0f **Usage Examples**\n\n### **Basic Lambda Handler**\n\n```python\ndef lambda_handler(event, context):\n    adapter = ApiGatewayAdapter()\n    return adapter.handle(event, mcp)\n```\n\n### **Lambda Authorizer Integration**\n\n```python\ndef lambda_handler(event, context):\n    adapter = ApiGatewayAdapter(require_auth=True)\n    \n    # Access user context from Lambda Authorizer\n    user_info = adapter.get_user_context(event)\n    if user_info:\n        print(f\"User: {user_info.get('principalId')}\")\n    \n    return adapter.handle(event, mcp)\n```\n\n### **JWT Token Validation**\n\n```python\nimport jwt\nimport os\nfrom typing import Dict, Any, Union\nfrom mcpbytes_lambda.core.exceptions import AuthenticationError\n\ndef validate_jwt(token: str) -> Union[Dict[str, Any], bool]:\n    try:\n        payload = jwt.decode(token, os.environ[\"JWT_SECRET\"], algorithms=[\"HS256\"])\n        return {\n            \"user_id\": payload[\"sub\"],\n            \"email\": payload[\"email\"],\n            \"role\": payload.get(\"role\", \"user\")\n        }\n    except jwt.ExpiredSignatureError:\n        raise AuthenticationError(\"Token has expired\")\n    except jwt.InvalidTokenError:\n        return False\n\ndef lambda_handler(event, context):\n    adapter = ApiGatewayAdapter(\n        require_auth=True,\n        token_validator=validate_jwt\n    )\n    \n    user_context = adapter.get_user_context(event)\n    return adapter.handle(event, mcp)\n```\n\n### **Multi-Server Routing**\n\n```python\n# Route to different MCP servers based on path\ndef lambda_handler(event, context):\n    path = event.get(\"path\", \"\")\n    \n    if path.startswith(\"/math\"):\n        server = math_mcp_server\n    elif path.startswith(\"/weather\"):\n        server = weather_mcp_server\n    else:\n        server = default_mcp_server\n    \n    adapter = ApiGatewayAdapter(require_auth=True)\n    return adapter.handle(event, server)\n```\n\n## \ud83d\udce1 **MCP Protocol Compliance**\n\n### **Streamable HTTP Transport (2025-06-18)**\n\u2705 HTTP POST for JSON-RPC requests/notifications/responses  \n\u2705 HTTP GET for optional Server-Sent Events (SSE) streams  \n\u2705 Proper status codes: 200 OK, 202 Accepted, 4xx/5xx errors  \n\u2705 MCP-Protocol-Version header support  \n\u2705 Bearer token authentication (RFC 6750)  \n\u2705 Session management with Mcp-Session-Id  \n\u2705 CORS preflight handling  \n\u2705 Content negotiation (application/json + text/event-stream)  \n\n### **Lambda Limitations**\n\u274c Server-Sent Events (SSE) streaming not supported  \n\u274c Real-time server-to-client notifications not supported  \n\u274c HTTP GET for stream initiation not supported  \n\u274c Stream resumability not supported  \n\n*For full streaming support, deploy as a long-running server process.*\n\n### **Required Headers**\n\n**Client must send:**\n```http\nPOST /your-endpoint HTTP/1.1\nContent-Type: application/json\nAccept: application/json, text/event-stream #BOTH headers\nAuthorization: Bearer <token> #if needed/enabled\nMCP-Protocol-Version: 2025-06-18 / multiple supported\n```\n\n**Server responds with:**\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\nAccess-Control-Allow-Origin: https://example.com\n```\n\n### **JSON-RPC Format**\n\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"tools/call\",\n  \"params\": {\n    \"name\": \"example.tool\",\n    \"arguments\": {\"message\": \"Hello MCP!\"}\n  },\n  \"id\": \"request-1\"\n}\n```\n\n## \ud83d\udd0d **Error Handling**\n\n### **HTTP Status Codes**\n\n- **200 OK** - CORS preflight successful, JSON-RPC requests processed\n- **400 Bad Request** - Malformed requests, unsupported protocol versions\n- **401 Unauthorized** - Missing or invalid Bearer token\n- **403 Forbidden** - Origin not allowed (CORS violation)\n- **406 Not Acceptable** - Accept header doesn't include required content types\n- **415 Unsupported Media Type** - Content-Type is not application/json\n- **500 Internal Server Error** - JSON-RPC error or server failure\n\n### **JSON-RPC Error Codes**\n\n```python\n# Standard JSON-RPC 2.0 error codes\n-32700  # Parse error (invalid JSON)\n-32600  # Invalid request (missing method, bad headers)\n-32601  # Method not found  \n-32602  # Invalid params\n-32603  # Internal error\n```\n\n## \ud83d\udee1\ufe0f **Security Best Practices**\n\n### **Authentication Strategies**\n1. **Lambda Authorizer** (Recommended for production)\n   - Centralized authentication logic\n   - Automatic caching and performance optimization\n   - Built-in AWS integration\n\n2. **Custom Token Validation**\n   - Flexible validation logic\n   - Support for JWT, API keys, custom tokens\n   - Direct integration with your auth system\n\n### **Environment Variables**\n\n```bash\n# Production CORS configuration\nALLOWED_ORIGINS=\"https://example.com,https://app.example.com\"\n\n# JWT Secret for token validation\nJWT_SECRET=\"your-secret-key\"\n\n# Development (allows all origins - not recommended for production)\n# ALLOWED_ORIGINS=\"\"  # Empty = allow all\n```\n\n### **API Gateway Setup**\n\n```yaml\n# SAM Template example\nResources:\n  McpApi:\n    Type: AWS::Serverless::Api\n    Properties:\n      Cors:\n        AllowMethods: \"'POST,OPTIONS'\"\n        AllowHeaders: \"'Content-Type,Authorization,MCP-Protocol-Version'\"\n        AllowOrigin: \"'*'\"  # Override with adapter's origin validation\n      Auth:\n        DefaultAuthorizer: TokenAuth\n        Authorizers:\n          TokenAuth:\n            FunctionArn: !GetAtt AuthFunction.Arn\n```\n\n## \ud83d\ude80 **Deployment**\n\n### **SAM Template**\n\n```yaml\nAWSTemplateFormatVersion: '2010-09-09'\nTransform: AWS::Serverless-2016-10-31\n\nResources:\n  McpFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      CodeUri: .\n      Handler: handler.lambda_handler\n      Runtime: python3.12\n      Environment:\n        Variables:\n          ALLOWED_ORIGINS: \"https://myapp.com,https://admin.myapp.com\"\n          JWT_SECRET: !Ref JWTSecret\n      Events:\n        McpApi:\n          Type: Api\n          Properties:\n            Path: /mcp\n            Method: any\n```\n\n### **CDK Deployment**\n\n```python\nfrom aws_cdk import aws_lambda as lambda_\nfrom aws_cdk import aws_apigateway as apigw\n\nlambda_function = lambda_.Function(\n    self, \"McpFunction\",\n    runtime=lambda_.Runtime.PYTHON_3_12,\n    handler=\"handler.lambda_handler\",\n    code=lambda_.Code.from_directory(\"src/\"),\n    environment={\n        \"ALLOWED_ORIGINS\": \"https://myapp.com\",\n        \"JWT_SECRET\": jwt_secret.secret_value_from_json(\"secret\").to_string()\n    }\n)\n\napi = apigw.RestApi(self, \"McpApi\")\napi.root.add_proxy(default_integration=apigw.LambdaIntegration(lambda_function))\n```\n\n## \ud83e\udd1d **Contributing**\n\n1. Fork the repository\n2. Create a feature branch: `git checkout -b feature-name`\n3. Make your changes and add tests\n4. Run tests: `python -m pytest`\n5. Submit a pull request\n\n## \ud83d\udcc4 **License**\n\nApache 2.0 License - see [LICENSE](../../LICENSE) for details.\n\n## \ud83d\udd17 **Related Packages**\n\n- [`mcpbytes-lambda-core`](../core/) - Transport-agnostic MCP server core\n- [`mcpbytes-lambda-stdio`](../stdio/) - Stdio transport adapter\n\n## \ud83d\udcda **Documentation**\n\n- [MCP Specification](https://spec.modelcontextprotocol.io/)\n- [AWS API Gateway Documentation](https://docs.aws.amazon.com/apigateway/)\n- [AWS Lambda Proxy Integration](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html)\n- [Project Examples](../../examples/)\n\n---\n\nBuilt with \u2764\ufe0f for the MCP ecosystem\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "AWS API Gateway transport adapter for mcpbytes-lambda-core",
    "version": "0.1.0",
    "project_urls": {
        "Documentation": "https://github.com/MCPBytes/mcpbytes-lambda#readme",
        "Homepage": "https://mcpbytes.com/",
        "Issues": "https://github.com/MCPBytes/mcpbytes-lambda/issues",
        "Repository": "https://github.com/MCPBytes/mcpbytes-lambda"
    },
    "split_keywords": [
        "api-gateway",
        " aws-lambda",
        " cors",
        " mcp",
        " model-context-protocol",
        " serverless",
        " transport"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f918c24e58daf0561b7e4878f678c5ebc18379a27706d0922c89f41707f10729",
                "md5": "7c4662574dab5d4eb96f12956d2af46d",
                "sha256": "90f56a4c555355e5d5a6e833a947482d36d71d50be38d0630e62800373075ea5"
            },
            "downloads": -1,
            "filename": "mcpbytes_lambda_apigw-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7c4662574dab5d4eb96f12956d2af46d",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 11745,
            "upload_time": "2025-09-01T01:42:35",
            "upload_time_iso_8601": "2025-09-01T01:42:35.382035Z",
            "url": "https://files.pythonhosted.org/packages/f9/18/c24e58daf0561b7e4878f678c5ebc18379a27706d0922c89f41707f10729/mcpbytes_lambda_apigw-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b1dc24f3010e1cfaab9b2b19351f468eb8d89269fc201ffe25a5dedebe6d7a56",
                "md5": "9c06147b3df8cbefe0febf49a927ba94",
                "sha256": "7d7a7ab9b6c8f756932434040bbaf1e48fd4890876860a27b416a4618441b4f1"
            },
            "downloads": -1,
            "filename": "mcpbytes_lambda_apigw-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "9c06147b3df8cbefe0febf49a927ba94",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 10084,
            "upload_time": "2025-09-01T01:42:36",
            "upload_time_iso_8601": "2025-09-01T01:42:36.457592Z",
            "url": "https://files.pythonhosted.org/packages/b1/dc/24f3010e1cfaab9b2b19351f468eb8d89269fc201ffe25a5dedebe6d7a56/mcpbytes_lambda_apigw-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-01 01:42:36",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "MCPBytes",
    "github_project": "mcpbytes-lambda#readme",
    "github_not_found": true,
    "lcname": "mcpbytes-lambda-apigw"
}
        
Elapsed time: 0.43244s