s3-mcp
Provides tools for interacting with Cloudflare R2 S3-compatible storage, enabling bucket listing, object listing, metadata inspection, capped object reads, and optional object upload/delete via configuration.
Provides tools for interacting with MinIO S3-compatible storage, enabling bucket listing, object listing, metadata inspection, capped object reads, and optional object upload/delete via configuration.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@s3-mcplist the objects in the prod-logs bucket"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
s3-mcp
Minimal Model Context Protocol server for S3-compatible storage — AWS S3, RustFS, MinIO, Cloudflare R2, and similar.
Path-style addressing by default (required for many self-hosted endpoints whose TLS cert does not cover
bucket.endpointsubdomains)Opt-in self-signed / custom-CA TLS trust, scoped to the S3 client only
Read-only by default; writes require an explicit flag
Optional bucket allow-list
Env vars + CLI flag overrides; secrets stay env-only
Tools
Tool | Access | Description |
| read | List buckets |
| read | List objects ( |
| read | Size, ETag, content-type, user metadata |
| read | Read body via a capped |
| write | Upload text or base64 content |
| write | Delete object (idempotent: missing key → success) |
Write tools refuse with a clear error unless S3_ALLOW_WRITE=true (or --allow-write).
Related MCP server: S3 MCP Server
Install / run
npx (recommended)
{
"mcpServers": {
"s3": {
"command": "npx",
"args": ["-y", "s3-mcp"],
"env": {
"S3_ENDPOINT": "https://rustfs.example.com",
"S3_ACCESS_KEY_ID": "<key>",
"S3_SECRET_ACCESS_KEY": "<secret>",
"S3_REGION": "us-east-1",
"S3_ALLOW_SELF_SIGNED": "true"
}
}
}
}A bare --stdio arg is accepted and ignored (drop-in compatible with configs written for s3-mcp-server).
npx straight from GitHub
{
"mcpServers": {
"s3": {
"command": "npx",
"args": ["-y", "github:tompetk/s3-mcp"],
"env": {
"S3_ENDPOINT": "https://rustfs.example.com",
"S3_ACCESS_KEY_ID": "<key>",
"S3_SECRET_ACCESS_KEY": "<secret>",
"S3_REGION": "us-east-1",
"S3_ALLOW_SELF_SIGNED": "true"
}
}
}
}Keep -y: without it npx asks for install confirmation on stdin, which is the MCP transport, so the server never starts. The first run takes roughly 40 seconds because npm installs TypeScript and runs the prepare build; later runs use the npx cache. The published npm package ships prebuilt dist/, so ["-y", "s3-mcp"] starts instantly.
From source
git clone https://github.com/tompetk/s3-mcp.git
cd s3-mcp
npm install
npm run build
node dist/index.js --helpPoint your MCP client at node + the absolute path to dist/index.js.
Configuration examples
RustFS / MinIO (self-hosted, often self-signed)
{
"mcpServers": {
"s3": {
"command": "npx",
"args": ["-y", "s3-mcp", "--insecure"],
"env": {
"S3_ENDPOINT": "https://rustfs.example.com",
"S3_ACCESS_KEY_ID": "<key>",
"S3_SECRET_ACCESS_KEY": "<secret>",
"S3_REGION": "us-east-1",
"S3_FORCE_PATH_STYLE": "true",
"S3_ALLOW_WRITE": "false"
}
}
}
}Prefer a custom CA when you have one:
S3_CA_BUNDLE=/path/to/ca.pem--insecure / S3_ALLOW_SELF_SIGNED=true disables certificate verification for this client only (never sets NODE_TLS_REJECT_UNAUTHORIZED). Prefer S3_CA_BUNDLE when possible.
Cloudflare R2
{
"mcpServers": {
"s3": {
"command": "npx",
"args": ["-y", "s3-mcp", "--no-path-style"],
"env": {
"S3_ENDPOINT": "https://<ACCOUNT_ID>.r2.cloudflarestorage.com",
"S3_ACCESS_KEY_ID": "<key>",
"S3_SECRET_ACCESS_KEY": "<secret>",
"S3_REGION": "auto"
}
}
}
}Environment variables & flags
Env | Flag | Default | Notes |
|
| (required) | S3 API URL |
| — | (required) | Env only (argv is visible in |
| — | (required) | Env only |
|
|
| Use |
|
|
| Path-style is the safe default for self-hosted |
|
|
| Skip TLS verify (logs a stderr warning) |
|
| — | PEM file to trust |
|
|
| Enable put/delete |
|
| — | Comma-separated allow-list |
|
|
| Cap for |
— |
| — | Accepted, ignored |
— |
| — |
CLI flags override env vars.
Security
Read-only by default. Pointing this at production buckets without
S3_ALLOW_WRITEcannot mutate data via the MCP tools.Bucket allow-list. Set
S3_ALLOWED_BUCKETS=prod-logs,prod-artifacts(or repeat--bucket) so the agent cannot touch other buckets the credentials can see.TLS. Prefer
S3_CA_BUNDLEover--insecure. Self-signed mode is convenient for lab endpoints; it is not a substitute for trusting the right CA.Secrets. Keep keys in the MCP client's
envblock or a secret store — never commit them..envis gitignored; use.env.exampleas a template for local smoke tests.
Development
npm install
npm run build
npm run typecheck
# Live round-trip (creates a throwaway bucket unless S3_BUCKET is set)
export S3_ENDPOINT=https://rustfs.example.com
export S3_ACCESS_KEY_ID=...
export S3_SECRET_ACCESS_KEY=...
npm run smoke
# Read-only credentials (list + head + ranged get)
S3_SMOKE_READ_ONLY=true S3_BUCKET=test npm run smokePublishing
Tags matching v* trigger GitHub Actions to build and npm publish --provenance --access public. Add an NPM_TOKEN repository secret once.
git tag v1.0.0
git push origin v1.0.0License
MIT
Available Tools
6 toolss3_delete_objectDelete S3 objectADestructive
Delete an object. Requires S3_ALLOW_WRITE=true. Idempotent: missing keys (NoSuchKey/404) are treated as success.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Object key | |
| bucket | Yes | Bucket name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the danger profile is known. The description adds genuinely new behavioral facts beyond them: the S3_ALLOW_WRITE=true gating requirement and idempotent handling of missing keys (NoSuchKey/404 treated as success), which materially affects error handling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with zero filler, front-loaded with the action, then precondition, then idempotency semantics. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter delete tool with full schema coverage and no output schema, the description covers the action, the authorization precondition, and the error/idempotency semantics. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% ('Object key', 'Bucket name'), so the schema already carries parameter meaning. The description adds nothing about bucket/key formats or constraints, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Delete an object') that an agent can immediately distinguish from the read/list/head/put siblings. The title and name reinforce the same precise meaning with no ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a hard precondition ('Requires S3_ALLOW_WRITE=true'), which is useful context for deciding whether the call will succeed, but it never contrasts when to use this versus siblings like s3_put_object or s3_head_object. Usage is implied rather than explicitly scoped.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
s3_head_objectHead S3 objectARead-only
Fetch object metadata without downloading the body (size, ETag, content-type, user metadata).
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Object key | |
| bucket | Yes | Bucket name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, and destructiveHint=false, so safety is covered. The description goes beyond that by naming the exact payload returned (size, ETag, content-type, user metadata) and confirming no body transfer, though it omits error behavior (e.g., missing key) and permission requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler; the key constraint ('without downloading the body') and the returned fields both earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully enumerates the returned metadata, which is exactly the gap it should fill. Error/edge-case behavior is the only missing piece, which is minor for a simple two-parameter read operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so bucket and key are already documented in the schema. The description adds no meaning beyond that (e.g., key format, versioning, prefix behavior), so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Fetch object metadata') and immediately differentiates itself from the body-downloading sibling by specifying 'without downloading the body'. An agent can distinguish this from s3_read_object without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the 'without downloading the body' clause, which suggests this is the cheap metadata-check alternative to s3_read_object. However, it never explicitly says when to use this versus alternatives (e.g., for existence checks) or when-not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
s3_list_bucketsList S3 bucketsARead-only
List all available S3 buckets visible to the configured credentials.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=true, so the safety profile is covered. The description adds meaningful context beyond that: results are limited to buckets visible to the configured credentials, which tells the agent why the list may be partial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler; the resource and its scoping constraint are both stated immediately.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with full annotation coverage and no output schema, the description is nearly sufficient. It does not state what the response contains (e.g., bucket names) or whether large accounts are truncated, a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the baseline this scores 4. The empty schema and the description agree that no filtering or paging inputs are accepted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (S3 buckets) with scope ('visible to the configured credentials'). The bucket-level resource naturally distinguishes it from the object-level siblings such as s3_list_objects and s3_head_object.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use statement, no exclusions, and no named alternatives. Usage is implied by the resource scope — an agent would reasonably call this to discover buckets before listing objects — but the description never says so.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
s3_list_objectsList S3 objectsARead-only
List objects in a bucket. Optional prefix/delimiter for folder-style browsing. Note: S3 ListObjectsV2 does not return user metadata — use s3_head_object for that.
| Name | Required | Description | Default |
|---|---|---|---|
| bucket | Yes | Bucket name | |
| prefix | No | Key prefix filter | |
| maxKeys | No | Max keys to return (default 1000) | |
| delimiter | No | Delimiter for common prefixes (e.g. "/") | |
| continuationToken | No | Pagination token from a previous response |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/openWorldHint/destructiveHint=false, so the safety profile is covered. The description adds a valuable limitation (metadata not returned) but says nothing about pagination behavior despite exposing a continuationToken, so added behavioral context is partial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short, front-loaded sentences with zero filler; purpose first, then the browsing idiom, then the sibling-routing caveat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Adequate for a read-only list tool whose annotations carry safety, but for a paginated list with a continuationToken parameter and no output schema, an agent gets no description of what the response contains or how to page. This is a meaningful gap for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so parameters are already fully documented. The description's mention of prefix/delimiter semantics and the metadata note adds marginal value but no syntax or format detail beyond the schema; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List objects in a bucket') and names the sibling it is not (s3_head_object), with scope clarified by prefix/delimiter for folder-style browsing. An agent can distinguish this from s3_list_buckets and neighboring object tools without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes metadata lookups to s3_head_object and implies folder-style browsing via prefix/delimiter. It does not, however, cover when-not-to-use beyond the metadata case, e.g. no guidance on choosing this over s3_list_buckets or on pagination workflows.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
s3_put_objectPut S3 objectADestructive
Upload object content. Requires S3_ALLOW_WRITE=true. Pass encoding=base64 to upload binary data from a base64 string.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Object key | |
| bucket | Yes | Bucket name | |
| content | Yes | Object body (text or base64) | |
| encoding | No | How to decode content (default: utf8) | |
| metadata | No | User metadata key/value map | |
| contentType | No | Content-Type header |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and openWorldHint=true, so the mutation/global side effects are covered. The description adds value by disclosing the S3_ALLOW_WRITE=true authorization gate, which an agent cannot infer from annotations or schema. It omits whether existing keys are overwritten, which would be the remaining useful detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with the core action first, then the prerequisite, then the binary-data hint. No filler and everything is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema and full schema coverage, the definition covers the action, the authorization prerequisite, and binary encoding. The main gap is overwrite/conflict behavior on an existing key, which is relevant for a put operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so bucket, key, content, encoding, metadata, and contentType are all documented in the schema. The description's encoding=base64 note merely restates the enum's intent, adding no syntax or edge-case detail beyond the structured fields, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Upload object content'), which is unambiguous against siblings like s3_read_object, s3_delete_object, and s3_list_objects. It does not explicitly name a sibling to disambiguate, but the write action is inherently distinct from the read/list/delete tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete precondition ('Requires S3_ALLOW_WRITE=true') and a format hint ('Pass encoding=base64 to upload binary data'), which tells the agent when the tool will work and how to handle binary payloads. It stops short of comparing against alternatives or stating when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
s3_read_objectRead S3 objectARead-only
Read object content. Uses a Range request capped by maxBytes so large objects never stream in full. encoding=auto returns UTF-8 text when decodable, otherwise base64.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Object key | |
| bucket | Yes | Bucket name | |
| encoding | No | How to encode the body (default: auto) | |
| maxBytes | No | Max bytes to read (default: 262144) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/destructive/openWorld, so the bar is lower, yet the description adds real operational context: a Range request capped by maxBytes means large objects are never fully streamed, and encoding=auto has defined fallback behavior. It does not state error behavior for missing keys, but the added traits go meaningfully beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with the core purpose front-loaded and no filler. Each sentence carries distinct information: purpose, size-bound behavior, and encoding behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must convey what comes back, and it does explain that the returned body is UTF-8 or base64 depending on encoding. It leaves out failure/not-found behavior and pagination-style continuation for truncated reads, which is a minor gap for a read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3, but the description adds semantics the schema lacks: that maxBytes is enforced via a Range request (bounding transfer cost) and that encoding=auto returns UTF-8 when decodable and falls back to base64. These explain the behavior of the two optional parameters rather than restating their names.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Read object content') that is clearly distinct in intent from sibling operations like s3_list_objects, s3_head_object, and s3_put_object. It stops short of explicitly contrasting itself with s3_head_object (metadata-only), so it misses the top tier.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance and no alternatives named. The obvious selection question (content read vs s3_head_object for metadata-only) is left entirely to inference. This matches the calibration case of a description with no explicit usage conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v1.0.0- First observed
s3_delete_object - First observed
s3_head_object - First observed
s3_list_buckets - First observed
s3_list_objects - First observed
s3_put_object - First observed
s3_read_object
TDQS
Scored across 6 tools
Each tool targets a distinct S3 operation: listing buckets, listing objects, fetching metadata, reading content, uploading, and deleting. The descriptions explicitly clarify the tricky boundary between s3_head_object (metadata only) and s3_read_object (content), and between s3_list_objects and s3_head_object regarding user metadata.
Every tool follows the same predictable `s3_verb_noun` snake_case pattern (s3_list_buckets, s3_read_object, s3_put_object, etc.). No mixed conventions or vague verbs.
Six tools is well-scoped for a focused S3 object-access server, covering the core read/write lifecycle without bloat. Each tool earns its place with a non-overlapping job.
Core object lifecycle is covered: list buckets, list objects, head, read, put, delete. Minor gaps exist — no bucket create/delete, no copy_object, and no multi-object delete — but agents can work around these for typical object read/write tasks.
Maintenance
Related MCP Connectors
Create a free sandbox object storage bucket; upload, download, list, inspect, and delete objects.
S3 storage and Solana/Base/Ethereum health checks for AI agents, paid per call via x402.
Artifact store for AI agents — read, write, and search files by path; share by rendered URL.
Encrypted A2A object storage for autonomous agent state and artifacts
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables AI assistants to manage MinIO object storage through comprehensive bucket operations, file uploads/downloads, batch processing, permissions management, and URL generation. Supports both automatic and manual connection modes with flexible authentication options.1915 npm2MIT
- AlicenseAqualityDmaintenanceEnables interaction with S3-compatible storage services like AWS S3 and Cloudflare R2, supporting bucket management, object listing, reading, uploading, and deletion operations.5199 npmISC
- AlicenseNot gradedqualityCmaintenanceEnables interaction with AWS S3 storage through bucket operations (create, delete, list), object management (upload, download, delete, list), and bucket policy configuration using AWS credentials.21 npm2MIT
- AlicenseNot gradedqualityDmaintenanceIt Integration for MinIO / S3-compatible object storage, providing AI assistants with direct access to bucket management, object CRUD, presigned URLs, policies, lifecycle rules, and storage analytics.1MIT