Skip to main content

MCP Lambda Handler

A Python library for building serverless Model Context Protocol (MCP) HTTP servers on AWS Lambda. Register tools and resources using decorators, plug in session storage, and drop the handler into any Lambda function.

Installation

pip install aws-lambda-mcp-server

Quick Start

from awslabs.mcp_lambda_handler import MCPLambdaHandler

mcp = MCPLambdaHandler(name="my-mcp-server", version="1.0.0")

@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b

def lambda_handler(event, context):
    return mcp.handle_request(event, context)

Tools

Type hints become the input schema automatically

from typing import Optional
from awslabs.mcp_lambda_handler import MCPLambdaHandler

mcp = MCPLambdaHandler(name="my-mcp-server")

@mcp.tool()
def search_products(
    query: str,
    max_results: int,
    category: Optional[str],
) -> str:
    """Search the product catalogue.

    Args:
        query: Search keywords
        max_results: Maximum number of results to return
        category: Optional category filter
    """
    # ... your logic here
    return f"Found results for: {query}"

Supported types: str, int, float, bool, List[T], Dict[str, T], Optional[T], and Enum.

Enum parameters

from enum import Enum
from awslabs.mcp_lambda_handler import MCPLambdaHandler

mcp = MCPLambdaHandler(name="my-mcp-server")

class Environment(Enum):
    DEV = "dev"
    STAGING = "staging"
    PROD = "prod"

@mcp.tool()
def deploy(service: str, env: Environment) -> str:
    """Deploy a service to an environment.

    Args:
        service: Name of the service to deploy
        env: Target environment
    """
    return f"Deploying {service} to {env.value}"

Returning images

Return bytes from a tool and the handler automatically base64-encodes them as an image content block. JPEG, PNG, GIF, and WebP are auto-detected.

import boto3
from awslabs.mcp_lambda_handler import MCPLambdaHandler

mcp = MCPLambdaHandler(name="my-mcp-server")

@mcp.tool()
def get_chart(metric: str) -> bytes:
    """Generate a chart for a metric and return it as an image.

    Args:
        metric: The metric name to chart
    """
    s3 = boto3.client("s3")
    obj = s3.get_object(Bucket="my-charts", Key=f"{metric}.png")
    return obj["Body"].read()

Resources

Static resource

from awslabs.mcp_lambda_handler import MCPLambdaHandler
from awslabs.mcp_lambda_handler.types import StaticResource

mcp = MCPLambdaHandler(name="my-mcp-server")

mcp.add_resource(StaticResource(
    uri="config://app/settings",
    name="App Settings",
    content='{"timeout": 30, "retries": 3}',
    description="Application configuration",
    mime_type="application/json",
))

File resource

from awslabs.mcp_lambda_handler import MCPLambdaHandler
from awslabs.mcp_lambda_handler.types import FileResource

mcp = MCPLambdaHandler(name="my-mcp-server")

mcp.add_resource(FileResource(
    uri="docs://openapi",
    path="/var/task/openapi.yaml",
    name="OpenAPI Spec",
    description="API specification",
))

Resource decorator (dynamic content)

import json
import boto3
from awslabs.mcp_lambda_handler import MCPLambdaHandler

mcp = MCPLambdaHandler(name="my-mcp-server")

@mcp.resource(
    uri="data://live-config",
    name="Live Config",
    description="Config fetched from Parameter Store at read time",
    mime_type="application/json",
)
def live_config():
    ssm = boto3.client("ssm")
    value = ssm.get_parameter(Name="/myapp/config")["Parameter"]["Value"]
    return value

Session Management

Stateless (default)

No session store is configured — each request is independent. Session IDs are still issued but nothing is persisted.

from awslabs.mcp_lambda_handler import MCPLambdaHandler

mcp = MCPLambdaHandler(name="my-mcp-server")

DynamoDB sessions

Pass a DynamoDB table name to enable persistent sessions with a 24-hour TTL.

from awslabs.mcp_lambda_handler import MCPLambdaHandler

mcp = MCPLambdaHandler(
    name="my-mcp-server",
    session_store="mcp-sessions",  # DynamoDB table name
)

Or use DynamoDBSessionStore directly:

from awslabs.mcp_lambda_handler import MCPLambdaHandler
from awslabs.mcp_lambda_handler.session import DynamoDBSessionStore

mcp = MCPLambdaHandler(
    name="my-mcp-server",
    session_store=DynamoDBSessionStore(table_name="mcp-sessions"),
)

Reading and writing session data from a tool

from awslabs.mcp_lambda_handler import MCPLambdaHandler

mcp = MCPLambdaHandler(name="my-mcp-server", session_store="mcp-sessions")

@mcp.tool()
def increment_counter() -> str:
    """Increment the per-session counter."""
    session = mcp.get_session()
    count = session.get("count", 0) + 1 if session else 1
    mcp.update_session(lambda s: s.set("count", count))
    return f"Count is now {count}"

@mcp.tool()
def get_counter() -> str:
    """Get the current per-session counter value."""
    session = mcp.get_session()
    count = session.get("count", 0) if session else 0
    return f"Count: {count}"

Custom session backend

Subclass SessionStore to use any storage backend:

from typing import Any, Dict, Optional
from awslabs.mcp_lambda_handler import MCPLambdaHandler
from awslabs.mcp_lambda_handler.session import SessionStore
import uuid

class RedisSessionStore(SessionStore):
    def __init__(self, redis_client):
        self.redis = redis_client

    def create_session(self, session_data: Optional[Dict[str, Any]] = None) -> str:
        session_id = str(uuid.uuid4())
        self.redis.setex(session_id, 86400, json.dumps(session_data or {}))
        return session_id

    def get_session(self, session_id: str) -> Optional[Dict[str, Any]]:
        data = self.redis.get(session_id)
        return json.loads(data) if data else None

    def update_session(self, session_id: str, session_data: Dict[str, Any]) -> bool:
        self.redis.setex(session_id, 86400, json.dumps(session_data))
        return True

    def delete_session(self, session_id: str) -> bool:
        self.redis.delete(session_id)
        return True

mcp = MCPLambdaHandler(
    name="my-mcp-server",
    session_store=RedisSessionStore(redis_client),
)

Example Architecture

A typical deployment looks like:

Client → API Gateway (/mcp)
              │
              ├── Lambda Authorizer  (validates bearer token)
              │
              └── MCP Lambda         (this library)
                        │
                        └── DynamoDB  (optional session store)

The Lambda function receives API Gateway proxy events and returns proxy responses — no extra configuration needed.

Development

git clone https://github.com/awslabs/mcp.git
cd mcp/src/mcp-lambda-handler
pip install -e ".[dev]"
pytest

License

Apache-2.0 — see LICENSE.

Metadata

Release files for lambda-mcp-server 0.1.14

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lambda-mcp-server 0.1.14
File Size Uploaded
lambda_mcp_server-0.1.14.tar.gz 71.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lambda-mcp-server 0.1.14
File Interpreter ABI Platform
lambda_mcp_server-0.1.14-py3-none-any.whl Python 3 none any Details

Total release size: 91.2 kB

Release files / lambda_mcp_server-0.1.14.tar.gz

Download URL lambda_mcp_server-0.1.14.tar.gz
Size 71.7 kB
Tags Source
SHA-256 checksum
How to use checksums
20593d0996a97294c17979eef34f360ca753c2f13ff26cce4a7e8becebbf90d9
BLAKE2b-256 checksum
How to use checksums
b70722d9507ef51534bbb53d1e7c57b5c475fd803af9a9fdb16088cd4033adf2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 1, 2026.

Transparency log

Release files / lambda_mcp_server-0.1.14-py3-none-any.whl

Download URL lambda_mcp_server-0.1.14-py3-none-any.whl
Size 19.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e333e92fcae7b27c05cebe219d6f0de738fe3b7c0e362d74ed10a753edee2a91
BLAKE2b-256 checksum
How to use checksums
5dc89755129e6815d8abca28919153cbed2f9b2b3b6d68fe9093376abbabe554
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.14 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page