Guide · AWS ECS Fargate
ECS Service Connect for MCP Servers
ECS Service Connect lets containers in the same ECS namespace call each other by a short DNS name without configuring Route 53, Cloud Map APIs, or a service mesh. For MCP server architectures that split responsibilities across services — a tool-dispatch service, a credential-fetch service, a cache-warming service — Service Connect removes the glue code. The proxy sidecar ECS injects into each task handles DNS resolution, connection pooling, retries, and circuit-breaking automatically, and emits per-connection metrics to CloudWatch. Three common mistakes: configuring client-server mode on a service that is only an outbound caller — the extra inbound listener wastes CPU on the sidecar; using the cluster default namespace without creating one first — the service fails to start with a cryptic namespace error; not accounting for the proxy's ephemeral port range — the security group must allow inbound traffic on 32768–65535 between tasks in the same namespace, not just port 80/443.
TL;DR
Create an HTTP Cloud Map namespace and set it as the default for your ECS cluster. Configure services that only make outbound calls in client mode. Configure services that receive inbound calls from other services in client-server mode — they get a short DNS alias (e.g., mcp-auth.production) routed through the proxy. The proxy emits RequestCount, ConnectionErrors, and RequestFailedCount metrics per destination service for free — no instrumentation required.
Creating the Cloud Map namespace
Service Connect requires an HTTP Cloud Map namespace. You create it once per environment and reference it from all services:
# Create the namespace (HTTP, not DNS — Service Connect uses HTTP namespaces)
aws servicediscovery create-http-namespace \
--name production \
--description "MCP server services — production"
# Output: { "OperationId": "gv4g5meo7ndmeh4fqskygvk23d2fijwa-k9302yzd" }
# Wait for it to complete:
aws servicediscovery get-operation --operation-id gv4g5meo7ndmeh4fqskygvk23d2fijwa-k9302yzd
Associate the namespace with your ECS cluster so it becomes the default for all services in that cluster:
aws ecs put-cluster-capacity-providers \
--cluster my-cluster \
--capacity-providers FARGATE FARGATE_SPOT \
--default-capacity-provider-strategy capacityProvider=FARGATE,weight=1 \
--configuration '{
"executeCommandConfiguration": {},
"managedStorageConfiguration": {},
"containerInsights": "enabled"
}'
# Set the default Service Connect namespace on the cluster
aws ecs update-cluster \
--cluster my-cluster \
--service-connect-defaults namespace=production
In CDK:
import * as servicediscovery from 'aws-cdk-lib/aws-servicediscovery';
import * as ecs from 'aws-cdk-lib/aws-ecs';
const namespace = new servicediscovery.HttpNamespace(this, 'Namespace', {
name: 'production',
});
const cluster = new ecs.Cluster(this, 'Cluster', {
vpc,
defaultCloudMapNamespace: { name: 'production', type: servicediscovery.NamespaceType.HTTP },
});
Client mode vs client-server mode
| Mode | What it does | When to use |
|---|---|---|
| Client mode | The proxy sidecar handles outbound connections to other services registered in the namespace. No inbound listener is created. Adds ~5ms per call for DNS resolution and connection pooling. | Services that call other services but do not themselves accept inbound Service Connect traffic (e.g., an MCP server that calls an internal auth service) |
| Client-server mode | The sidecar handles both inbound requests (registered under a DNS alias in the namespace) and outbound calls. Inbound requests arrive at the proxy on a random ephemeral port; the proxy forwards them to the application container on its port. | Services that are called by other services in the namespace (e.g., a credential-fetch service or tool registry that multiple MCP servers query) |
Client mode configuration
aws ecs create-service \
--cluster my-cluster \
--service-name mcp-server-svc \
--task-definition mcp-server:3 \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-abc],securityGroups=[sg-abc],assignPublicIp=DISABLED}" \
--service-connect-configuration '{
"enabled": true,
"namespace": "production"
}'
With client mode, the MCP server container can reach http://mcp-auth.production directly — no DNS configuration needed. Calls are routed through the local proxy sidecar on each task.
Client-server mode configuration
aws ecs create-service \
--cluster my-cluster \
--service-name mcp-auth-svc \
--task-definition mcp-auth:2 \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-abc],securityGroups=[sg-abc],assignPublicIp=DISABLED}" \
--service-connect-configuration '{
"enabled": true,
"namespace": "production",
"services": [{
"portName": "http",
"clientAliases": [{
"port": 80,
"dnsName": "mcp-auth"
}]
}]
}'
The portName must match a port mapping name in the task definition. Add names to port mappings in the task definition:
{
"containerDefinitions": [{
"name": "mcp-auth",
"portMappings": [{
"name": "http",
"containerPort": 3000,
"protocol": "tcp",
"appProtocol": "http"
}]
}]
}
The appProtocol field enables HTTP/2 optimizations in the proxy and is required for the detailed per-request metrics to appear in CloudWatch.
Security group rules for Service Connect
The proxy sidecar listens on an ephemeral port (32768–65535) for inbound connections. Tasks in client mode connect to the proxy on that port. If your tasks are in different security groups, the inbound rule must allow the full ephemeral range:
# Allow Service Connect proxy traffic between tasks
aws ec2 authorize-security-group-ingress \
--group-id sg-mcp-auth \
--protocol tcp \
--port 32768-65535 \
--source-group sg-mcp-server
Within the same security group, self-referential rules cover this automatically. If you separate services into different security groups, the ephemeral port range rule is mandatory — without it, the proxy connection attempt silently times out and calls fail after the connection timeout (default 10s).
Service Connect metrics in CloudWatch
The proxy sidecar automatically emits metrics to CloudWatch under the AWS/ECS/ManagedScaling and custom ECS/ContainerInsights/ServiceConnect namespaces. No instrumentation code required:
| Metric | Unit | What to alarm on |
|---|---|---|
RequestCount |
Count | Traffic baseline; use for per-service capacity planning |
RequestFailedCount |
Count | Alarm > 0 for sustained period — indicates MCP auth or downstream failures |
ConnectionErrors |
Count | Alarm > 0 — indicates the proxy cannot reach the destination service (task not running, wrong port, security group issue) |
NewConnectionCount |
Count | High rate = connection pool not being reused; check for missing keep-alive in HTTP client |
ProcessedBytes |
Bytes | Baseline for data transfer cost between services |
Metrics are dimensioned by DiscoveryName (the service DNS name), ServiceName, and ClusterName — you can build a per-service-to-service connection dashboard without any custom instrumentation.
Common failures
| Symptom | Root cause | Fix |
|---|---|---|
Service fails to start: InvalidParameterException: The specified namespace does not exist |
The namespace in service-connect-configuration was specified before it was fully created, or the namespace type is DNS instead of HTTP |
Wait for the create-http-namespace operation to complete; verify the namespace type is HTTP (not DNS_PRIVATE) |
Calls to mcp-auth.production timeout after 10s |
Security group missing ephemeral port range inbound rule; proxy cannot establish connection to the destination | Add inbound TCP 32768–65535 from the caller's security group to the receiving service's security group |
| Service Connect proxy container repeatedly restarting | Task has insufficient CPU allocated; the proxy sidecar competes for CPU with the application container under load | Increase task CPU; the proxy needs at least 0.25 vCPU reserved on top of application CPU |
| No Service Connect metrics appearing in CloudWatch | appProtocol missing from the port mapping in the task definition; proxy cannot classify the traffic |
Add "appProtocol": "http" or "http2" to the port mapping; redeploy the service |
| Old tasks still in RUNNING state after service update, new tasks not routing inbound requests | Inbound alias re-registration in Cloud Map takes 15–30s after task reaches RUNNING; the ALB registers the task but Service Connect alias hasn't propagated yet | Add a 30s health check grace period to the service; callers should retry on 503 for the propagation window |
Monitor inter-service connectivity for your MCP server cluster
Service Connect failures between MCP components are invisible until a tool call fails. AliveMCP probes each service endpoint every 60 seconds and alerts the moment a component becomes unreachable — before an agent session fails for your users.
Join the waitlist →