Guide · AWS Lambda
MCP Server Lambda@Edge — edge routing, auth, and geo-routing for MCP endpoints
Lambda@Edge runs your code at CloudFront edge locations — reducing latency for auth, routing, and request rewriting — but it cannot run full MCP server logic. Three constraints make Lambda@Edge unsuitable as the MCP execution layer: 128 MB memory limit (the MCP SDK, tool handlers, and their dependencies typically exceed 128 MB; Lambda@Edge viewer-facing functions are capped at 128 MB versus the 10 GB available to regional Lambda), no VPC access (Lambda@Edge cannot be placed in a VPC and cannot reach private databases, ElastiCache, or internal services — all the data sources your MCP tools query), and 5-second timeout for viewer-request and viewer-response triggers (tool calls routinely take 5–60 seconds; the edge function would time out before the tool completes). Use Lambda@Edge for the functions it excels at: token validation, geo-routing to the nearest regional origin, and request normalization.
TL;DR
Run the MCP server itself in regional Lambda (with Function URLs) or ECS. Put CloudFront in front for a custom domain. Use Lambda@Edge or CloudFront Functions at the edge for: JWT signature validation (reject bad tokens before they reach your origin), geo-routing (route /mcp requests to the nearest regional Lambda origin), and request rewriting (normalize paths, add headers). Viewer-request triggers have a 5-second timeout; origin-request triggers have 30 seconds and 128 MB — neither is sufficient for running tool calls.
Lambda@Edge vs CloudFront Functions vs regional Lambda
AWS offers three compute layers at CloudFront: CloudFront Functions (sub-millisecond, JavaScript, very limited), Lambda@Edge (milliseconds, Node.js or Python, moderate limits), and regional Lambda (seconds to minutes, all runtimes, full limits). Match the workload to the layer.
| Capability | CloudFront Functions | Lambda@Edge (viewer) | Lambda@Edge (origin) | Regional Lambda |
|---|---|---|---|---|
| Max timeout | 1ms | 5s | 30s | 900s |
| Max memory | 2 MB | 128 MB | 128 MB | 10,240 MB |
| VPC access | No | No | No | Yes |
| Environment variables | No | No (read from event) | No | Yes |
| Async/network calls | No | Yes (within timeout) | Yes (within timeout) | Yes |
| Good for MCP tool execution | No | No | No | Yes |
| Good for MCP auth/routing | Yes (simple checks) | Yes (JWT validation) | Yes (geo-routing) | Not needed here |
Pattern 1: Edge JWT validation with CloudFront Functions
CloudFront Functions run in sub-millisecond at every edge location and can validate JWT structure and signature for simple HMAC-signed tokens. This pattern rejects unauthorized requests before they reach your origin, reducing load and preventing unauthenticated sessions from consuming Lambda concurrency.
// cloudfront-mcp-auth.js — CloudFront Function (viewer-request trigger)
// Validates HMAC-SHA256 signed JWT before forwarding to Lambda origin
// Note: CloudFront Functions do not support crypto.subtle — use a pre-shared key pattern
function handler(event) {
var request = event.request;
var headers = request.headers;
// Only protect MCP endpoint paths
if (!request.uri.startsWith('/mcp')) {
return request; // pass through for other paths
}
var authHeader = headers['authorization'] ? headers['authorization'].value : '';
if (!authHeader.startsWith('Bearer ')) {
return {
statusCode: 401,
statusDescription: 'Unauthorized',
headers: {
'content-type': { value: 'application/json' },
'cache-control': { value: 'no-store' },
},
body: JSON.stringify({ error: 'Missing or invalid Authorization header' }),
};
}
// For full JWT signature validation, use Lambda@Edge (origin-request trigger)
// CloudFront Functions cannot make network calls to fetch JWKS
// This function only validates token format; signature check happens at origin
var token = authHeader.slice(7);
var parts = token.split('.');
if (parts.length !== 3) {
return {
statusCode: 401,
statusDescription: 'Unauthorized',
headers: { 'content-type': { value: 'application/json' } },
body: JSON.stringify({ error: 'Malformed token' }),
};
}
return request; // pass to origin for signature validation
}
For full JWT signature validation at the edge (including JWKS fetch from Cognito), use a Lambda@Edge origin-request trigger (30-second timeout, can make HTTPS calls to fetch the JWKS URI). Cache the JWKS response at the Lambda@Edge execution environment level to avoid fetching on every request.
Pattern 2: Geo-routing to nearest regional MCP origin
If you deploy MCP servers in multiple AWS regions (us-east-1, eu-west-1, ap-southeast-1), a Lambda@Edge origin-request trigger can inspect the client's country/region header and route to the closest regional origin, reducing round-trip latency for MCP tool calls.
// lambda-edge-geo-router.js — Lambda@Edge (origin-request trigger)
// Deployed in us-east-1 (Lambda@Edge functions must be in us-east-1)
// Runs at CloudFront edge location closest to the viewer
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
// CloudFront adds viewer-country header (ISO 3166-1 alpha-2)
const viewerCountry = headers['cloudfront-viewer-country']?.[0]?.value ?? 'US';
// Map viewer country to nearest regional Lambda Function URL
const regionMap = {
// Europe
'GB': 'eu-west-1', 'DE': 'eu-west-1', 'FR': 'eu-west-1',
'NL': 'eu-west-1', 'SE': 'eu-north-1', 'FI': 'eu-north-1',
// Asia Pacific
'JP': 'ap-northeast-1', 'AU': 'ap-southeast-2',
'SG': 'ap-southeast-1', 'IN': 'ap-south-1',
};
const region = regionMap[viewerCountry] ?? 'us-east-1'; // default to US
// Regional Lambda Function URL origins (configured in CloudFront distribution)
const originDomains = {
'us-east-1': 'abc123.lambda-url.us-east-1.on.aws',
'eu-west-1': 'def456.lambda-url.eu-west-1.on.aws',
'ap-southeast-1': 'ghi789.lambda-url.ap-southeast-1.on.aws',
'ap-northeast-1': 'jkl012.lambda-url.ap-northeast-1.on.aws',
};
const targetDomain = originDomains[region] ?? originDomains['us-east-1'];
// Rewrite origin host
request.origin = {
custom: {
domainName: targetDomain,
port: 443,
protocol: 'https',
readTimeout: 60,
keepaliveTimeout: 5,
sslProtocols: ['TLSv1.2'],
customHeaders: {},
}
};
request.headers['host'] = [{ key: 'Host', value: targetDomain }];
return request;
};
Deployment constraint: Lambda@Edge functions must be deployed in us-east-1 regardless of where your origin regions are — CloudFront replicates the function to all edge locations automatically. The CDK code goes in a stack that targets us-east-1.
CDK pattern for Lambda@Edge with CloudFront
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
import * as lambda from "aws-cdk-lib/aws-lambda";
import { EdgeFunction } from "aws-cdk-lib/aws-cloudfront";
// Lambda@Edge must be deployed to us-east-1
// Use a cross-stack reference or EdgeFunction construct
const geoRouter = new cloudfront.experimental.EdgeFunction(this, "GeoRouter", {
runtime: lambda.Runtime.NODEJS_22_X,
handler: "lambda-edge-geo-router.handler",
code: lambda.Code.fromAsset("src/edge"),
// No VPC, no environment variables — Lambda@Edge constraints
});
const distribution = new cloudfront.Distribution(this, "McpDistribution", {
defaultBehavior: {
origin: new origins.HttpOrigin("abc123.lambda-url.us-east-1.on.aws", {
protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY,
readTimeout: Duration.seconds(60),
}),
cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
compress: false, // critical: never compress SSE streams
edgeLambdas: [
{
functionVersion: geoRouter.currentVersion,
eventType: cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
},
],
},
domainNames: ["alivemcp.com"],
certificate: acmCert,
});
Monitoring edge-distributed MCP with AliveMCP
When your MCP endpoint is geo-distributed across regions, standard monitoring from a single location only checks one origin. AliveMCP probes from multiple global locations — each probe independently checks your CloudFront endpoint, which routes to the nearest regional origin. This means a regional Lambda failure (e.g., us-east-1 ECS task crashing) is detected by US probes while EU probes confirm the eu-west-1 origin is healthy — giving you a precise failure scope rather than a binary up/down alert.
Common failure modes
| Symptom | Cause | Fix |
|---|---|---|
Lambda@Edge function fails to deploy — InvalidLambdaFunctionAssociation | Lambda@Edge functions must be in us-east-1; deploying from another region fails | Use cloudfront.experimental.EdgeFunction which always creates in us-east-1, or manually specify the region in the CDK stack |
| SSE stream terminates at 5 seconds from edge | Viewer-request or viewer-response Lambda@Edge trigger has a 5-second timeout; streaming MCP sessions exceed this | Use origin-request trigger (30-second timeout) for any logic near the MCP connection; or move auth to CloudFront Functions (sub-1ms) so no timeout applies |
| Edge function cannot reach Cognito JWKS URI | Lambda@Edge runs outside VPC and makes HTTPS calls; the call succeeds but latency is 50–200ms per cold JWKS fetch | Cache the JWKS JSON in the Lambda@Edge execution environment's module scope (survives warm invocations); refresh only when a kid is not found in the cache |
| Geo-routing sends EU users to US origin despite CloudFront Function | cloudfront-viewer-country header not enabled on the distribution | Enable CloudFrontViewerCountry in the CloudFront origin request policy; the header is only populated when explicitly included in the request policy |
| Environment variables not available in Lambda@Edge function | Lambda@Edge does not support environment variables — a hard platform constraint | Embed configuration as constants in the function code, or fetch from SSM/Secrets Manager at function initialization time (add latency to first invocation) |