Skip to main content
Glama
aayushmittall

Lambda MCP Server

README.md
# Lambda MCP Server Container

A stateless Python MCP server packaged as a custom AWS Lambda container image and exposed through an API Gateway HTTP API. It uses MCP Streamable HTTP at `/mcp`.

## Included tools

- `hello(name)` — returns a greeting
- `add(a, b)` — adds two numbers
- `current_time()` — returns the current UTC time

Add your own functions in `src/server.py` and decorate them with `@mcp.tool()`.

## Prerequisites

- Docker
- AWS CLI authenticated to your AWS account

## Test the Python tools

```powershell
py -3.12 -m venv .venv
.venv\Scripts\Activate.ps1
pip install -r requirements-dev.txt
pytest
```

## Build the Lambda image

Lambda is configured for ARM64 by default in these examples:

```powershell
docker buildx build --platform linux/arm64 --provenance=false -t lambda-mcp-server:latest --load .
```

For an x86_64 Lambda, use `--platform linux/amd64` instead.

## Test the container locally

Start the Lambda runtime emulator included in the AWS base image:

```powershell
docker run --platform linux/arm64 --rm -p 9000:8080 lambda-mcp-server:latest
```

Invoke it from another terminal with an API Gateway HTTP API v2 event:

```powershell
$body = '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
$event = @{
  version = "2.0"
  routeKey = "POST /mcp"
  rawPath = "/mcp"
  rawQueryString = ""
  headers = @{ "content-type" = "application/json"; "accept" = "application/json, text/event-stream" }
  requestContext = @{ http = @{ method = "POST"; path = "/mcp"; protocol = "HTTP/1.1"; sourceIp = "127.0.0.1"; userAgent = "local" }; requestId = "local"; routeKey = "POST /mcp"; stage = '$default'; time = ""; timeEpoch = 0 }
  body = $body
  isBase64Encoded = $false
} | ConvertTo-Json -Depth 10 -Compress
Invoke-RestMethod -Method Post -Uri http://localhost:9000/2015-03-31/functions/function/invocations -ContentType application/json -Body $event
```

## Push to Amazon ECR

Replace the variables with your AWS account details:

```powershell
$Region = "ap-south-1"
$AccountId = aws sts get-caller-identity --query Account --output text
$Repository = "lambda-mcp-server"

aws ecr create-repository --repository-name $Repository --region $Region
aws ecr get-login-password --region $Region | docker login --username AWS --password-stdin "$AccountId.dkr.ecr.$Region.amazonaws.com"
docker tag "lambda-mcp-server:latest" "$AccountId.dkr.ecr.$Region.amazonaws.com/${Repository}:latest"
docker push "$AccountId.dkr.ecr.$Region.amazonaws.com/${Repository}:latest"
```

Create or update a Lambda function using that image URI. Set its architecture to `arm64`, timeout to 30 seconds, and memory to at least 512 MB.

## API Gateway

Create an API Gateway **HTTP API** with Lambda proxy integration. Add an `ANY /mcp` route targeting the Lambda function, then grant API Gateway permission to invoke it. The MCP URL will look like:

```text
https://YOUR_API_ID.execute-api.ap-south-1.amazonaws.com/mcp
```

## Connect through AgentCore Gateway

Keep the Lambda image command as `src.server.handler` and expose the function through the API Gateway `ANY /mcp` route described above.

In Amazon Bedrock AgentCore Gateway, add an **MCP server target** using the full API Gateway endpoint:

```text
https://YOUR_API_ID.execute-api.ap-south-1.amazonaws.com/mcp
```

Use `DEFAULT` listing mode so AgentCore synchronizes the tools exposed by FastMCP. No separate tool-schema JSON is needed because AgentCore discovers the tools through MCP `tools/list`.

For initial testing you can use no outbound authorization. For production, configure IAM authorization on API Gateway and select IAM (SigV4) outbound authorization for the AgentCore target.

## Connect an MCP client

Configure a client that supports Streamable HTTP with the deployed output URL:

```json
{
  "mcpServers": {
    "lambda-tools": {
      "url": "https://YOUR_API_ID.execute-api.ap-south-1.amazonaws.com/mcp"
    }
  }
}
```

## Production note

An unauthenticated API Gateway route is public. Before exposing tools that access private data or perform writes, add authentication at API Gateway (for example JWT/Cognito) and validate authorization in the application. Keep tools stateless, or store shared state in an external service such as DynamoDB.