Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/XxYouDeaDPunKxX/cloudflare-r2-remote-mcp-worker/llms.txt

Use this file to discover all available pages before exploring further.

The R2 MCP Worker runs as a Cloudflare Worker and exposes your R2 object storage to AI clients over the Model Context Protocol. Once deployed, any MCP-compatible client can connect to your /mcp endpoint and interact with R2 through a structured set of tools — all protected by GitHub OAuth when running in production.

Deployment model

The deployed Worker exposes these routes:
/healthz    — liveness and configuration probe
/mcp        — MCP endpoint (protected by OAuth when AUTH_MODE=github)
/authorize  — OAuth authorization redirect
/callback   — OAuth callback
/token      — OAuth token exchange
/register   — OAuth client registration
The Worker requires three platform resources:
ResourcePurpose
R2 bucket (production)Object storage for deployed Workers
R2 bucket (preview)Object storage for local and preview runs
KV namespace (OAUTH_KV)Short-lived OAuth state for callback validation
The preview bucket is used exclusively by npm run dev and Wrangler preview deployments. The production bucket is used by all deployed Workers. Keeping them separate prevents local experiments from touching production data.

Full deployment walkthrough

1
Install dependencies and log in to Wrangler
2
Install project dependencies, then authenticate your local Wrangler CLI against your Cloudflare account:
3
npm install
npx wrangler login
4
Wrangler opens a browser window for OAuth. After completing the flow your credentials are cached locally.
5
Create R2 buckets
6
Create the production bucket:
7
npx wrangler r2 bucket create your-bucket-name
8
Create a preview bucket for local and preview deployments:
9
npx wrangler r2 bucket create your-preview-bucket-name
10
Dashboard path (alternative): Navigate to Cloudflare Dashboard → R2 Object Storage → Create bucket and create both buckets from the UI. Choose the same region for both.
11
Configure wrangler.jsonc
12
Copy the example configuration file and edit it for your deployment:
13
cp wrangler.example.jsonc wrangler.jsonc
14
The full example file (for reference):
15
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "cloudflare-r2-remote-mcp-worker",
  "main": "src/index.ts",
  "compatibility_date": "2026-05-01",
  "compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
  "r2_buckets": [
    {
      "binding": "R2_BUCKET",
      "bucket_name": "example-bucket",
      "preview_bucket_name": "example-bucket-preview"
    }
  ],
  "kv_namespaces": [
    {
      "binding": "OAUTH_KV",
      "id": "00000000000000000000000000000000"
    }
  ],
  "vars": {
    "AUTH_MODE": "github",
    "ALLOWED_GITHUB_LOGINS": "your-github-login",
    "R2_BUCKET_NAME": "example-bucket",
    "R2_ROOT_PREFIX": "",
    "MAX_INLINE_TEXT_BYTES": "262144",
    "MAX_TRANSFER_BYTES": "1048576",
    "MAX_LIST_LIMIT": "100",
    "ENABLE_ACCOUNT_TOOLS": "false",
    "ENABLE_PRESIGN_TOOLS": "false"
  },
  "observability": {
    "enabled": true
  },
  "dev": {
    "port": 8787
  }
}
16
Fields to edit in your copy:
17
  • name — Worker name, used to determine the workers.dev subdomain
  • r2_buckets[0].bucket_name — production bucket name from step 2
  • r2_buckets[0].preview_bucket_name — preview bucket name from step 2
  • vars.R2_BUCKET_NAME — must match r2_buckets[0].bucket_name
  • vars.R2_ROOT_PREFIX — optional prefix to scope all object keys (leave empty for full bucket access)
  • vars.AUTH_MODE"github" for protected deployments, "none" for local dev only
  • vars.ALLOWED_GITHUB_LOGINS — comma-separated list of GitHub usernames allowed to log in
  • Feature flags — ENABLE_ACCOUNT_TOOLS, ENABLE_PRESIGN_TOOLS
  • 18
    wrangler.jsonc is listed in .gitignore and must never be committed. It contains real bucket names and namespace IDs. Similarly, never commit .dev.vars — use wrangler secret put for secrets in production.
    19
    Bind the R2 bucket
    20
    The Worker accesses R2 exclusively through the R2_BUCKET binding. Set both bucket names in wrangler.jsonc:
    21
    "r2_buckets": [
      {
        "binding": "R2_BUCKET",
        "bucket_name": "your-bucket-name",
        "preview_bucket_name": "your-preview-bucket-name"
      }
    ]
    
    22
    All object tools (r2_object_get, r2_object_put, r2_object_list, etc.) route through this binding.
    23
    Configure the OAuth state KV namespace
    24
    Create a KV namespace to store short-lived OAuth state:
    25
    npx wrangler kv namespace create OAUTH_KV
    
    26
    Wrangler prints a namespace ID. Add it to wrangler.jsonc:
    27
    "kv_namespaces": [
      {
        "binding": "OAUTH_KV",
        "id": "your-kv-namespace-id"
      }
    ]
    
    28
    This namespace is only used during the GitHub OAuth callback exchange. It holds transient state values that expire automatically.
    29
    Configure GitHub OAuth
    30
    Public deployments must use AUTH_MODE=github. You need a GitHub OAuth App whose callback URL matches your Worker URL.
    31
    Known subdomain path — if you already know your Workers subdomain:
    32
  • Set name in wrangler.jsonc.
  • Identify your Cloudflare Workers subdomain (visible in Cloudflare Dashboard → Workers & Pages).
  • Your Worker URL will be:
    https://<worker-name>.<account-subdomain>.workers.dev
    
  • Create a GitHub OAuth App with this callback URL:
    https://<worker-name>.<account-subdomain>.workers.dev/callback
    
  • 33
    Unknown subdomain path — if you haven’t deployed yet:
    34
  • Set name in wrangler.jsonc.
  • Deploy once with only non-secret config set (secrets can be empty placeholders for now).
  • Copy the Worker URL printed by Wrangler or shown in Cloudflare Dashboard → Workers & Pages.
  • Create or update your GitHub OAuth App callback:
    https://<actual-worker-url-host>/callback
    
  • Set OAuth secrets (next step).
  • Deploy again.
  • 35
    See GitHub OAuth setup for detailed instructions on creating the OAuth App.
    36
    Set secrets
    37
    Production secrets must be stored with wrangler secret put, not in wrangler.jsonc. Required for AUTH_MODE=github:
    38
    npx wrangler secret put GITHUB_CLIENT_ID -c wrangler.jsonc
    npx wrangler secret put GITHUB_CLIENT_SECRET -c wrangler.jsonc
    npx wrangler secret put COOKIE_ENCRYPTION_KEY -c wrangler.jsonc
    
    39
    For COOKIE_ENCRYPTION_KEY, generate a random high-entropy string of at least 32 characters. On macOS/Linux:
    40
    openssl rand -base64 32
    
    41
    Wrangler will prompt you to paste each secret value. The values are encrypted and stored in Cloudflare’s secrets store — they are never visible after submission.
    42
    Configure optional account tools (read-only)
    43
    Account tools expose read-only Cloudflare R2 admin operations (bucket listing, usage stats). Enable them in wrangler.jsonc:
    44
    "vars": {
      "ENABLE_ACCOUNT_TOOLS": "true",
      "CLOUDFLARE_ACCOUNT_ID": "your-account-id",
      "R2_BUCKET_NAME": "your-bucket-name"
    }
    
    45
    Then set the API token as a secret:
    46
    npx wrangler secret put CLOUDFLARE_API_TOKEN -c wrangler.jsonc
    
    47
    Use the narrowest API token scope that can read the R2 resources required by your deployment. An R2 read-only token is sufficient for account tools.
    48
    Required variables when ENABLE_ACCOUNT_TOOLS=true:
    49
    ENABLE_ACCOUNT_TOOLS=true
    CLOUDFLARE_ACCOUNT_ID=...
    CLOUDFLARE_API_TOKEN=...
    R2_BUCKET_NAME=...
    
    50
    Configure optional presign tools
    51
    Presign tools generate time-limited pre-signed URLs for direct S3-compatible access to R2 objects. Enable them in wrangler.jsonc:
    52
    "vars": {
      "ENABLE_PRESIGN_TOOLS": "true",
      "R2_BUCKET_NAME": "your-bucket-name",
      "R2_S3_REGION": "auto"
    }
    
    53
    Then set the R2 API keys as secrets:
    54
    npx wrangler secret put R2_ACCESS_KEY_ID -c wrangler.jsonc
    npx wrangler secret put R2_SECRET_ACCESS_KEY -c wrangler.jsonc
    
    55
    Required variables when ENABLE_PRESIGN_TOOLS=true:
    56
    ENABLE_PRESIGN_TOOLS=true
    R2_BUCKET_NAME=...
    R2_ACCESS_KEY_ID=...
    R2_SECRET_ACCESS_KEY=...
    R2_S3_REGION=auto
    
    57
    If R2_S3_ENDPOINT is omitted, the Worker derives the endpoint automatically from CLOUDFLARE_ACCOUNT_ID:
    58
    https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com
    
    59
    You can override this by setting R2_S3_ENDPOINT explicitly in vars.
    60
    Verify locally
    61
    Start the local development server:
    62
    npm run dev
    
    63
    Then check the health endpoint:
    64
    http://localhost:8787/healthz
    
    65
    A healthy response looks like:
    66
    {
      "ok": true,
      "bucketAccessible": true,
      "authMode": "none",
      "accountToolsEnabled": false,
      "presignToolsEnabled": false,
      "rootPrefix": "",
      "maxInlineTextBytes": 262144,
      "maxListLimit": 100,
      "maxTransferBytes": 1048576
    }
    
    67
    If bucketAccessible is false, check that the preview bucket name in wrangler.jsonc matches the bucket you created in step 2.
    68
    Deploy to production
    69
    Once local verification passes, deploy the Worker:
    70
    npm run deploy
    
    71
    Wrangler builds and publishes the Worker. Your remote MCP endpoint is:
    72
    https://<worker-name>.<account-subdomain>.workers.dev/mcp
    
    73
    Confirm the deployment by hitting /healthz on the live URL, then proceed to Verify Your Deployment for full end-to-end checks.

    Next steps

    Build docs developers (and LLMs) love