Skip to main content
Glama
ingsamcas

R2 Bucket MCP

by ingsamcas
README.md
# r2-bucket-mcp

Servidor MCP **stdio** para Cursor y otros clientes MCP. Sube archivos locales a **Cloudflare R2** (S3-compatible) sin ejecutar scripts shell. Pensado para APKs de proyectos (`vitalo`, `linkbox`, `nestle`, …) y cualquier otro archivo.

## Qué hace

Expone cinco tools MCP:

| Tool | Uso |
|------|-----|
| `upload_apk` | APKs con key `{project}/{version}/{filename}` |
| `upload_file` | Cualquier archivo con key opcional |
| `get_file` | Descargar por key (URL o guardar local) |
| `list_files` | Listar objetos por prefijo |
| `delete_file` | Borrar objeto por key |

La respuesta incluye `downloadUrl` (URL pública CDN si `R2_PUBLIC_BASE_URL` está configurada, o presigned URL temporal).

## Instalación

```bash
cd /Users/samuelgerardocastrolopez/Desktop/r2-bucket-mcp
npm install
```

## Credenciales R2

Usa las mismas variables que `opencode_whatsapp/.env` (sin copiar secretos al repo):

1. Abre `opencode_whatsapp/.env` en tu máquina.
2. Copia los valores de `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `R2_BUCKET`, `R2_ENDPOINT` (o `R2_ACCOUNT_ID`), y opcionalmente `R2_PUBLIC_BASE_URL`.
3. Para pruebas locales, crea `.env` en este repo desde `.env.example` (nunca lo commitees).

| Variable | Requerida | Descripción |
|----------|-----------|-------------|
| `R2_ACCESS_KEY_ID` | sí | Access key R2 |
| `R2_SECRET_ACCESS_KEY` | sí | Secret key R2 |
| `R2_BUCKET` | sí | Bucket (default: `apks`) |
| `R2_ENDPOINT` | sí* | Endpoint S3-compatible |
| `R2_ACCOUNT_ID` | sí* | Alternativa a endpoint explícito |
| `R2_KEY_PREFIX` | no | Prefijo global opcional |
| `R2_PUBLIC_BASE_URL` | no | CDN pública; si falta, presigned URL |
| `R2_PRESIGNED_TTL_SECS` | no | Default: 604800 (7 días) |
| `R2_MAX_FILE_BYTES` | no | Límite validación MCP (default: 500 MB) |

\* Al menos uno de `R2_ENDPOINT` o `R2_ACCOUNT_ID`.

## Prueba manual

Arranque stdio (proceso queda esperando; Ctrl+C para salir):

```bash
node index.js
# stderr: [r2-bucket-mcp] ready (stdio)
```

Smoke test con credenciales en `.env` local (sube un `.smoke-test.txt` temporal):

```bash
npm run smoke
```

## Registrar en Cursor

**Settings → MCP** o edita `~/.cursor/mcp.json`.

Usa la ruta absoluta de `node` (`which node`). Ejemplo:

```json
{
  "mcpServers": {
    "r2-bucket": {
      "type": "stdio",
      "command": "/Users/samuelgerardocastrolopez/.nvm/versions/node/v22.17.0/bin/node",
      "args": [
        "/Users/samuelgerardocastrolopez/Desktop/r2-bucket-mcp/index.js"
      ],
      "env": {
        "R2_ACCESS_KEY_ID": "PEGAR_ACCESS_KEY",
        "R2_SECRET_ACCESS_KEY": "PEGAR_SECRET_KEY",
        "R2_BUCKET": "apks",
        "R2_ENDPOINT": "https://<account-id>.r2.cloudflarestorage.com",
        "R2_PUBLIC_BASE_URL": "https://cdn.tudominio.com"
      }
    }
  }
}
```

Reinicia Cursor o recarga servidores MCP tras cambiar `mcp.json`.

## Uso desde agentes

- **APKs:** preferir `upload_apk` con `project`, `version` y `filePath` absoluto.
- **Otros archivos:** `upload_file` con `filePath` y opcionalmente `key`, `prefix`, `contentType`.
- **Listar:** `list_files` con `prefix` opcional (ej. `vitalo/`).
- **Descargar:** `get_file` con `key`; opcional `filePath` absoluto para guardar en disco.
- **Borrar:** `delete_file` con `key` completa (ej. `vitalo/2.1.0/app-release.apk`).

Ejemplo de key generada por `upload_apk`:

```
vitalo/2.1.0/app-release.apk
```

Respuesta JSON (campo principal para compartir el enlace):

```json
{
  "ok": true,
  "bucket": "apks",
  "key": "vitalo/2.1.0/app-release.apk",
  "size": 12345678,
  "contentType": "application/vnd.android.package-archive",
  "downloadUrl": "https://cdn.tudominio.com/vitalo/2.1.0/app-release.apk",
  "publicUrl": "https://cdn.tudominio.com/vitalo/2.1.0/app-release.apk",
  "presignedUrl": null
}
```

Si no hay `R2_PUBLIC_BASE_URL`, `downloadUrl` será una presigned URL y `publicUrl` será `null`.

## Integración SDK

Con un agente SDK local y `settingSources: ['user']`, el agente carga el mismo MCP definido en `~/.cursor/mcp.json`. También puedes pasar `mcpServers` inline en la config del agente con las mismas credenciales en `env`.

## Tools

### `upload_file`

| Parámetro | Requerido | Descripción |
|-----------|-----------|-------------|
| `filePath` | sí | Ruta absoluta al archivo local |
| `key` | no | Clave en el bucket (default: basename) |
| `prefix` | no | Prefijo override (sin `R2_KEY_PREFIX` global) |
| `contentType` | no | MIME explícito |

### `upload_apk`

| Parámetro | Requerido | Descripción |
|-----------|-----------|-------------|
| `filePath` | sí | Ruta absoluta al APK |
| `project` | sí | Alias (`vitalo`, `linkbox`, …) |
| `version` | sí | Versión (`2.1.0`) |
| `filename` | no | Default: `app-release.apk` |

### `get_file`

| Parámetro | Requerido | Descripción |
|-----------|-----------|-------------|
| `key` | sí | Clave del objeto (ej. `vitalo/2.1.0/app-release.apk`) |
| `filePath` | no | Ruta absoluta local para guardar; sin ella solo devuelve URLs |

### `list_files`

| Parámetro | Requerido | Descripción |
|-----------|-----------|-------------|
| `prefix` | no | Filtro de prefijo (ej. `vitalo/`, `vitalo/2.1.0/`) |
| `maxKeys` | no | Máximo por página (default: 100, max: 1000) |
| `continuationToken` | no | Token de paginación de una respuesta anterior |

### `delete_file`

| Parámetro | Requerido | Descripción |
|-----------|-----------|-------------|
| `key` | sí | Clave del objeto (ej. `vitalo/2.1.0/app-release.apk`) |

TDQS

A4/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: delete, get, list, upload specifically for APKs, and general upload. No ambiguity between operations.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (delete_file, get_file, list_files, upload_apk, upload_file).

Tool Count5/5

Five tools cover the essential CRUD operations for interacting with an R2 bucket: get, delete, list, upload general, and upload for APKs. This is well-scoped.

Completeness5/5

The tool set covers the core lifecycle for objects in a bucket: listing, retrieving, deleting, and uploading (with a specialized variant for APKs). No obvious gaps for the stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues