mcp-storage
Universal cloud storage MCP server — manage files across AWS S3, Google Cloud Storage, Cloudflare R2, MinIO, and any S3-compatible provider through a single interface. 12 tools for listing, uploading, downloading, copying, moving, and searching objects.
Installation
cargo install mcp-storage
Provider Setup
AWS S3
No extra config needed if you have ~/.aws/credentials set up:
mcp-storage
Or with explicit credentials:
STORAGE_ACCESS_KEY=AKIA... STORAGE_SECRET_KEY=... STORAGE_REGION=us-east-1 mcp-storage
Google Cloud Storage
GCS works via S3 interoperability. Create HMAC keys first:
# Create HMAC key (one-time setup)
gcloud storage hmac create [email protected]
# Run with GCS
STORAGE_ENDPOINT=https://storage.googleapis.com \
STORAGE_ACCESS_KEY=GOOG1E... \
STORAGE_SECRET_KEY=... \
STORAGE_REGION=us-east-1 \
mcp-storage
Note: GCS S3 interop doesn't support
list_buckets. Uselist_objectswith a specific bucket name.
Cloudflare R2
STORAGE_ENDPOINT=https://ACCOUNT_ID.r2.cloudflarestorage.com \
STORAGE_ACCESS_KEY=... \
STORAGE_SECRET_KEY=... \
STORAGE_REGION=auto \
mcp-storage
Get R2 credentials from: Cloudflare Dashboard → R2 → Manage R2 API Tokens.
MinIO (Self-hosted)
STORAGE_ENDPOINT=http://localhost:9000 \
STORAGE_ACCESS_KEY=minioadmin \
STORAGE_SECRET_KEY=minioadmin \
mcp-storage
DigitalOcean Spaces
STORAGE_ENDPOINT=https://nyc3.digitaloceanspaces.com \
STORAGE_ACCESS_KEY=... \
STORAGE_SECRET_KEY=... \
STORAGE_REGION=nyc3 \
mcp-storage
Backblaze B2
STORAGE_ENDPOINT=https://s3.us-west-004.backblazeb2.com \
STORAGE_ACCESS_KEY=... \
STORAGE_SECRET_KEY=... \
STORAGE_REGION=us-west-004 \
mcp-storage
MCP Client Configuration
Claude Desktop
{
"mcpServers": {
"storage": {
"command": "mcp-storage",
"env": {
"STORAGE_ENDPOINT": "https://storage.googleapis.com",
"STORAGE_ACCESS_KEY": "GOOG1E...",
"STORAGE_SECRET_KEY": "your-secret",
"STORAGE_REGION": "us-east-1"
}
}
}
}
Cursor
Add to .cursor/mcp.json:
{
"mcpServers": {
"storage": {
"command": "mcp-storage",
"env": {}
}
}
}
If using AWS with default credentials (~/.aws/credentials), no env vars needed.
Tools (12)
Browse & Read
Write (Gated)
Usage Examples
List what's in a bucket
Agent: "What files are in my data-pipeline bucket?"
→ list_objects(bucket="data-pipeline", prefix="output/", limit=20)
Result:
output/report-2026-05-01.csv (2.3 MB)
output/report-2026-05-02.csv (2.1 MB)
output/summary.json (4.2 KB)
Upload a file
Agent: "Save this analysis to my reports bucket"
→ upload_object(bucket="reports", key="2026/q2-analysis.md", content="# Q2 Analysis\n...")
Result: uploaded, etag="abc123"
Generate a shareable link
Agent: "I need a download link for the quarterly report, valid for 1 hour"
→ generate_presigned_url(bucket="reports", key="2026/q2-report.pdf", expires_in=3600)
Result: https://s3.amazonaws.com/reports/2026/q2-report.pdf?X-Amz-Signature=...
Search for files
Agent: "Find all CSV files from May"
→ search_objects(bucket="data-pipeline", pattern="output/2026-05")
Result:
output/2026-05-01.csv
output/2026-05-02.csv
...
Check storage usage
Agent: "How much space is my logs bucket using?"
→ get_storage_usage(bucket="application-logs")
Result: 142,847 objects, 23.4 GB total
Environment Variables
*If not set, uses AWS default credential chain (~/.aws/credentials, AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY env vars, IAM roles).
Security
- Write operations are gated —
delete_object,move_object, andcreate_bucketrequire approval in governed environments - Presigned URLs expire — default 1 hour, configurable per request
- No secrets in responses — credentials are never echoed back
- Read-only by default — browse and download tools don't modify anything
Tested Providers
*GCS S3 interop doesn't support ListBuckets — use list_objects with a known bucket name.
License
Apache-2.0
rmcp and MCP compatibility
This server is built with rmcp 3.1.2 and requires Rust 1.94.1 or newer. The rmcp 3 rollout retains legacy MCP initialization compatibility and targets MCP protocol revisions 2025-11-25 and 2026-07-28.
MCP 2026-07-28 rollout (P4 workflow/business)
This server uses rmcp 3.1.2 and adk-mcp-sdk 0.2 with a minimum supported
Rust version of 1.94.1. It accepts stateless MCP 2026 requests with
per-request protocol, client identity, and capability metadata while retaining
the legacy MCP 2025-11-25 initialize flow for ordinary tools.
- Tasks:
download_object,generate_presigned_url,upload_object - MRTR approvals:
move_object,delete_object,create_bucket - Discovery and routing: rmcp serves on-demand discovery and validates the
per-request protocol envelope; HTTP deployments can route with
Mcp-MethodandMcp-Name. The packaged binary currently uses stdio. - Caching:
tools/listreturns a publicttlMsof 60,000 for MCP 2026; rmcp omits the cache fields for legacy clients. - Deprecated extensions: this server does not add new Roots, Sampling, or dynamic client-registration dependencies.
Protected tools require MCP_REQUEST_STATE_KEY with at least 32 high-entropy
bytes. All replicas must share that key so sealed approval state can resume on
another instance. Approval state is bound to the client identity, tool, and
arguments and expires after two minutes. Missing identity, invalid state,
rejection, or legacy protocol use fails closed. Task records are process-local
for the current stdio runtime; use a durable task store before deploying the
server behind scale-to-zero HTTP infrastructure.