Guide · ECS Fargate · Lambda · Service Quotas · Scaling

ECS Fargate and Lambda Quota Management for MCP Servers

MCP servers can be deployed as long-running ECS Fargate services or as serverless Lambda functions behind an HTTP adapter. Both deployment models have distinct quota profiles that constrain horizontal scaling. ECS Fargate deployments run into task count quotas — the number of running Fargate tasks per cluster has a default ceiling of 500, which sounds large until you are running multi-tenant deployments with one task per customer. Lambda-based MCP tool handlers share the account-wide concurrent executions quota across every Lambda function in every service in the account. This guide covers the specific quotas, their monitoring approaches, and the increase request strategies for each deployment model.

TL;DR

For ECS Fargate: monitor running task count with Container Insights (ECS/ContainerInsights RunningTaskCount) and alarm at 80% of the per-cluster Fargate task quota (default 500). For Lambda: monitor AWS/Usage ResourceCount Executions against the concurrent executions quota (default 1,000); use reserved concurrency on critical MCP tool handler functions to protect them from account-wide throttles. For both: use aws service-quotas request-service-quota-increase proactively at 60% utilization rather than waiting for 80% alarms to fire before submitting requests.

ECS Fargate quota breakdown

ECS Fargate has several interlocking quotas. Hitting any one of them causes task scheduling to fail silently — the ECS service reports PROVISIONING state indefinitely without a clear error message in the console.

Quota nameDefaultQuota codeImpact when exhausted
Running Fargate tasks per cluster500L-3794C6DCNo new tasks can be scheduled in the cluster; existing tasks run normally
Running Fargate tasks per region1,000L-DC8A8B7CNo new tasks can be scheduled in any cluster in the region
ECS services per cluster500L-B7F81543Cannot create new ECS services — affects multi-tenant service-per-customer deployments
Fargate Spot target capacity units1,000L-FE37DB9BFargate Spot requests exceeding this fail — affects cost-optimized fleets

Monitoring running task count requires Container Insights. Enable it at the cluster level:

const cluster = new ecs.Cluster(this, 'McpCluster', {
  clusterName: 'alivemcp-prod',
  containerInsights: true,  // enables ECS Container Insights metrics
  vpc,
});

// Container Insights publishes ECS/ContainerInsights RunningTaskCount automatically
// Alarm at 80% of the per-cluster task quota
const fargateTaskAlarm = new cloudwatch.Alarm(this, 'FargateTaskQuotaAlarm', {
  alarmName: 'alivemcp-fargate-task-quota-80pct',
  metric: new cloudwatch.Metric({
    namespace: 'ECS/ContainerInsights',
    metricName: 'RunningTaskCount',
    dimensionsMap: { ClusterName: 'alivemcp-prod' },
    period: cdk.Duration.minutes(1),
    statistic: 'Maximum',
  }),
  threshold: 500 * 0.8,  // 80% of default quota (adjust after approved increases)
  evaluationPeriods: 3,
  datapointsToAlarm: 2,
  treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});

Diagnosing quota exhaustion in ECS

When ECS Fargate task scheduling fails due to quota exhaustion, the ECS service shows tasks in PROVISIONING state. Use the ECS service event log to find quota error messages:

# Check service events for quota errors
aws ecs describe-services \
  --cluster alivemcp-prod \
  --services alivemcp-mcp-server \
  --query 'services[0].events[:10].{CreatedAt:createdAt,Message:message}'

# Count running tasks to compare against quota
aws ecs list-tasks \
  --cluster alivemcp-prod \
  --desired-status RUNNING | \
  jq '.taskArns | length'

# Get the per-cluster Fargate task quota
aws service-quotas get-service-quota \
  --service-code ecs \
  --quota-code L-3794C6DC \
  --query 'Quota.Value'

Lambda quota breakdown

Lambda quotas affect MCP servers that use Lambda as the tool handler runtime (via HTTP adapter or direct invocation from ECS). The concurrent executions quota is shared across all Lambda functions in the account — a noisy Lambda batch job can exhaust the quota and cause MCP tool call failures even if the MCP-specific Lambdas are well within their expected concurrency.

Quota nameDefaultQuota codeImpact when exhausted
Concurrent executions (account-wide)1,000L-B99A9384TooManyRequestsException on all Lambda invocations in the account
Provisioned concurrency utilizationScales with concurrent executions quotaL-DC2196D0Cannot provision warm Lambda instances beyond this limit
Function storage (ephemeral /tmp)10 GB (default 512 MB per function, adjustable up to 10 GB)L-2ACBD22FTool handlers writing large temp files fail with ENOSPC
Deployment package size (direct upload)50 MB (direct) / 250 MB (S3)N/A (hard limit)Large Lambda bundles must be deployed via S3 not direct upload

Using reserved concurrency to protect MCP tool handlers

Reserved concurrency dedicates a portion of the account-wide concurrency pool exclusively to a specific function. If the account runs other Lambda workloads (data pipelines, webhooks, cron jobs), use reserved concurrency on MCP tool handler functions to prevent account-wide throttles from affecting MCP availability:

const mcpToolHandler = new lambda.Function(this, 'McpToolHandler', {
  runtime: lambda.Runtime.NODEJS_22_X,
  code: lambda.Code.fromAsset('tool-handler'),
  handler: 'index.handler',
  // Reserve 200 out of the account's 1,000 concurrent executions
  // Other Lambda functions in the account share the remaining 800
  reservedConcurrentExecutions: 200,
  memorySize: 512,
  timeout: cdk.Duration.seconds(30),
});

// Monitor reserved concurrency utilization separately
const reservedConcurrencyAlarm = new cloudwatch.Alarm(this, 'ReservedConcurrencyAlarm', {
  alarmName: 'alivemcp-mcp-handler-reserved-concurrency-80pct',
  metric: new cloudwatch.Metric({
    namespace: 'AWS/Lambda',
    metricName: 'ConcurrentExecutions',
    dimensionsMap: { FunctionName: mcpToolHandler.functionName },
    period: cdk.Duration.minutes(1),
    statistic: 'Maximum',
  }),
  threshold: 200 * 0.8,  // 80% of reserved pool
  evaluationPeriods: 3,
  datapointsToAlarm: 2,
  treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});

Reserved concurrency has a cost: a function with reservedConcurrentExecutions: 200 can never scale beyond 200 concurrent executions regardless of the account quota. If the MCP server experiences a burst that requires more than 200 concurrent handlers, calls will be throttled. Set the reserved value at 80–90% of the expected peak, and monitor for throttles on the reserved function separately to know when to increase the reservation.

Provisioned concurrency for cold-start-sensitive MCP handlers

MCP protocol establishes a session before the first tool call. If the Lambda handler has a cold start of several seconds, the session establishment adds perceptible latency. Provisioned concurrency pre-warms Lambda instances to eliminate cold starts:

const handlerVersion = mcpToolHandler.currentVersion;

const provisionedConfig = new lambda.ProvisionedConcurrencyConfig(this, 'McpHandlerProvisionedConcurrency', {
  target: handlerVersion,
  provisionedConcurrentExecutions: 10,  // keep 10 warm instances at all times
});

// Provisioned concurrency alarm — alert if more than 80% of provisioned instances are in use
// (remaining 20% available for burst before cold starts begin)
const provisionedUtilizationAlarm = new cloudwatch.Alarm(this, 'ProvisionedConcurrencyAlarm', {
  alarmName: 'alivemcp-provisioned-concurrency-utilization-80pct',
  metric: new cloudwatch.Metric({
    namespace: 'AWS/Lambda',
    metricName: 'ProvisionedConcurrencyUtilization',
    dimensionsMap: { FunctionName: mcpToolHandler.functionName },
    period: cdk.Duration.minutes(1),
    statistic: 'Maximum',
  }),
  threshold: 80,  // 80% of provisioned pool in use
  evaluationPeriods: 5,
  datapointsToAlarm: 3,
  treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});

Quota increase request timing

The optimal time to request a quota increase is when usage reaches 60%, not 80%. Quota increase approvals take 1–3 business days for common quotas. If you wait until 80% alarm fires to submit a request and the approval takes 3 days, you may hit 100% and experience service disruption during the approval window. For quotas on critical scaling paths (Lambda concurrent executions, Fargate running tasks per cluster), include the following in your increase request to accelerate approval:

# Request Lambda concurrent executions increase with justification note
aws service-quotas request-service-quota-increase \
  --service-code lambda \
  --quota-code L-B99A9384 \
  --desired-value 3000 \
  # Note: add justification in the resulting Support case
  # Case ID is returned in --query 'RequestedQuota.CaseId'

AWS does not provide a free-text justification field in RequestServiceQuotaIncrease. The API creates a Support case — add the justification text as a reply to that case using the Support console or the aws support add-communication-to-case CLI command.

Common failures

SymptomCauseFix
ECS service shows tasks in PROVISIONING indefinitelyFargate task quota (per-cluster or per-region) exhausted; ECS cannot schedule new tasksCheck aws ecs describe-services --services SERVICE --query 'services[0].events' for quota error messages; count running tasks and compare to quota; request increase via Service Quotas API
Lambda returns TooManyRequestsException even at low function-level concurrencyAccount-wide concurrent executions quota exhausted by other Lambda functionsUse aws lambda get-account-settings --query ConcurrentExecutions to see account-wide usage; add reserved concurrency to MCP handlers; request quota increase; optionally move noisy Lambdas to a separate AWS account
Provisioned concurrency alarm fires even when usage appears lowMetric is ProvisionedConcurrencyUtilization (percentage), not ProvisionedConcurrencyAllocated (count)Verify that the metric dimensions specify FunctionName not just the function's ARN — Alias dimensions are required if provisioned concurrency is on an alias rather than a version
Container Insights RunningTaskCount not appearing in CloudWatchContainer Insights not enabled on the cluster, or the cluster was created before Container Insights was enabledEnable via aws ecs update-cluster-settings --cluster CLUSTER --settings name=containerInsights,value=enabled; metrics appear within a few minutes of the next ECS task state change