Guide · AWS Networking · Global Accelerator
AWS Global Accelerator for MCP Server Monitoring
MCP servers using SSE transport expose a long-lived HTTP stream — the connection setup latency (TCP handshake + TLS) happens once per session, but it matters: a client in Tokyo hitting a us-east-1 MCP endpoint waits 150–200 ms before the first SSE event arrives. AWS Global Accelerator routes that connection through the nearest AWS edge POP over the AWS backbone, cutting first-packet latency by 40–60% and eliminating the variable public internet path. Global Accelerator also gives you two permanent static anycast IPs — enterprise firewall teams can allowlist two IPs instead of updating DNS-resolved ALB/NLB addresses. This guide covers GA's architecture relative to NLB and CloudFront, CDK setup, and where AliveMCP uses GA in its probe fleet. For endpoint routing and traffic dials see Global Accelerator Routing for MCP Endpoints; for health checks and failover timing see Global Accelerator Health Checks for MCP Servers; for multi-region active-active deployments see Multi-Region MCP Servers with Global Accelerator.
TL;DR
Use Global Accelerator when your MCP server serves users in multiple geographic regions (latency reduction via AWS backbone), when enterprise clients need two stable IPs for firewall allowlisting, or when you need cross-region failover in under 30 seconds without Route 53 TTL delays. GA is L3/L4 (like NLB) so SSE and WebSocket pass through unchanged. It costs ~$18/month per accelerator plus data-transfer premium — negligible for a commercial MCP product but overkill for a hobby project serving one region.
GA vs CloudFront vs NLB: what to use for MCP
All three AWS services front your MCP server with different tradeoffs. The MCP SSE transport is a long-lived HTTP GET that the server streams events into — this connection cannot be cached and must stay open for minutes to hours. That constraint rules out the typical CDN use case.
| Property | Global Accelerator | CloudFront | NLB (single-region) |
|---|---|---|---|
| OSI layer | L3/L4 (TCP/UDP) | L7 (HTTP/HTTPS) | L4 (TCP/UDP/TLS) |
| Multi-region routing | Yes — anycast routes to nearest edge, AWS backbone to target region | Yes — CDN caches at edges | No — single-region only |
| Caching | None — pure routing | Full CDN cache | None — pure routing |
| SSE/WebSocket | Transparent (TCP pass-through) | SSE not natively supported (30s connection timeout); WebSocket supported | Transparent (TCP pass-through) |
| Static IPs | 2 permanent anycast IPs per accelerator | No — DNS-resolved IPs change | 1 Elastic IP per AZ (not anycast) |
| Cross-region failover | Under 30 seconds (GA rerouts on health failure) | Via origin failover groups (~60s) | No — single region |
| DDoS protection | AWS Shield Standard included; Shield Advanced optional | AWS Shield Standard included | AWS Shield Standard included |
| WAF integration | No L7 WAF at GA; attach WAF to ALB behind GA | Yes — AWS WAF at edge | No |
| Idle timeout | Controlled by target (NLB 350s, ALB configurable) | 30 seconds (fixed) — kills SSE connections | 350 seconds (fixed TCP) |
| Pricing | $0.025/hr per accelerator + data transfer premium | $0.0085/10K requests + data transfer | $0.008/hr per LCU |
The decision rule for MCP: if you need content caching (API responses, documentation, static assets), use CloudFront. If you serve MCP SSE streams from a single region and need static IPs or high TCP throughput, use NLB. If you serve MCP SSE streams from multiple regions or need global anycast routing, use Global Accelerator — typically in front of a regional NLB.
How Global Accelerator works: anycast and the AWS backbone
When you create a Global Accelerator, AWS announces two IP addresses via BGP from every AWS edge POP simultaneously. Because these IPs are advertised from ~100 locations worldwide, a client's TCP SYN packet routes to the nearest AWS POP — not to your origin region. From that POP, AWS carries the packet over its private backbone to your origin (an NLB or ALB in us-east-1, for example). The result: you've eliminated the variable, unpredictable public internet path for the longest leg of the connection.
For MCP servers, the benefit is concentrated at connection establishment. Each new SSE session performs a TCP handshake + TLS negotiation before the first MCP initialize request. For a Tokyo client connecting to us-east-1:
- Without GA: ~170ms round-trip on the public internet (Tokyo → US East), TLS requires 2 RTTs → ~510ms before first SSE byte.
- With GA: ~3ms Tokyo → Tokyo POP (nearest AWS edge), then AWS backbone carries the session → effective TLS handshake from client perspective is 2 × 3ms POP RTT = ~6ms; backbone latency adds ~80ms one-way but TCP handshake is between client and POP. First SSE byte arrives in ~250ms — roughly 50% faster connection setup.
After the SSE connection is established, GA is a transparent TCP proxy — it doesn't buffer or inspect application data, so throughput and latency for event delivery are determined by the backbone + target region, not by GA itself.
GA resource hierarchy
Four objects model a Global Accelerator deployment:
- Accelerator — the top-level resource; has 2 static anycast IPv4 addresses and one optional IPv6 address. Associate a DNS name (e.g.,
xxxx.awsglobalaccelerator.com) with your domain via CNAME or Route 53 alias. - Listener — protocol (TCP or UDP), port range (e.g., 443–443 or 8080–8080), and client affinity policy (NONE or SOURCE_IP). One accelerator can have multiple listeners (different ports).
- Endpoint group — scoped to a single AWS region. Has a traffic dial (0–100%) that you adjust for blue/green deployments or DR. Has health check settings (protocol, interval, threshold). One listener can have one endpoint group per region.
- Endpoint — the actual target: ALB, NLB, EC2 instance, or Elastic IP. Each endpoint has a weight (0–255). Zero weight removes the endpoint from rotation without health-check override.
CDK: Global Accelerator in front of a regional NLB
The CDK L2 construct for Global Accelerator lives in aws-cdk-lib/aws-globalaccelerator (the accelerator, listener, and endpoint group) and aws-cdk-lib/aws-globalaccelerator-endpoints (endpoint type wrappers). Both packages ship with CDK v2 — no additional install needed.
import * as ga from 'aws-cdk-lib/aws-globalaccelerator';
import * as gaEndpoints from 'aws-cdk-lib/aws-globalaccelerator-endpoints';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { CfnOutput, Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
export function createMcpGlobalAccelerator(
scope: Construct,
nlb: elbv2.NetworkLoadBalancer,
region: string,
): ga.Accelerator {
const accelerator = new ga.Accelerator(scope, 'McpAccelerator', {
acceleratorName: 'alivemcp-accelerator',
enabled: true,
});
const listener = accelerator.addListener('McpListener', {
portRanges: [{ fromPort: 443, toPort: 443 }],
protocol: ga.ConnectionProtocol.TCP,
// SOURCE_IP affinity: same client IP hashes to same endpoint per 5-tuple.
// Required for stateful SSE sessions — prevents mid-session re-routing to
// a different NLB (which would drop the TCP connection).
clientAffinity: ga.ClientAffinity.SOURCE_IP,
});
listener.addEndpointGroup('PrimaryGroup', {
region,
// 100% of traffic goes to this group by default.
// To deploy a second region, add another endpoint group at 0% dial,
// test, then ramp up while ramping this one down.
trafficDialPercentage: 100,
// GA health checks NLB directly. Use HTTP type + /health path if your
// NLB listener is HTTP (port 80) to detect application-layer failures,
// not just port reachability.
healthCheckProtocol: ga.HealthCheckProtocol.TCP,
healthCheckInterval: ga.HealthCheckInterval.HEALTH_CHECK_INTERVAL_10,
healthCheckThreshold: 3,
endpoints: [
new gaEndpoints.NetworkLoadBalancerEndpoint(nlb, {
weight: 128,
// Preserve client IP through GA → NLB → ECS.
// Requires NLB preserveClientIp: true AND task SG allows 0.0.0.0/0.
preserveClientIp: true,
}),
],
});
// Export both static anycast IPs for firewall allowlisting.
new CfnOutput(scope, 'AcceleratorIp1', {
value: accelerator.ipv4Addresses[0],
description: 'GA static IP #1 — add to enterprise firewall allowlist',
});
new CfnOutput(scope, 'AcceleratorIp2', {
value: accelerator.ipv4Addresses[1],
description: 'GA static IP #2 — add to enterprise firewall allowlist',
});
return accelerator;
}
After deployment, the accelerator's two IPs appear in CloudFormation outputs and never change — even if you replace the NLB behind it. Enterprise clients allowlist these two IPs once; future infrastructure changes are invisible to their firewall policies.
DNS setup: CNAME vs Route 53 alias
GA assigns a DNS hostname like a1b2c3d4e5f6.awsglobalaccelerator.com. To use your own domain (mcp.yourcompany.com), you have two options:
- CNAME — works with any DNS provider. Add a CNAME from
mcp.yourcompany.comtoa1b2c3d4e5f6.awsglobalaccelerator.com. TTL recommendation: 60–300 seconds. Clients that resolve the CNAME will receive the GA anycast IP. - Route 53 alias — zero-cost DNS queries, no CNAME chasing, works at zone apex (
yourcompany.comnot just subdomains). In CDK:new route53.ARecord({ recordName: 'mcp', target: route53.RecordTarget.fromAlias(new targets.GlobalAcceleratorTarget(accelerator)) }). The alias resolves to the static GA IPs.
If you're using Spaceship or another external DNS provider (as AliveMCP does for alivemcp.com), use CNAME. If your domain is in Route 53, use an alias record — it's free and avoids the CNAME chain.
Pricing breakdown for a commercial MCP product
GA pricing has two components: fixed hourly charge and variable data transfer premium. The premium is the difference between what you'd pay for internet data transfer from your region vs the GA-optimized backbone rate.
| Component | Rate | Monthly estimate (10 GB transferred) |
|---|---|---|
| Accelerator fixed charge | $0.025/hour | $18.00 (730 hours) |
| Data transfer premium (US origin) | $0.015/GB in-region; $0.035/GB inter-region (US→EU) | ~$0.35 (10 GB at mixed rates) |
| Total (one accelerator, 10 GB/mo) | — | ~$18.35/month |
The $18/month fixed charge is the dominant cost for typical MCP servers — SSE streams are low-bandwidth (text events). For a $9/mo Author tier product, GA is a backend cost that makes sense once you're past ~5 paying enterprise Team tier customers ($49/mo each). AliveMCP's probe coordinator uses GA because probe agents in 8 regions need a single stable entry point — the two static IPs make firewall configuration for on-prem probe agents trivial.
How AliveMCP uses Global Accelerator
AliveMCP runs probe agents in 8 AWS regions (us-east-1, us-west-2, eu-west-1, eu-central-1, ap-southeast-1, ap-northeast-1, ap-south-1, sa-east-1). Each agent sends probe results back to the central coordinator in us-east-1. Without GA, probe agents must resolve our coordinator's NLB DNS name — which returns different IPs per region and changes when we replace the NLB.
With GA, probe agents are configured with two static IPs hardcoded in their environment. They connect via TCP to port 8443 (MCP over SSE for probe result delivery). When we replaced our coordinator NLB during a Fargate migration, the GA IPs never changed — probe agents kept delivering results through the maintenance window without reconfiguration.
GA also gives AliveMCP a secondary benefit: the probe coordinator's GA endpoint serves as the return address for MCP servers that want to push status events to AliveMCP rather than be polled. Because GA routes through the AWS backbone, a server in ap-south-1 pushing an event to the coordinator has ~40ms backbone latency vs ~200ms public internet — event delivery is faster and more reliable under congestion.
What Global Accelerator does not do
GA is routing infrastructure, not an application proxy. Common misconceptions:
- GA does not cache responses — every request reaches your origin. Use CloudFront for caching.
- GA does not terminate TLS (in TCP mode) — your NLB or application handles TLS. GA is transparent at L3/L4. (GA does have a TLS listener type in some regions for managed certificates, but the common SSE pattern uses TCP passthrough.)
- GA does not perform L7 WAF inspection — attach AWS WAF to the ALB behind GA if you need per-request rules.
- GA does not hide your origin region's IP — the backbone connection between GA POP and your NLB uses your NLB's real IP. GA hides your IP from clients (they see GA's anycast IPs) but not from the perspective of VPC flow logs or NLB access logs.
- GA does not fix latency inside a region — once the connection is inside AWS, backbone routing is already in play. GA's benefit is eliminating the public internet path from client to nearest POP.
Monitoring Global Accelerator with CloudWatch
GA publishes metrics to CloudWatch under the AWS/GlobalAccelerator namespace, scoped to accelerator + listener + endpoint group + endpoint:
| Metric | What it measures | Alert threshold |
|---|---|---|
| NewFlowCount | New TCP connections per minute through the accelerator | Alert if drops to 0 during expected traffic hours (DNS/routing failure) |
| ProcessedBytesIn / ProcessedBytesOut | Bytes flowing through GA (in both directions) | Alert on sudden >50% drop (possible endpoint failure) |
| HealthyEndpointCount | Endpoints passing GA health checks per endpoint group | Alert when < 1 in any group (full group failure) |
| UnhealthyEndpointCount | Endpoints failing GA health checks | Alert if > 0 (any endpoint unhealthy) |
GA metrics have 1-minute granularity. For connection-level anomaly detection (reconnection storms, connection leaks), combine GA NewFlowCount with NLB ActiveFlowCount — they measure the same connections at different layers and should track together. A spike in GA NewFlowCount without matching NLB spike indicates a routing discrepancy worth investigating.