Aws Mcp

AWS MCP: How to Use AWS MCP Servers

In the rapidly evolving landscape of AI-assisted cloud operations, the integration of Amazon Web Services (AWS) with the Model Context Protocol (MCP) represents a significant advancement in how AI systems can securely interact with cloud infrastructure. AWS MCP servers establish a standardized bridge between conversational AI models and AWS's extensive suite of services, enabling AI assistants to provision resources, manage configurations, analyze metrics, and execute complex cloud workflows through natural language interfaces. This technical implementation transforms language models from simple text generators into powerful cloud operations agents capable of programmatic interaction with the entire AWS ecosystem while maintaining appropriate authentication, authorization, and audit controls.

Introduction

The Model Context Protocol provides a standardized framework for connecting AI models with external tools and data sources. AWS MCP servers implement this protocol to create a secure, authenticated interface between AI assistants and Amazon Web Services. By leveraging AWS's comprehensive SDKs and APIs, MCP servers enable language models to programmatically access and manipulate cloud resources, analyze operational data, manage services, and execute infrastructure-as-code—all while maintaining robust security controls and proper access management.

https://github.com/modelcontextprotocol/aws-mcp-server (opens in a new tab)

Technical Architecture of AWS MCP

MCP Protocol Foundation

AWS MCP operates within the Model Context Protocol architecture, which defines several key components:

  1. Transport Layer:

    • STDIO (Standard Input/Output): Direct process communication
    • SSE (Server-Sent Events): HTTP-based asynchronous communication
    • WebSocket: Bidirectional real-time communication
  2. Resource Types:

    • Prompts: Templated cloud operation patterns
    • Tools: Executable AWS service operations
    • Resources: Cloud resource metadata and configurations
  3. Serialization Format: JSON for structured data exchange between client and server

AWS MCP Architecture

The AWS MCP server implements a multi-layered architecture optimized for secure cloud operations:

aws-mcp/
├── src/
│   ├── auth/
│   │   ├── credentials.ts        # AWS credentials management
│   │   ├── role-assumption.ts    # IAM role management
│   │   └── policy-validator.ts   # Permission validation
│   ├── services/
│   │   ├── ec2-service.ts        # EC2 operations
│   │   ├── s3-service.ts         # S3 operations
│   │   ├── lambda-service.ts     # Lambda operations
│   │   └── cloudwatch-service.ts # CloudWatch operations
│   ├── tools/
│   │   ├── resource-tools.ts     # Resource management tools
│   │   ├── analytics-tools.ts    # Data analysis tools
│   │   ├── monitoring-tools.ts   # CloudWatch tools
│   │   └── iac-tools.ts          # Infrastructure-as-code tools
│   ├── resources/
│   │   ├── account-info.ts       # Account metadata resources
│   │   └── service-quotas.ts     # Service limits resources
│   └── server.ts                 # MCP server implementation
├── config/
│   └── aws-config.ts             # Configuration schema
└── package.json                  # Dependencies and scripts

The core technical implementation consists of:

  1. Credential Manager: Secure handling of AWS authentication credentials
  2. Service Clients: Type-safe wrappers around AWS SDK clients
  3. Permission Boundary Enforcer: Ensures operations comply with IAM policies
  4. Tool Implementations: Translates MCP commands to AWS API calls
  5. Response Formatters: Transforms complex AWS responses into MCP-friendly formats

Setup and Installation

Prerequisites

To implement AWS MCP, ensure you have:

  1. Node.js 16+ environment
  2. AWS account with appropriate IAM permissions
  3. AWS CLI configured with credentials (optional but recommended)
  4. An MCP-compatible client (e.g., Claude Desktop, Cursor, VS Code)

Authentication Configuration

AWS MCP supports multiple authentication methods:

1. Environment Variables

# Set AWS credentials directly
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_REGION=us-west-2
 
# Optional session token for temporary credentials
export AWS_SESSION_TOKEN=your_session_token

2. Shared Credentials File

The MCP server can use the standard AWS credentials file:

# ~/.aws/credentials
[default]
aws_access_key_id = your_access_key
aws_secret_access_key = your_secret_key
region = us-west-2
 
[project-prod]
aws_access_key_id = production_access_key
aws_secret_access_key = production_secret_key
region = us-east-1

3. IAM Role Assumption (Advanced)

For enhanced security, the server can assume IAM roles:

interface AssumeRoleOptions {
  roleArn: string;
  sessionName: string;
  durationSeconds?: number;
  externalId?: string;
}
 
// Implementation
async function assumeRole(options: AssumeRoleOptions): Promise<Credentials> {
  const sts = new STSClient({ region: process.env.AWS_REGION });
  const command = new AssumeRoleCommand({
    RoleArn: options.roleArn,
    RoleSessionName: options.sessionName,
    DurationSeconds: options.durationSeconds || 3600,
    ExternalId: options.externalId
  });
  
  const response = await sts.send(command);
  
  return {
    accessKeyId: response.Credentials.AccessKeyId,
    secretAccessKey: response.Credentials.SecretAccessKey,
    sessionToken: response.Credentials.SessionToken,
    expiration: response.Credentials.Expiration
  };
}

Installation Methods

Option 1: Using npm

npm install -g aws-mcp

Option 2: Using Smithery

npx -y @smithery/cli install aws-mcp --client claude

Option 3: Manual Installation from Source

git clone https://github.com/modelcontextprotocol/aws-mcp-server
cd aws-mcp-server
npm install
npm run build

Configuration

The AWS MCP server accepts various configuration parameters:

  1. Authentication Configuration:

    • AWS_PROFILE: Named profile from credentials file
    • AWS_REGION: Default AWS region
    • AWS_ROLE_ARN: Optional IAM role to assume
  2. Permission Controls:

    • AWS_ALLOWED_SERVICES: Comma-separated list of allowed AWS services
    • AWS_ALLOWED_REGIONS: Comma-separated list of allowed regions
    • AWS_PERMISSION_BOUNDARY: ARN of IAM permission boundary policy
  3. Operational Settings:

    • AWS_MAX_CONCURRENCY: Maximum concurrent AWS API calls
    • AWS_REQUEST_TIMEOUT: Default timeout for API requests in milliseconds
    • AWS_RETRY_COUNT: Number of retries for failed API calls

Example configuration in aws-config.json:

{
  "authentication": {
    "profile": "default",
    "region": "us-east-1",
    "assumeRole": {
      "roleArn": "arn:aws:iam::123456789012:role/MCP-ExecutionRole",
      "sessionName": "MCP-Session",
      "durationSeconds": 3600
    }
  },
  "permissions": {
    "allowedServices": ["s3", "ec2", "lambda", "cloudwatch"],
    "allowedRegions": ["us-east-1", "us-west-2"],
    "readOnlyMode": false,
    "permissionBoundary": "arn:aws:iam::123456789012:policy/MCP-Boundary"
  },
  "operations": {
    "maxConcurrency": 5,
    "timeout": 30000,
    "retryCount": 3,
    "logLevel": "info"
  }
}

Integration with MCP Clients

Claude Desktop Integration

To integrate with Claude Desktop, edit the configuration file:

  • macOS: ~/Library/Application\ Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%/Claude/claude_desktop_config.json

Add the following configuration:

{
  "mcpServers": {
    "aws": {
      "command": "npx",
      "args": ["-y", "aws-mcp"],
      "env": {
        "AWS_PROFILE": "default",
        "AWS_REGION": "us-east-1",
        "AWS_ALLOWED_SERVICES": "s3,ec2,lambda,cloudwatch"
      }
    }
  }
}

VS Code Integration

For VS Code with GitHub Copilot, add to settings.json:

{
  "github.copilot.chat.mcpServers": [
    {
      "name": "aws",
      "command": "npx",
      "args": ["-y", "aws-mcp"],
      "env": {
        "AWS_PROFILE": "default",
        "AWS_REGION": "us-east-1"
      }
    }
  ]
}

Core Functionality and Technical Usage

Available Tools

The AWS MCP server implements a comprehensive set of tools across major AWS service categories:

1. EC2 Operations

  • aws_ec2_describe_instances: Lists EC2 instances with filters

    interface DescribeInstancesOptions {
      region?: string;
      filters?: Array<{
        name: string;
        values: string[];
      }>;
      instanceIds?: string[];
      maxResults?: number;
      nextToken?: string;
    }
  • aws_ec2_control_instance: Manages instance state

    interface ControlInstanceOptions {
      region?: string;
      instanceId: string;
      action: 'start' | 'stop' | 'reboot' | 'terminate';
      force?: boolean;
    }

2. S3 Operations

  • aws_s3_list_objects: Lists bucket contents

    interface ListObjectsOptions {
      region?: string;
      bucket: string;
      prefix?: string;
      maxKeys?: number;
      delimiter?: string;
      continuationToken?: string;
    }
  • aws_s3_get_object: Retrieves object content

    interface GetObjectOptions {
      region?: string;
      bucket: string;
      key: string;
      versionId?: string;
      responseContentType?: string;
      range?: string;
    }

3. Lambda Operations

  • aws_lambda_invoke: Invokes Lambda function

    interface InvokeLambdaOptions {
      region?: string;
      functionName: string;
      payload?: any;
      invocationType?: 'RequestResponse' | 'Event' | 'DryRun';
      logType?: 'None' | 'Tail';
      qualifier?: string;
    }
  • aws_lambda_list_functions: Lists Lambda functions

    interface ListFunctionsOptions {
      region?: string;
      functionVersion?: 'ALL' | '$LATEST';
      maxItems?: number;
      marker?: string;
    }

4. CloudWatch Operations

  • aws_cloudwatch_get_metrics: Retrieves metrics

    interface GetMetricsOptions {
      region?: string;
      namespace?: string;
      metricName?: string;
      dimensions?: Array<{
        name: string;
        value: string;
      }>;
      startTime: string | Date;
      endTime: string | Date;
      period: number;
      statistics: Array<'Average' | 'Maximum' | 'Minimum' | 'SampleCount' | 'Sum'>;
    }
  • aws_cloudwatch_describe_alarms: Lists CloudWatch alarms

    interface DescribeAlarmsOptions {
      region?: string;
      alarmNames?: string[];
      alarmNamePrefix?: string;
      stateValue?: 'OK' | 'ALARM' | 'INSUFFICIENT_DATA';
      maxRecords?: number;
      nextToken?: string;
    }

Technical Usage Patterns

Multi-step Resource Management

// List EC2 instances with specific tag
const instances = await tools.aws_ec2_describe_instances({
  region: "us-east-1",
  filters: [
    {
      name: "tag:Environment",
      values: ["Production"]
    },
    {
      name: "instance-state-name",
      values: ["running"]
    }
  ]
});
 
// Get CloudWatch metrics for these instances
const instanceIds = instances.Reservations.flatMap(r => 
  r.Instances.map(i => i.InstanceId)
);
 
const cpuMetrics = await Promise.all(instanceIds.map(instanceId => 
  tools.aws_cloudwatch_get_metrics({
    region: "us-east-1",
    namespace: "AWS/EC2",
    metricName: "CPUUtilization",
    dimensions: [{ name: "InstanceId", value: instanceId }],
    startTime: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24 hours
    endTime: new Date(),
    period: 300, // 5-minute intervals
    statistics: ["Average"]
  })
));
 
// Identify instances with high CPU usage
const highCpuInstances = cpuMetrics
  .filter(metric => {
    const datapoints = metric.Datapoints || [];
    const recentDatapoints = datapoints.slice(-12); // Last hour
    const avgCpu = recentDatapoints.reduce((sum, dp) => sum + dp.Average, 0) / 
                  (recentDatapoints.length || 1);
    return avgCpu > 80; // CPU above 80%
  })
  .map(metric => metric.Dimensions.find(d => d.Name === "InstanceId").Value);
 
// Scale up instances with high CPU
await Promise.all(highCpuInstances.map(instanceId => 
  tools.aws_ec2_control_instance({
    region: "us-east-1",
    instanceId,
    action: "stop"
  }).then(() => 
    // Update instance type
    tools.aws_ec2_modify_instance({
      region: "us-east-1",
      instanceId,
      instanceType: "m5.2xlarge"
    })
  ).then(() =>
    // Restart instance
    tools.aws_ec2_control_instance({
      region: "us-east-1",
      instanceId,
      action: "start"
    })
  )
));

Infrastructure as Code Operation

// Retrieve CloudFormation template from S3
const templateObject = await tools.aws_s3_get_object({
  bucket: "company-templates",
  key: "infrastructure/web-stack.yaml"
});
 
const templateBody = templateObject.Body.toString('utf-8');
 
// Create or update CloudFormation stack
const stackResult = await tools.aws_cloudformation_create_stack({
  stackName: "web-production",
  templateBody,
  parameters: [
    {
      parameterKey: "EnvironmentType",
      parameterValue: "Production"
    },
    {
      parameterKey: "InstanceType",
      parameterValue: "t3.large"
    }
  ],
  capabilities: ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"],
  tags: [
    { key: "Project", value: "WebPlatform" },
    { key: "Environment", value: "Production" }
  ]
});
 
// Monitor stack creation progress
const stackId = stackResult.StackId;
let stackStatus = "CREATE_IN_PROGRESS";
 
while (["CREATE_IN_PROGRESS", "UPDATE_IN_PROGRESS"].includes(stackStatus)) {
  await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
  
  const stackInfo = await tools.aws_cloudformation_describe_stacks({
    stackName: stackId
  });
  
  stackStatus = stackInfo.Stacks[0].StackStatus;
  console.log(`Stack status: ${stackStatus}`);
}
 
// Get outputs from the stack
const outputs = stackInfo.Stacks[0].Outputs;
const apiEndpoint = outputs.find(o => o.OutputKey === "ApiEndpoint").OutputValue;
const databaseEndpoint = outputs.find(o => o.OutputKey === "DatabaseEndpoint").OutputValue;

Advanced Implementation Considerations

Security and Permissions

AWS MCP implements robust security measures:

  1. IAM Policy Evaluation:

    class PolicyEvaluator {
      private readonly iam: IAMClient;
      
      constructor(region: string) {
        this.iam = new IAMClient({ region });
      }
      
      async evaluateAction(action: string, resource: string): Promise<boolean> {
        try {
          const command = new SimulatePrincipalPolicyCommand({
            PolicySourceArn: process.env.AWS_ROLE_ARN || "current-user",
            ActionNames: [action],
            ResourceArns: [resource]
          });
          
          const response = await this.iam.send(command);
          const result = response.EvaluationResults[0];
          
          return result.EvalDecision === "allowed";
        } catch (error) {
          console.error("Policy evaluation error:", error);
          return false; // Default to denial on error
        }
      }
    }
  2. Request Signing and Authentication:

    async function getSignedRequest(
      service: string,
      region: string,
      endpoint: string,
      method: string,
      body?: any
    ): Promise<SignedRequest> {
      // Get credentials
      const credentials = await credentialsProvider.getCredentials();
      
      // Calculate signature
      const date = new Date();
      const amzDate = date.toISOString().replace(/[:-]|\.\d{3}/g, '');
      const datestamp = amzDate.substring(0, 8);
      
      // Create canonical request
      const canonicalHeaders = `host:${endpoint}\nx-amz-date:${amzDate}\n`;
      const signedHeaders = 'host;x-amz-date';
      
      const payloadHash = crypto
        .createHash('sha256')
        .update(body || '')
        .digest('hex');
      
      const canonicalRequest = [
        method,
        '/',
        '',
        canonicalHeaders,
        signedHeaders,
        payloadHash
      ].join('\n');
      
      // Create string to sign
      const algorithm = 'AWS4-HMAC-SHA256';
      const credentialScope = `${datestamp}/${region}/${service}/aws4_request`;
      const stringToSign = [
        algorithm,
        amzDate,
        credentialScope,
        crypto.createHash('sha256').update(canonicalRequest).digest('hex')
      ].join('\n');
      
      // Calculate signature
      const signingKey = getSignatureKey(
        credentials.secretAccessKey,
        datestamp,
        region,
        service
      );
      
      const signature = crypto
        .createHmac('sha256', signingKey)
        .update(stringToSign)
        .digest('hex');
      
      // Create authorization header
      const authHeader = [
        `${algorithm} Credential=${credentials.accessKeyId}/${credentialScope}`,
        `SignedHeaders=${signedHeaders}`,
        `Signature=${signature}`
      ].join(', ');
      
      return {
        url: `https://${endpoint}/`,
        method,
        headers: {
          'Host': endpoint,
          'X-Amz-Date': amzDate,
          'Authorization': authHeader,
          'Content-Type': 'application/json'
        },
        body
      };
    }

Cost Control and Resource Boundaries

To prevent unexpected cloud resource costs:

class CostController {
  private readonly serviceLimits = {
    ec2: {
      maxInstances: 5,
      allowedTypes: ['t3.micro', 't3.small', 't3.medium']
    },
    s3: {
      maxBucketCount: 3,
      maxStorageGB: 100
    },
    lambda: {
      maxConcurrentExecutions: 10,
      maxMemoryMB: 512
    }
  };
  
  async validateEC2Launch(instanceType: string, count: number): Promise<boolean> {
    // Check instance type is allowed
    if (!this.serviceLimits.ec2.allowedTypes.includes(instanceType)) {
      throw new Error(`Instance type ${instanceType} is not allowed`);
    }
    
    // Check instance count doesn't exceed limit
    const existingInstances = await countRunningInstances();
    if (existingInstances + count > this.serviceLimits.ec2.maxInstances) {
      throw new Error(`Cannot launch ${count} new instances: would exceed limit of ${this.serviceLimits.ec2.maxInstances}`);
    }
    
    // Check estimated cost is within budget
    const estimatedCost = await calculateEstimatedCost(instanceType, count);
    if (estimatedCost > this.dailyBudget) {
      throw new Error(`Estimated cost ${estimatedCost} exceeds daily budget of ${this.dailyBudget}`);
    }
    
    return true;
  }
  
  // Additional validation methods for other services...
}

Troubleshooting Common Technical Issues

AWS API Throttling Handling

For managing AWS API rate limits:

class ThrottleHandler {
  private requestCounts: Map<string, number> = new Map();
  private lastReset: number = Date.now();
  private readonly resetInterval: number = 60000; // 1 minute in ms
  
  async executeWithThrottling<T>(
    serviceKey: string,
    operation: () => Promise<T>,
    maxAttempts: number = 3
  ): Promise<T> {
    this.updateCounts();
    
    const currentCount = this.requestCounts.get(serviceKey) || 0;
    this.requestCounts.set(serviceKey, currentCount + 1);
    
    let attempt = 0;
    let lastError;
    
    while (attempt < maxAttempts) {
      try {
        return await operation();
      } catch (error) {
        if (error.name === 'ThrottlingException' || 
            error.name === 'TooManyRequestsException' ||
            error.code === 'RequestLimitExceeded') {
          
          attempt++;
          lastError = error;
          
          if (attempt < maxAttempts) {
            // Exponential backoff with jitter
            const delayMs = Math.min(
              1000 * Math.pow(2, attempt) + Math.random() * 100,
              30000 // Max 30 seconds
            );
            await new Promise(resolve => setTimeout(resolve, delayMs));
            continue;
          }
        }
        
        throw error; // Non-throttling error or max attempts reached
      }
    }
    
    throw lastError;
  }
  
  private updateCounts() {
    const now = Date.now();
    if (now - this.lastReset >= this.resetInterval) {
      this.requestCounts.clear();
      this.lastReset = now;
    }
  }
}

Credential Management Issues

For handling credential refresh and rotation:

class CredentialRefresher {
  private credentials: AWS.Credentials | null = null;
  private expirationTime: number = 0;
  private refreshPromise: Promise<AWS.Credentials> | null = null;
  
  async getCredentials(): Promise<AWS.Credentials> {
    const now = Date.now();
    
    // If credentials are still valid, return them
    if (this.credentials && now < this.expirationTime - 15 * 60 * 1000) {
      return this.credentials;
    }
    
    // If refresh is in progress, wait for it
    if (this.refreshPromise) {
      return this.refreshPromise;
    }
    
    // Start credential refresh
    this.refreshPromise = this.refreshCredentials();
    
    try {
      this.credentials = await this.refreshPromise;
      
      // Set expiration time with 15-minute buffer
      if (this.credentials.expireTime) {
        this.expirationTime = this.credentials.expireTime.getTime();
      } else {
        // Default to 1 hour if no expiration is set
        this.expirationTime = now + 60 * 60 * 1000;
      }
      
      return this.credentials;
    } finally {
      this.refreshPromise = null;
    }
  }
  
  private async refreshCredentials(): Promise<AWS.Credentials> {
    // Implement appropriate credential refresh logic based on 
    // authentication method (IAM role, STS, etc.)
    
    // Example: Assuming IAM role
    if (process.env.AWS_ROLE_ARN) {
      const sts = new AWS.STS();
      const result = await sts.assumeRole({
        RoleArn: process.env.AWS_ROLE_ARN,
        RoleSessionName: 'MCP-Session'
      }).promise();
      
      return new AWS.Credentials({
        accessKeyId: result.Credentials.AccessKeyId,
        secretAccessKey: result.Credentials.SecretAccessKey,
        sessionToken: result.Credentials.SessionToken,
        expireTime: result.Credentials.Expiration
      });
    }
    
    // Default: Load from environment or shared credentials file
    return new AWS.SharedIniFileCredentials({
      profile: process.env.AWS_PROFILE || 'default'
    });
  }
}

Conclusion

AWS MCP servers represent a sophisticated technical bridge between conversational AI and the extensive capabilities of Amazon Web Services. By implementing the Model Context Protocol with AWS's comprehensive API ecosystem, these servers enable AI assistants to securely manage cloud infrastructure, analyze telemetry data, and execute complex operational workflows—all through natural language interaction.

This implementation establishes a foundation for building secure, scalable cloud operations that can be triggered and managed through conversational interfaces. As both MCP and AWS services continue to evolve, we can expect further advancements in security features, service coverage, and integration options.

For developers seeking to extend their AI systems with cloud capabilities, AWS MCP offers a standardized, secure approach that abstracts the complexity of AWS APIs while providing AI assistants with powerful tools to operate within the world's most comprehensive cloud infrastructure platform.

Last updated on