{
  "markdown": "<p align=\"center\">\n  <img src=\"docs/public/images/logo.png\" alt=\"nogoo9\" width=\"128\" />\n</p>\n\n<h1 align=\"center\">@nogoo9/mcp-server-cloud-fs</h1>\n\n<p align=\"center\">\n  <a href=\"https://github.com/nogoo9/mcp-server-cloud-fs/actions/workflows/ci.yml\"><img src=\"https://github.com/nogoo9/mcp-server-cloud-fs/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"></a>\n  <a href=\"https://nogoo9.github.io/mcp-server-cloud-fs/\"><img src=\"https://img.shields.io/badge/docs-GitHub_Pages-blue?logo=github\" alt=\"Docs\"></a>\n  <a href=\"https://coveralls.io/github/nogoo9/mcp-server-cloud-fs?branch=main\"><img src=\"https://coveralls.io/repos/github/nogoo9/mcp-server-cloud-fs/badge.svg?branch=main\" alt=\"Coverage\"></a>\n  <a href=\"https://semgrep.dev\"><img src=\"https://img.shields.io/badge/SAST-Semgrep-4B11A8?logo=semgrep&logoColor=white\" alt=\"Semgrep\"></a>\n  <br/>\n  <a href=\"https://www.npmjs.com/package/@nogoo9/mcp-server-cloud-fs\"><img src=\"https://img.shields.io/npm/v/@nogoo9/mcp-server-cloud-fs\" alt=\"npm\"></a>\n  <img src=\"https://img.shields.io/npm/dm/%40nogoo9%2Fmcp-server-cloud-fs\" alt=\"NPM Downloads\">\n  <a href=\"https://skills.sh/nogoo9/mcp-server-cloud-fs\"><img src=\"https://skills.sh/b/nogoo9/mcp-server-cloud-fs\" alt=\"skills.sh\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/license-PolyForm--Shield--1.0.0-blue\" alt=\"License\"></a>\n</p>\n\n<p align=\"center\">\n  Cloud replacement for <code>mcp-server-filesystem</code> — 30 tools for S3, Azure Blob, and GCS.<br/>\n  Deploy locally via STDIO or remotely over HTTP/WebSocket with OAuth 2.1 auth.<br/>\n  Also available as an npm library and interactive TUI.\n</p>\n\n<p align=\"center\">\n  <strong>📖 <a href=\"https://nogoo9.github.io/mcp-server-cloud-fs/latest/\">Read the full documentation →</a></strong>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://buymeacoffee.com/eterna2\">\n    <img src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" alt=\"Buy Me A Coffee\" height=\"48\">\n  </a>\n</p>\n\n![cloud-fs in Claude Code](docs/public/images/cloud-fs-claude-demo.svg)\n\n![cloud-fs interactive shell](docs/public/images/cloud-fs-cli-demo.svg)\n\n**Providers:** Amazon S3 · Azure Blob Storage · Google Cloud Storage · MinIO · RustFS · Cloudflare R2 · Backblaze B2 · Wasabi · LocalStack · SQLite · In-Memory\n\n---\n\n## Table of Contents\n\n- [What it does](#what-it-does)\n- [Quick start](#quick-start)\n- [Interactive Shell](#interactive-shell-cloud-fs)\n- [Transports](#transports)\n- [Authentication & Authorization](#authentication--authorization)\n- [Production Features](#production-features)\n- [CLI Reference](#cli-reference)\n- [Provider Setup](#provider-setup)\n- [MCP Client Config](#mcp-client-config)\n- [Tool Reference](#tool-reference)\n- [Architecture: VFS](#architecture-virtual-filesystem-vfs)\n- [Caching](#caching)\n- [Programmatic Usage](#programmatic-usage-npm-library)\n- [MCP Inspector](#mcp-inspector)\n- [Development & Testing](#development--testing)\n- [AI Agent Skill](#ai-agent-skill)\n- [Documentation](#documentation)\n- [License](#license)\n\n---\n\n## What it does\n\n`@nogoo9/mcp-server-cloud-fs` exposes all 14 tools defined by [`mcp-server-filesystem`](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem) — same tool names, same parameter schemas — over cloud object storage. Drop it into any MCP client config that currently points at `mcp-server-filesystem` and your AI assistant gains read/write access to S3, Azure Blob Storage, or Google Cloud Storage buckets.\n\nIt also includes **5 extended tools** inspired by [claude-code's filesystem tool surface](https://github.com/codeaashu/claude-code/tree/main/src/tools): line-range reads, byte-range chunk reads, in-process regex search (single file and multi-file), server-side copy, and opt-in deletion. Plus **6 cloud-native tools** (presigned URLs, object metadata/tags, tag-based search, version history, version restore), **2 AI-native tools** (schema extraction, file summarization), and **1 macro tool** (`patch_file` for atomic diffs).\n\nA **Virtual Filesystem (VFS) layer** provides FUSE-like cache coherence with ETag-based concurrency control, a **shell tool** lets you run POSIX-like commands (`ls`, `grep`, `jq`, `cat | wc`, etc.) against cloud storage, and the package is available as a **programmatic npm library**.\n\n### v0.7.0 Highlights\n\n- **Dynamic tool surface reduction**: scope-aware tool filtering — clients only see tools they're authorized to use\n- **DLP content sanitization**: regex-based middleware redacts PII, API keys, and credentials from tool responses (`--enable-dlp`)\n- **AI-native tools**: `get_file_schema` extracts CSV/JSON structure; `summarize_file` returns compact head/tail previews\n- **ETag concurrency control**: SHA-256 content-addressable ETags with `expected_etag` conflict detection on `edit_file` and `patch_file`\n- **`patch_file` macro tool**: atomic read-diff-write in a single tool call — supports unified diffs and line-range replacements\n\n### v0.6.0 Highlights\n\n- **Cloud-native tools**: presigned URLs, object metadata/tags, version history, version restore\n- **Byte-range reads**: `read_file_chunk` fetches specific byte ranges without downloading the full object\n- **Structured audit logging**: tool invocation audit trail with pluggable sinks (stderr, file)\n- **Multi-provider routing**: `MultiProvider` serves S3 + Azure + GCS from a single server instance\n- **Azure Managed Identity**: `DefaultAzureCredential` for OIDC and federated auth\n- **Connection health-check**: startup credential validation with diagnostic reporting\n- **MCP Resources**: browse cloud storage as native MCP Resources (no tool calls needed)\n- **Structured errors**: `CloudError` with typed codes and provider-specific error mappers\n\n### v0.5.0 Highlights\n\n- **Interactive TUI (`cloud-fs`)**: Terminal shell with `cd`, tab completion, and command history\n- **Multi-transport**: STDIO (default), Streamable HTTP, and WebSocket\n- **Dual runtime**: Bun-native and Node.js support (HTTP transport + SQLite provider)\n- **OAuth 2.1**: Built-in auth server or external IdP token validation\n- **ext-auth extensions**: Client Credentials (M2M) and Enterprise-Managed Authorization (SSO)\n- **Production hardening**: Rate limiting, CORS, security headers, health checks, structured logging\n- **AI agent skill**: Installable `skills/cloud-fs` for Claude Code, Gemini CLI, and other AI assistants\n\n---\n\n## Quick start\n\n### Local (STDIO — default)\n\n```bash\nnpx @nogoo9/mcp-server-cloud-fs s3 s3://my-bucket\n```\n\n### Remote (HTTP)\n\n```bash\n# Bun (zero Express dependency)\nbunx @nogoo9/mcp-server-cloud-fs s3 s3://my-bucket --transport http --port 3000\n\n# Node.js (requires express peer dep)\nnpx @nogoo9/mcp-server-cloud-fs s3 s3://my-bucket --transport http --port 3000\n```\n\n### Remote (WebSocket — Bun only)\n\n```bash\nbunx @nogoo9/mcp-server-cloud-fs s3 s3://my-bucket --transport ws --port 3000\n```\n\n### Demo (no cloud credentials needed)\n\n```bash\nbunx @nogoo9/mcp-server-cloud-fs memory mem://demo --enable-shell --seed-demo\n```\n\n---\n\n## Interactive Shell (`cloud-fs`)\n\n![cloud-fs interactive shell demo](docs/public/images/cloud-fs-cli-demo.svg)\n\nDrop into an interactive terminal for exploring and managing cloud storage — no MCP client needed:\n\n```bash\n# S3\nnpx -p @nogoo9/mcp-server-cloud-fs cloud-fs s3 s3://my-bucket\n\n# In-memory demo with sample files\nnpx -p @nogoo9/mcp-server-cloud-fs cloud-fs memory mem://demo --seed-demo\n\n# With a config file (cloud-fs.json in CWD)\nnpx -p @nogoo9/mcp-server-cloud-fs cloud-fs\n```\n\n### Features\n\n- **`cd` navigation** — `cd data`, `cd ..`, `cd /` with dynamic prompt showing current directory\n- **Tab completion** — context-aware path and command completion\n- **Command history** — persistent across sessions (`~/.cloud-fs_history`)\n- **Relative paths** — all commands resolve relative to `cwd`, just like a real shell\n- **19 built-in commands** — `ls`, `cat`, `head`, `tail`, `cp`, `mv`, `rm`, `mkdir`, `touch`, `stat`, `find`, `grep`, `wc`, `du`, `echo`, `tee`, `diff`, `jq`, `cd`\n- **Pipes & redirects** — `cat config.json | jq '.database'`, `echo hello > file.txt`\n\n### Local development\n\n```bash\nbun src/cli-tui.ts memory mem://demo --seed-demo\n```\n\n---\n\n## Transports\n\nThe server supports three MCP transports, selected via `--transport`:\n\n| Transport | Flag | Runtime | Use case |\n|---|---|---|---|\n| **STDIO** | `--transport stdio` (default) | Bun, Node | Local `npx`, Claude Desktop, Claude Code |\n| **Streamable HTTP** | `--transport http` | Bun ✅, Node ✅ | Remote deployment, multi-user, enterprise |\n| **WebSocket** | `--transport ws` | Bun only | Low-latency bidirectional, real-time apps |\n\n### Streamable HTTP\n\nImplements the [MCP Streamable HTTP specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) with a single `/mcp` endpoint for POST (requests), GET (SSE notifications), and DELETE (session termination).\n\n**Dual runtime support:**\n\n- **Bun**: Uses `WebStandardStreamableHTTPServerTransport` with `Bun.serve()` directly — zero Express dependency, maximum performance.\n- **Node.js**: Falls back to `StreamableHTTPServerTransport` with Express. Requires `express` as an optional peer dependency (`npm install express`).\n\nRuntime is auto-detected at startup.\n\n**Session management:**\n\nSessions use **UUID v7** (RFC 9562) — time-ordered and K-sortable, making them ideal for logging, debugging, and database indexing. Sessions are tracked via the `Mcp-Session-Id` header.\n\n**Resumability:**\n\nWhen an EventStore is configured, clients can reconnect and resume receiving messages from where they left off via the `Last-Event-ID` SSE header.\n\n```bash\n# Basic HTTP server\ncloud-fs-mcp s3 s3://my-bucket --transport http --port 3000\n\n# With authentication\ncloud-fs-mcp s3 s3://my-bucket --transport http --port 3000 --auth builtin --auth-issuer https://my-server.example.com\n\n# Production deployment\ncloud-fs-mcp s3 s3://my-bucket \\\n  --transport http --port 3000 --host 0.0.0.0 \\\n  --auth external --auth-jwks-uri https://login.example.com/.well-known/jwks.json \\\n  --cors-origin https://app.example.com \\\n  --rate-limit 60 --rate-limit-burst 10 \\\n  --security-headers \\\n  --request-logging\n```\n\n### WebSocket\n\nBun-native WebSocket transport using `Bun.serve()` with WebSocket upgrade handling. Provides lower latency than HTTP for high-frequency tool invocations.\n\n- JSON-RPC message framing over WebSocket\n- UUID v7 session assigned on upgrade\n- WS ping/pong heartbeat for connection liveness\n\n```bash\ncloud-fs-mcp s3 s3://my-bucket --transport ws --port 3000\n```\n\n---\n\n## Authentication & Authorization\n\nAuthentication is **disabled by default** and only applies to HTTP/WS transports. STDIO mode never requires auth.\n\n### Auth modes\n\n| Mode | Flag | Description |\n|---|---|---|\n| `none` | `--auth none` (default) | No authentication. Suitable for local/trusted networks. |\n| `builtin` | `--auth builtin` | Self-hosted OAuth 2.1 Authorization Server. The MCP server acts as both AS and RS. |\n| `external` | `--auth external` | Validate bearer tokens against an external IdP (Okta, Auth0, Keycloak, Azure AD). |\n\n### Built-in OAuth server (`--auth builtin`)\n\nThe server runs a full OAuth 2.1 Authorization Server using the MCP SDK's `mcpAuthRouter()`:\n\n- **Authorization Code + PKCE** (mandatory) — interactive user consent flow\n- **Dynamic Client Registration** — MCP clients auto-register on first connect\n- **Refresh token rotation** — single-use refresh tokens prevent replay\n- **Metadata discovery** — `/.well-known/oauth-authorization-server` (RFC 8414) and `/.well-known/oauth-protected-resource` (RFC 9728)\n\n```bash\ncloud-fs-mcp s3 s3://my-bucket \\\n  --transport http --port 3000 \\\n  --auth builtin --auth-issuer https://my-server.example.com\n```\n\n### External IdP (`--auth external`)\n\nThe server only validates bearer tokens — it does not issue tokens. Use this when you have an existing identity provider.\n\n- **JWKS validation** — fetches and caches signing keys from your IdP\n- **JWT verification** — checks signature, issuer, audience, expiry\n- **Token introspection** — fallback for opaque tokens\n\n```bash\ncloud-fs-mcp s3 s3://my-bucket \\\n  --transport http --port 3000 \\\n  --auth external \\\n  --auth-jwks-uri https://login.example.com/.well-known/jwks.json \\\n  --auth-audience https://cloud-fs.example.com\n```\n\n### ext-auth: Client Credentials (M2M)\n\nImplements the [MCP Client Credentials extension](https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/draft/oauth-client-credentials.mdx) for machine-to-machine authentication without user interaction. Designed for CI/CD pipelines, background services, and automated workflows.\n\n- **JWT assertion auth** (`private_key_jwt` per RFC 7523) — recommended\n- **Client secret auth** (`client_secret_basic`) — simpler but less secure\n- No user interaction required — tokens granted based on pre-registered client credentials\n\n```bash\ncloud-fs-mcp s3 s3://my-bucket \\\n  --transport http --port 3000 \\\n  --auth builtin --auth-issuer https://my-server.example.com \\\n  --auth-client-credentials\n```\n\n### ext-auth: Enterprise-Managed Authorization (SSO)\n\nImplements the [MCP Enterprise-Managed Authorization extension](https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/draft/enterprise-managed-authorization.mdx) for seamless SSO via your organization's Identity Provider.\n\n**How it works:**\n\n1. User logs in to the MCP Client via the enterprise IdP (OpenID Connect or SAML)\n2. Client exchanges the ID Token for an Identity Assertion JWT Authorization Grant (ID-JAG) via Token Exchange (RFC 8693)\n3. Client presents the ID-JAG to this server's Authorization Server (RFC 7523)\n4. Server validates the ID-JAG and issues an access token\n\n**Benefits:**\n\n- Zero manual authorization per MCP Server — SSO handles everything\n- Enterprise admins control which users/groups can access which MCP servers\n- Granular scope enforcement via IdP policies\n\n```bash\ncloud-fs-mcp s3 s3://my-bucket \\\n  --transport http --port 3000 \\\n  --auth builtin --auth-issuer https://my-server.example.com \\\n  --auth-enterprise-idp https://acme.okta.com\n```\n\n### OAuth Scopes\n\nWhen auth is enabled, tool access is controlled by granular scopes:\n\n| Scope | Tools |\n|---|---|\n| `cloud-fs:read` | `read_file`, `read_text_file`, `read_media_file`, `read_multiple_files`, `read_file_range`, `read_file_chunk`, `get_presigned_url`, `get_object_metadata`, `list_versions`, `get_file_schema`, `summarize_file` |\n| `cloud-fs:write` | `write_file`, `edit_file`, `create_directory`, `set_object_tags`, `restore_version`, `patch_file` |\n| `cloud-fs:delete` | `delete_file` |\n| `cloud-fs:search` | `search_files`, `grep_file`, `grep_files`, `list_directory`, `list_directory_with_sizes`, `directory_tree`, `search_by_tag` |\n| `cloud-fs:shell` | `shell` |\n| `cloud-fs:admin` | All tools + `get_file_info`, `list_allowed_directories` |\n\nWhen `grantedScopes` is set (via OAuth tokens), tools outside the granted scopes are **not registered** — they don't appear in `tools/list` at all, reducing LLM prompt token waste and preventing tool hallucination.\n\nTokens with insufficient scopes receive a clear error response indicating which scope is required.\n\n---\n\n## Production Features\n\n### Health Checks\n\nHTTP/WS transports expose Kubernetes-convention health endpoints:\n\n| Endpoint | Purpose | Success | Failure |\n|---|---|---|---|\n| `/healthz` | Liveness — is the process alive? | `200 OK` always | Process is dead |\n| `/readyz` | Readiness — can it serve traffic? | `200 OK` after VFS hydration | `503` during startup |\n\nConfigure your orchestrator's liveness and readiness probes to use these endpoints.\n\n### Rate Limiting\n\nToken bucket rate limiting protects against abuse. **Disabled by default.**\n\n- **In-memory** — per-IP/per-client counters for single-process deployments\n- **Redis** — distributed rate limiting for multi-instance deployments (uses existing optional `ioredis` peer dep)\n- Returns `429 Too Many Requests` with `Retry-After` header when limits are exceeded\n\n```bash\n# 60 requests/minute with burst of 10\ncloud-fs-mcp s3 s3://my-bucket --transport http \\\n  --rate-limit 60 --rate-limit-burst 10\n```\n\n### CORS\n\nCross-Origin Resource Sharing for browser-based MCP clients:\n\n- Strict origin allowlist — no wildcards in production\n- Exposes `Mcp-Session-Id` and `Mcp-Protocol-Version` headers\n- Localhost auto-allows `*` when `--host 127.0.0.1` (dev convenience)\n\n```bash\ncloud-fs-mcp s3 s3://my-bucket --transport http \\\n  --cors-origin https://app.example.com \\\n  --cors-origin https://staging.example.com\n```\n\n### Structured Request Logging\n\nJSON audit trail to stderr for compliance and debugging:\n\n```json\n{\"ts\":\"2026-05-12T12:00:00Z\",\"sessionId\":\"019...\",\"tool\":\"read_file\",\"user\":\"alice@example.com\",\"latencyMs\":42,\"status\":200}\n```\n\nEnable with `--request-logging`.\n\n### DNS Rebinding Protection\n\nAutomatically applied when binding to localhost addresses. Validates the `Host` header against allowed hostnames to prevent DNS rebinding attacks.\n\n### Security Headers\n\nOpt-in HTTP response hardening via [nosecone](https://github.com/arcjet/arcjet-js/tree/main/nosecone) — a framework-agnostic security headers library. Works with both Bun-native and Node/Express transports.\n\nWhen enabled, every HTTP response includes standard security headers:\n\n- `Content-Security-Policy`\n- `Strict-Transport-Security`\n- `X-Content-Type-Options: nosniff`\n- `X-Frame-Options`\n- `Cross-Origin-Opener-Policy`\n- `Cross-Origin-Resource-Policy`\n- `Referrer-Policy`\n- And more (see [nosecone defaults](https://docs.arcjet.com/nosecone/quick-start))\n\n```bash\n# Enable with defaults\ncloud-fs-mcp s3 s3://my-bucket --transport http --security-headers\n\n# Custom configuration via inline JSON\ncloud-fs-mcp s3 s3://my-bucket --transport http \\\n  --security-headers-config '{\"contentSecurityPolicy\":false}'\n\n# Custom configuration via file\ncloud-fs-mcp s3 s3://my-bucket --transport http \\\n  --security-headers-config-file ./nosecone.json\n```\n\n> **Note:** Requires the `nosecone` peer dependency: `npm install nosecone`\n\n---\n\n## CLI Reference\n\n```\ncloud-fs-mcp <provider> <root-uri> [root-uri...] [options]\n```\n\n### Providers\n\n| Provider | URI format | Description |\n|---|---|---|\n| `s3` | `s3://bucket[/prefix]` | AWS S3, and any S3-compatible endpoint (MinIO, RustFS, Cloudflare R2, Backblaze B2, Wasabi, LocalStack, …) |\n| `azure` | `az://container[/prefix]` | Azure Blob Storage |\n| `gcs` | `gs://bucket[/prefix]` | Google Cloud Storage |\n| `memory` | `mem://name` | In-memory (ephemeral, for demos) |\n| `sqlite` | `sqlite://name` | SQLite (persistent local) |\n\n### Options\n\n#### Transport & Network\n\n| Flag | Default | Description |\n|---|---|---|\n| `--transport <stdio\\|http\\|ws>` | `stdio` | Transport protocol |\n| `--port <number>` | `3000` | Listen port (http/ws only) |\n| `--host <address>` | `127.0.0.1` | Bind address (http/ws only) |\n\n#### Authentication\n\n| Flag | Default | Description |\n|---|---|---|\n| `--auth <none\\|builtin\\|external>` | `none` | Auth mode (http/ws only) |\n| `--auth-issuer <url>` | — | OAuth issuer URL (builtin mode) |\n| `--auth-jwks-uri <url>` | — | JWKS URI (external mode) |\n| `--auth-audience <string>` | — | Expected token audience (external mode) |\n| `--auth-client-credentials` | `false` | Enable Client Credentials ext-auth flow |\n| `--auth-enterprise-idp <url>` | — | Enable Enterprise-Managed Authorization |\n\n#### Production\n\n| Flag | Default | Description |\n|---|---|---|\n| `--cors-origin <origin>` | — | Allowed CORS origin (repeatable) |\n| `--rate-limit <req/min>` | `0` (off) | Rate limit per client |\n| `--rate-limit-burst <n>` | `10` | Burst allowance |\n| `--request-logging` | `false` | Enable structured JSON request logging |\n| `--audit-log` | `false` | Enable tool invocation audit logging to stderr |\n| `--audit-log-file <path>` | — | Write audit log to file (implies `--audit-log`) |\n| `--security-headers` | `false` | Enable security headers via nosecone |\n| `--security-headers-config <json>` | — | Inline JSON config for nosecone |\n| `--security-headers-config-file <path>` | — | Load nosecone config from a JSON file |\n\n#### Storage & Cache\n\n| Flag | Default | Description |\n|---|---|---|\n| `--region <region>` | — | Cloud region (S3, GCS) |\n| `--endpoint <url>` | — | Custom endpoint for S3-compatible backends |\n| `--cache-store <memory\\|fs\\|redis>` | `memory` | Cache backend |\n| `--cache-ttl <seconds>` | `60` | Cache TTL in seconds |\n| `--sync-debounce <ms>` | `2000` | Write flush delay in ms |\n| `--cache-dir <path>` | — | Directory for fs cache store |\n| `--no-cache` | — | Bypass cache entirely (pass-through mode) |\n| `--gcs-endpoint <url>` | — | Custom endpoint for GCS |\n| `--sqlite-db <path>` | — | SQLite database file path |\n| `--ca-file <path>` | — | PEM CA bundle for TLS (S3-compatible + Redis) |\n\n#### Tools\n\n| Flag | Default | Description |\n|---|---|---|\n| `--enable-delete` | `false` | Enable the `delete_file` tool |\n| `--enable-shell` | `false` | Enable the `shell` tool |\n| `--enable-dlp` | `false` | Enable DLP content sanitization (redacts PII/secrets from responses) |\n| `--grep-max-objects <n>` | `1000` | Max objects `grep_files` scans per call |\n| `--seed-demo` | `false` | Seed VFS with sample files for demo |\n\nCredentials are always sourced from SDK credential chains — never CLI flags.\n\n---\n\n## Provider Setup\n\n### AWS S3\n\nCredentials are read from the standard AWS credential chain: `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` env vars, `~/.aws/credentials`, EC2 instance profiles, and so on.\n\n```bash\ncloud-fs-mcp s3 s3://my-bucket --region us-east-1\n```\n\n### S3-compatible storage\n\nAny S3-compatible backend works via `--endpoint`. All use the standard AWS credential chain (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`).\n\n| Provider | `--endpoint` value | Notes |\n|---|---|---|\n| **MinIO** | `http://minio:9000` | Self-hosted; use `--ca-file` for TLS with a private CA |\n| **RustFS** | `http://rustfs:9000` | Rust-native S3-compatible store |\n| **LocalStack** | `http://localhost:4566` | Full AWS emulator for local dev and CI |\n| **Cloudflare R2** | `https://<account-id>.r2.cloudflarestorage.com` | No egress fees; use an R2 API token as the secret key |\n| **Backblaze B2** | `https://s3.<region>.backblazeb2.com` | Use B2 application key ID / key |\n| **Wasabi** | `https://s3.<region>.wasabisys.com` | Compatible, no egress fees |\n| **DigitalOcean Spaces** | `https://<region>.digitaloceanspaces.com` | Use a Spaces access key |\n| **Scaleway** | `https://s3.<region>.scw.cloud` | Use a Scaleway access key |\n| **Ceph RGW** | `http://<rgw-host>:<port>` | Enterprise self-hosted; supports all S3 APIs |\n| **SeaweedFS** | `http://<master>:8333` | High-throughput distributed FS with S3 API |\n| **Garage** | `http://<node>:3900` | Lightweight distributed S3 for homelabs |\n\n```bash\n# MinIO\nexport AWS_ACCESS_KEY_ID=minioadmin\nexport AWS_SECRET_ACCESS_KEY=minioadmin\ncloud-fs-mcp s3 s3://my-bucket --endpoint http://minio:9000\n\n# Cloudflare R2\nexport AWS_ACCESS_KEY_ID=<r2-access-key-id>\nexport AWS_SECRET_ACCESS_KEY=<r2-secret-access-key>\ncloud-fs-mcp s3 s3://my-bucket --endpoint https://<account-id>.r2.cloudflarestorage.com --region auto\n\n# Backblaze B2\nexport AWS_ACCESS_KEY_ID=<b2-key-id>\nexport AWS_SECRET_ACCESS_KEY=<b2-application-key>\ncloud-fs-mcp s3 s3://my-bucket --endpoint https://s3.us-west-004.backblazeb2.com --region us-west-004\n\n# LocalStack\nexport AWS_ACCESS_KEY_ID=test\nexport AWS_SECRET_ACCESS_KEY=test\ncloud-fs-mcp s3 s3://my-bucket --endpoint http://localhost:4566 --region us-east-1\n```\n\n> **TLS with private CA:** For MinIO, RustFS, or Ceph with a self-signed certificate, add `--ca-file /path/to/ca.pem`.\n\n### Azure Blob Storage\n\nUses `DefaultAzureCredential` — works with `AZURE_TENANT_ID` / `AZURE_CLIENT_ID` / `AZURE_CLIENT_SECRET` env vars, managed identity, `az login`, and so on.\n\n```bash\ncloud-fs-mcp azure az://my-container\n```\n\n### Google Cloud Storage\n\nUses Application Default Credentials (ADC). Set `GOOGLE_APPLICATION_CREDENTIALS` or run `gcloud auth application-default login`.\n\n```bash\ncloud-fs-mcp gcs gs://my-bucket\n```\n\n### In-Memory (ephemeral)\n\nZero-config, zero-dependency provider. All data lives in a `Map` and is lost when the process exits.\n\n```bash\ncloud-fs-mcp memory mem://demo --enable-shell\n```\n\n### SQLite (persistent local)\n\nPersistent local storage using WAL mode. Dual-runtime: uses `bun:sqlite` on Bun, `better-sqlite3` on Node.js (install as peer dep: `npm install better-sqlite3`).\n\n```bash\ncloud-fs-mcp sqlite sqlite://my-bucket --sqlite-db /tmp/cloud-fs.db --enable-shell\n```\n\n---\n\n## MCP Client Config\n\n### Claude Desktop\n\n`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"cloud-fs\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@nogoo9/mcp-server-cloud-fs\", \"s3\", \"s3://my-bucket\"]\n    }\n  }\n}\n```\n\n### Claude Code\n\n`.mcp.json` in your project root:\n\n```json\n{\n  \"mcpServers\": {\n    \"cloud-fs\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@nogoo9/mcp-server-cloud-fs\", \"s3\", \"s3://my-bucket\"]\n    }\n  }\n}\n```\n\n### Remote HTTP client\n\n```json\n{\n  \"mcpServers\": {\n    \"cloud-fs\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://cloud-fs.example.com/mcp\"\n    }\n  }\n}\n```\n\n---\n\n## Tool Reference\n\nAll paths are cloud URIs — e.g. `s3://my-bucket/path/to/file.txt`. The server validates every path against the configured root URIs at startup; requests outside allowed roots are rejected.\n\n### Read tools\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `read_file` | `path` | Read a file. Binary → base64; text → UTF-8. |\n| `read_text_file` | `path`, `head?`, `tail?` | Read text file with optional head/tail line limits. |\n| `read_media_file` | `path` | Read image/media as base64 MCP image content block. |\n| `read_multiple_files` | `paths` | Read several files in parallel. |\n| `read_file_range` ✨ | `path`, `offset`, `limit` | Read a 1-based line range with total line count header. |\n| `read_file_chunk` ✨ | `path`, `start_byte`, `end_byte?`, `encoding?` | Read a byte range without downloading the entire file. Max 10MB. |\n\n### Write tools\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `write_file` | `path`, `content` | Write/overwrite a file. Flushed after debounce window. |\n| `edit_file` | `path`, `edits[]`, `dryRun?`, `expected_etag?` | Apply `{ oldText, newText }` edits. Preview with `dryRun`. Optional ETag conflict detection. |\n\n### Directory tools\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `create_directory` | `path` | Create a directory placeholder and parent prefixes. |\n| `list_directory` | `path` | List immediate children (like `ls`). |\n| `list_directory_with_sizes` | `path`, `sortBy?`, `limit?` | List children with sizes. Sort by size or name. |\n| `directory_tree` | `path`, `excludePatterns?` | Recursive directory tree with glob exclusions. |\n\n### Move, Copy & Delete tools\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `move_file` | `source`, `destination` | Move file. Server-side copy + delete for same-bucket. |\n| `copy_file` ✨ | `source`, `destination` | Copy file. Server-side for same-bucket. |\n| `delete_file` ✨ | `path` | Delete file. **Requires `--enable-delete`.** |\n\n### Search tools\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `search_files` | `path`, `pattern`, `excludePatterns?` | Glob-based object key search. |\n| `grep_file` ✨ | `path`, `pattern`, `case_insensitive?` | Regex search in a single file with line numbers. |\n| `grep_files` ✨ | `path`, `pattern`, `glob?`, `case_insensitive?`, `output_mode?`, `max_objects?` | Regex search across all objects under a path. |\n\n### Info tools\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `get_file_info` | `path` | File metadata: size, last-modified, content type. |\n| `list_allowed_directories` | _(none)_ | List configured root URIs. |\n\n> ✨ = Extended tool\n\n### Cloud-native tools ☁️\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `get_presigned_url` ☁️ | `path`, `operation?`, `expires_in?` | Generate a temporary access URL (default: GET, 1 hour). |\n| `get_object_metadata` ☁️ | `path` | Size, content type, last modified, custom metadata, and tags. |\n| `set_object_tags` ☁️ | `path`, `tags` | Replace object tags with key-value pairs. |\n| `search_by_tag` ☁️ | `path`, `tags`, `recursive?` | Find objects matching tag filters (AND logic). |\n| `list_versions` ☁️ | `path`, `max_results?`, `page_token?` | Version history with timestamps, sizes, and markers. |\n| `restore_version` ☁️ | `path`, `version_id` | Restore a previous object version (copies over current). |\n\n> ☁️ = Cloud-native tool (requires provider support)\n\n### AI-native tools 🧠\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `get_file_schema` 🧠 | `path` | Extract structural schema: CSV column names/types/samples, JSON shape, or text line/byte counts. |\n| `summarize_file` 🧠 | `path`, `max_lines?` | Compact head/tail preview with file size, line count, and content type. |\n\n> 🧠 = AI-native tool (reduces LLM context token waste)\n\n### Macro tools 🩹\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `patch_file` 🩹 | `path`, `patch`, `format?`, `expected_etag?` | Apply unified diffs or line-range replacements atomically in a single tool call. |\n\n> 🩹 = Macro tool (combines read + transform + write)\n\n### Shell tool ⚡\n\n| Tool | Parameters | Description |\n|---|---|---|\n| `shell` ⚡ | `command` | Execute POSIX-like commands. Supports pipes, redirects. **Requires `--enable-shell`.** |\n\n**Built-in commands:** `ls`, `cat`, `head`, `tail`, `cp`, `mv`, `rm`, `mkdir`, `touch`, `stat`, `find`, `grep`, `wc`, `du`, `echo`, `tee`, `diff`, `jq`, `cd`\n\n#### Relative paths\n\nAll shell commands (and all other tools) support **relative paths** — you don't need to type the full URI every time. Paths without a scheme prefix (`s3://`, `mem://`, etc.) are resolved relative to the first configured root:\n\n```bash\n# With root s3://my-bucket/data, these are equivalent:\nshell \"cat config.json\"\nshell \"cat s3://my-bucket/data/config.json\"\n\n# Subdirectories work naturally:\nshell \"ls logs/\"\nshell \"cat logs/app.log | grep ERROR\"\n\n# ls with no args lists the root's contents:\nshell \"ls\"\n\n# find with no args searches from the root:\nshell \"find -name '*.json'\"\n```\n\nStandard `.` and `..` are normalized, with `..` traversal blocked at the root boundary for security.\n\n#### Examples\n\n```bash\n# List root contents\nshell \"ls -l\"\n\n# JSON query with jq\nshell \"cat config.json | jq '.database.port'\"\n\n# Search and count\nshell \"grep -i error server.log | wc -l\"\n\n# Write files\nshell \"echo hello world > greeting.txt\"\n\n# Copy and diff\nshell \"cp config.json config.backup.json\"\nshell \"diff config.json config.backup.json\"\n\n# Full URIs still work for cross-root access\nshell \"cat s3://other-bucket/file.txt\"\n```\n\n> ⚡ Requires `--enable-shell`. `rm` and `mv` additionally require `--enable-delete`.\n\n---\n\n## Architecture: Virtual Filesystem (VFS)\n\nAll tool operations are mediated through a **Virtual Filesystem (VFS)** layer inspired by [FUSE](https://en.wikipedia.org/wiki/Filesystem_in_Userspace).\n\n```\n┌─────────────────────────────────────────────────────────┐\n│  MCP Tool Handlers (read, write, list, stat, …)         │\n├─────────────────────────────────────────────────────────┤\n│  VirtualFS                                              │\n│  ┌───────────┐ ┌───────────┐ ┌───────────┐              │\n│  │  Inodes   │ │ DirIndex  │ │ Tombstones│              │\n│  │ (metadata)│ │ (parents) │ │ (deleted) │              │\n│  └─────┬─────┘ └─────┬─────┘ └─────┬─────┘              │\n│        └──────────────┴─────────────┘                   │\n│         ⇣ Overlay (in-memory, persisted to CacheStore)  │\n├─────────────────────────────────────────────────────────┤\n│  CacheStore (Memory / Filesystem / Redis)               │\n├─────────────────────────────────────────────────────────┤\n│  StorageProvider (S3 / Azure Blob / GCS / Memory / SQL) │\n└─────────────────────────────────────────────────────────┘\n```\n\n| Operation | Resolution |\n|---|---|\n| **`get()`** | Cache hit → return. Tombstoned → throw. Else → provider fallback. |\n| **`stat()`** | Inode overlay → cached content size → provider `headObject`. |\n| **`list()`** | Provider listing – tombstones + overlay dirIndex entries. |\n| **`put()`** | Cache set + markDirty + inode update + dirIndex. Immediate visibility. |\n| **`remove()`** | Provider deleteObject + cache evict + tombstone. Immediate invisibility. |\n\nVFS metadata is persisted to the CacheStore under `__vfs__/*` keys. On startup, `VirtualFS.hydrate()` restores state; corrupted data is silently discarded.\n\n---\n\n## Caching\n\n| Backend | Flag | Notes |\n|---|---|---|\n| **Memory** (default) | `--cache-store memory` | In-process, fast, not shared, not persistent. |\n| **Filesystem** | `--cache-store fs --cache-dir <path>` | Survives restarts. |\n| **Redis** | `--cache-store redis` | Shared, persistent. Requires `ioredis` peer dep. `REDIS_URL` env var. Use `rediss://` for TLS. |\n\n**Writes** land in cache immediately (marked dirty), flushed after debounce window (default: 2s). **Graceful shutdown** flushes all dirty entries before exit. **Pass-through mode** (`--no-cache`) sends every operation directly to the provider.\n\n> **⚠️ Redis TLS:** The server warns at startup when `REDIS_URL` uses unencrypted `redis://`. Use `rediss://` for TLS-encrypted connections in production.\n\n### Custom CA Certificates\n\nUse `--ca-file <path>` to supply a PEM CA bundle for S3-compatible endpoints (MinIO, RustFS) and Redis running with a private CA:\n\n```bash\n# S3-compatible with self-signed CA\ncloud-fs-mcp s3 s3://my-bucket \\\n  --endpoint https://minio.internal:9000 \\\n  --ca-file /etc/ssl/certs/my-ca.pem\n\n# Redis with private CA\nREDIS_URL=rediss://redis.internal:6380 \\\ncloud-fs-mcp s3 s3://my-bucket --cache-store redis \\\n  --ca-file /etc/ssl/certs/my-ca.pem\n```\n\nFor runtime-wide CA trust (all providers + Redis), use the standard `NODE_EXTRA_CA_CERTS` env var instead:\n\n```bash\nNODE_EXTRA_CA_CERTS=/etc/ssl/certs/my-ca.pem cloud-fs-mcp s3 s3://my-bucket\n```\n\n---\n\n## Programmatic Usage (npm library)\n\n```ts\nimport {\n  createMcpServer, VirtualFS, MemoryStore,\n  S3Provider, parseUri,\n} from \"@nogoo9/mcp-server-cloud-fs\";\n\nconst roots    = [parseUri(\"s3://my-bucket\")];\nconst provider = new S3Provider({ region: \"us-east-1\" });\nconst cache    = new MemoryStore(provider, { ttlMs: 60_000, syncDebounceMs: 2000 });\nconst vfs      = new VirtualFS(provider, cache);\nawait vfs.hydrate();\n\nconst server = createMcpServer({ vfs, roots });\n```\n\n### Exported API\n\n| Export | Description |\n|---|---|\n| `createMcpServer(ctx)` | Create a configured MCP server instance |\n| `executeShell(command, ctx)` | Run POSIX-like commands against the VFS |\n| `VirtualFS` | FUSE-inspired write-back overlay |\n| `MemoryStore`, `FilesystemStore`, `createRedisStore`, `PassThroughCache` | Cache backends |\n| `S3Provider`, `AzureProvider`, `GcsProvider`, `MemoryProvider`, `SqliteProvider`, `MultiProvider` | Storage providers |\n| `CloudError`, `CloudErrorCode` | Structured cloud-aware error handling |\n| `checkHealth`, `formatHealthReport` | Connection health-check utilities |\n| `AuditLogger`, `StderrAuditSink`, `FileAuditSink` | Tool invocation audit logging |\n| `parseUri`, `toCacheKey`, `resolveToolPath` | Path utilities |\n| `ShellContext`, `ShellCommandHandler` | Shell extension types |\n\n---\n\n## MCP Inspector\n\n```bash\n# Quick demo (no credentials needed)\nbun run inspect:memory\n\n# Custom configuration\nbun run inspect -- s3 s3://my-bucket --region us-east-1 --enable-shell\n```\n\n---\n\n## MCP App: Interactive Shell (xterm.js)\n\nBuild the app: `bun run build:app` → outputs `dist/app/shell-app.html`.\n\nCatppuccin Mocha theme, command history, auto-resize. Renders inside compatible MCP hosts (Claude Desktop) via the MCP Apps extension.\n\n---\n\n## Development & Testing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for full setup instructions.\n\n**AI agent skills** are installed separately after cloning via `bun x skills add semgrep/skills` — see [CONTRIBUTING.md](CONTRIBUTING.md#ai-agent-skills) for details.\n\n### Test tiers\n\n| Tier | Command | Infra? |\n|---|---|---|\n| **Unit** | `bun run test` | No |\n| **E2E (HTTP)** | `bun run test:e2e:http` | No |\n| **E2E (Infra)** | `bun run test:e2e:infra` | Docker |\n| **Integration** | `bun run test:integration` | Docker |\n| **All** | `bun run test:all` | Docker |\n\n### CI pipeline\n\nThe CI workflow runs on every push/PR:\n\n1. **ci** job: lint → typecheck → unit tests (with coverage) → HTTP E2E → build\n2. **e2e** job: full E2E with Docker Compose (MinIO, Redis)\n\nHTTP E2E tests use the in-memory provider and need zero infrastructure, making them fast and reliable for every CI run.\n\n---\n\n## AI Agent Skill\n\n![cloud-fs skill in action](docs/public/images/cloud-fs-claude-demo.svg)\n\nThe `skills/cloud-fs` directory contains an installable AI agent skill that teaches coding assistants (Claude Code, Gemini CLI, etc.) how to use cloud-fs as a POSIX-like virtual filesystem. Install it to give your assistant fluency with cloud storage commands.\n\n### What it provides\n\n- **MCP mode auto-detection** — recognizes `mcp__cloud-fs__*` tools and maps user intents to the right tool calls\n- **Bootstrap flow** — walks the user through first-time setup when the MCP server isn't configured yet\n- **POSIX-to-MCP mapping** — translates shell commands (`ls`, `cat`, `grep`, `find`, `cp`, etc.) into the correct MCP tool calls\n- **Provider credential reference** — AWS, Azure, GCS, MinIO/RustFS, SQLite setup guidance\n- **`.mcp.json` persistence** — offers to save provider configuration so future sessions are pre-wired\n\n### Installation\n\n```bash\n# Claude Code\nclaude mcp add-skill nogoo9/mcp-server-cloud-fs\n\n# skills.sh\nnpx skills add nogoo9/mcp-server-cloud-fs\n\n# or with bun instead\nbun x skills add nogoo9/mcp-server-cloud-fs\n```\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md#ai-agent-skills) for details on the skill system.\n\n---\n\n## Documentation\n\nFull documentation is available at **[nogoo9.github.io/mcp-server-cloud-fs](https://nogoo9.github.io/mcp-server-cloud-fs/)**.\n\n- 📖 Versioned docs for each release (v0.4.0+)\n- 🔄 PR preview docs for open pull requests\n- 🔍 Full-text search, dark mode, responsive design\n- Built with [VitePress](https://vitepress.dev/)\n\nTo run the documentation site locally:\n\n```bash\nbun run docs:dev      # start dev server at http://localhost:5173\nbun run docs:build    # build static site\nbun run docs:preview  # preview production build\n```\n\n---\n\n## License\n\n[PolyForm Shield 1.0.0](LICENSE). Free for any non-competitive use.\n\n---\n\nBuilt with [![Claude](https://img.shields.io/badge/Claude-d97706?logo=anthropic&logoColor=white)](https://claude.ai) [![Gemini](https://img.shields.io/badge/Gemini-8E75FF?logo=googlegemini&logoColor=white)](https://gemini.google.com) [![Antigravity](https://img.shields.io/badge/Antigravity-4285F4?logo=google&logoColor=white)](https://antigravity.google/)\n",
  "bytes": 38974,
  "sha": "3cf913b2fa6b18bfd08a06f7dd169d3821b2310a9c4f05930a49a66fb41540df",
  "repo_slug": "nogoo9/mcp-server-cloud-fs",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_nogoo9_mcp_server_cloud_fs_afcd2344/readme"
}