mcpField
C
cloud-storage

cloud-storage

github.com/claude-dev-suiteCloud & DevOps4664 installsUpdated 2d ago
Repository

About cloud-storage

A reference skill for implementing AWS S3 object storage in application code. It covers upload and download patterns, bucket configuration, and operational safeguards for developers working with stored files.

Key features

  1. 01S3 uploads and downloads
  2. 02Presigned URLs
  3. 03Multipart uploads for large files
  4. 04Bucket policy and CORS examples
  5. 05Troubleshooting and production checklist

Use cases

  1. 01Allow clients to upload files directly to S3
  2. 02Generate time-limited download links
  3. 03Configure browser uploads and public asset access

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill cloud-storage

After installing, type/cloud-storagein Claude Code to confirm it loaded.

Details

From the project README

Cloud Object Storage

AWS S3 (Recommended Default)

Setup (SDK v3)
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

const s3 = new S3Client({ region: process.env.AWS_REGION });
Upload
// Direct upload
await s3.send(new PutObjectCommand({
  Bucket: process.env.S3_BUCKET,
  Key: `uploads/${userId}/${filename}`,
  Body: buffer,
  ContentType: mimeType,
  Metadata: { 'uploaded-by': userId },
}));

// Presigned URL (client uploads directly to S3)
const url = await getSignedUrl(s3, new PutObjectCommand({
  Bucket: process.env.S3_BUCKET,
  Key: `uploads/${key}`,
  ContentType: mimeType,
}), { expiresIn: 3600 });
Presigned Download
const url = await getSignedUrl(s3, new GetObjectCommand({
  Bucket: process.env.S3_BUCKET,
  Key: fileKey,
}), { expiresIn: 3600 });
Multipart Upload (large files)
import { CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';

// Simplified with lib-storage
const upload = new Upload({
  client: s3,
  params: { Bucket: bucket, Key: key, Body: readableStream },
  partSize: 10 * 1024 * 1024, // 10MB parts
  leavePartsOnError: false,
});
upload.on('httpUploadProgress', (progress) => console.log(progress));
await upload.done();
Python (boto3)
import boto3
from botocore.config import Config

s3 = boto3.client('s3', config=Config(signature_version='s3v4'))

# Upload
s3.upload_fileobj(file_obj, bucket, key, ExtraArgs={'ContentType': mime_type})

# Presigned URL
url = s3.generate_presigned_url('put_object',
    Params={'Bucket': bucket, 'Key': key, 'ContentType': mime_type},
    ExpiresIn=3600)
Java (Spring)
@Service
public class S3Service {
    private final S3Client s3;

    public String generatePresignedUploadUrl(String key, String contentType) {
        var presigner = S3Presigner.builder().region(Region.of(region)).build();
        var request = PutObjectPresignRequest.builder()
            .signatureDuration(Duration.ofHours(1))
            .putObjectRequest(b -> b.bucket(bucket).key(key).contentType(contentType))
            .build();
        return presigner.presignPutObject(request).url().toString();
    }
}

Bucket Policy Patterns

Public read for assets
{
  "Statement": [{
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::my-bucket/public/*"
  }]
}
CORS for direct uploads
{
  "CORSRules": [{
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["PUT", "POST"],
    "AllowedOrigins": ["https://myapp.com"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }]
}

Anti-Patterns

Anti-PatternFix
Proxying large files through serverUse presigned URLs for direct client upload/download
No Content-Type on uploadAlways set ContentType to enable correct browser behavior
Predictable file keysUse UUIDs or hashed paths to prevent enumeration
No lifecycle rulesSet expiration for temp uploads, transition old files to Glacier
Long-lived presigned URLsKeep expiry short (1h for uploads, 15m for downloads)
No multipart for large filesUse multipart upload for files > 100MB

Quick Troubleshooting

IssueCauseFix
403 on presigned URLExpired, wrong region, or CORSCheck expiry, region, CORS config
SignatureDoesNotMatchContentType mismatchEnsure client sends same ContentType used in signing
Slow uploadsSingle-part for large filesUse multipart upload with parallel parts
CORS errorsMissing CORS configurationAdd CORSRules to bucket
AccessDenied on public filesMissing bucket policyAdd public read policy for the prefix

Production Checklist

  • Presigned URLs for all client uploads (never proxy large files)
  • ContentType set on every upload
  • UUID-based keys (prevent enumeration)
  • CORS configured for direct uploads
  • Lifecycle rules for temp/old files
  • Encryption at rest enabled (SSE-S3 or SSE-KMS)
  • Access logging enabled
  • Versioning enabled for critical buckets
  • CloudFront CDN for public assets

Comments

Markdown supported