Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Proton Drive

БесплатноПоддерживается

MCP server and CLI that gives Claude full access to Proton Drive — upload, download, share, and manage your end-to-end encrypted files without leaving the conve

GitHubEmbed

Описание

MCP server and CLI that gives Claude full access to Proton Drive — upload, download, share, and manage your end-to-end encrypted files without leaving the conversation.

README

  ____  ____   ___ _____ ___  _   _   ____  ____  _____     _______ 
 |  _ \|  _ \ / _ \_   _/ _ \| \ | | |  _ \|  _ \|_ _\ \   / / ____|
 | |_) | |_) | | | || || | | |  \| | | | | | |_) || | \ \ / /|  _|  
 |  __/|  _ <| |_| || || |_| | |\  | | |_| |  _ < | |  \ V / | |___ 
 |_|   |_| \_\\___/ |_| \___/|_| \_| |____/|_| \_\___|  \_/  |_____|
  MCP server and CLI · Full Proton Drive control for Claude

Unofficial community project, not affiliated with or endorsed by Proton AG. Proton and Proton Drive are trademarks of Proton AG. This server only drives the official Proton Drive CLI and never handles your password or session. See the threat model for what it protects and what reaches your AI provider.

Give Claude Desktop (or any MCP client) full access to your Proton Drive and Proton Photos: list folders, upload and download files, invite collaborators, manage sharing, handle trash, and manage photo albums — all with end-to-end encryption intact. The same capabilities are available as a full CLI for scripting, backups, and cron.

Related projects: the same author's Proton Mail Bridge MCP server handles Proton Mail. It is a separate server on purpose: mail and Drive need different permissions, so you can grant a model one without the other.

Quick start (60 seconds)

  1. Install the official Proton Drive CLI, then sign in once: proton-drive auth login.
  2. Connect Claude Desktop, either way:
    • Bundle: install proton-drive-mcp-<version>.mcpb from the latest release and set proton-drive CLI path to the output of which proton-drive.
    • Global install: npm install -g proton-drive-mcp, then proton-drive-cli doctor, then proton-drive-cli setup-claude-desktop --write. (setup-claude-desktop refuses to run from a temporary npx cache, so install globally first.) Fully quit and restart Claude Desktop afterwards.
    • Claude Code: claude mcp add --env PROTON_DRIVE_BIN="$(which proton-drive)" proton-drive -- npx -y proton-drive-mcp
  3. Try these prompts:
    • "Find files named invoice in my Drive." (drive_search)
    • "What is using my Drive space?" (drive_usage)
    • "Find duplicate files in my Drive." (drive_find_duplicates)
    • "Who has access to my shared folders?" (drive_sharing_audit)
    • "Tidy up /Downloads, show me a plan first." (drive_bulk_move / drive_bulk_trash preview first, nothing changes until you confirm)
  4. Sensitive files? Start read-only and confined: PROTON_DRIVE_MODE=readonly and PROTON_DRIVE_REMOTE_ROOTS=/my-files/<folder>, plus an audit log (guard layer, secure setup).
  5. Optional: PROTON_DRIVE_INDEX=1 keeps a plaintext local copy of file names so searches are instant after a restart (details); PROTON_DRIVE_TOOL_TIER=core exposes a smaller tool set.

Compatibility

Status
Proton Drive CLI Built and live-tested against 0.8.0 (all 32 scriptable commands covered). Other versions are untested: run proton-drive-cli doctor after upgrading the CLI.
Node.js 22 or newer
macOS Live-tested. Built-in Vision OCR.
Linux The test suite runs on Ubuntu in CI; not live-tested against a real account.
Windows Not supported

Recipes

Find my scanned documents

Searching by name (drive_search) will not find a scan called IMG_0042.jpg. Search by content instead:

  1. Set PROTON_DRIVE_OCR=1 and PROTON_DRIVE_CONTENT_INDEX=1 in the server's environment and restart it. Both are off by default.
  2. Ask: "Index my /my-files/Scans folder." Claude calls drive_content_index with that path. If the result says partial: true, it calls again to continue.
  3. Ask: "Find the scan that mentions my 2023 tax return." Claude calls drive_search_content.

Honest limits: on macOS the OCR helper is compiled the first time it is needed, a one-time wait of about 30 s (the server warms it in the background shortly after start). OCR makes mistakes, especially on handwriting, low-resolution photos and unusual layouts, so a document can be missed or matched on a wrong word; open the file to check. OCR runs one file at a time, so a big folder of scans takes a while. The index covers only the folders you indexed and reflects the last update. Details: OCR for scans, Content search.

Audit who can see my files

Ask: "Who has access to my shared folders?" and then "Which public links expire soon or never expire?"

  • drive_sharing_audit lists public links (role, expiry, password), invitees and pending invitations, with risk flags such as public-link-no-expiry, public-link-editor and external-invitee.
  • drive_share_expiry_report lists public links with the time left, soonest first (withinDays sets what counts as soon).

Both only read; they change nothing, and link URLs are left out of the results. Each checks at most 100 shared items, so on a big drive point it at one folder at a time. To act on a finding, drive_share_remove_url or drive_share_revoke change sharing; they ask for confirmation.

Tidy a folder safely

Ask: "Move all the PDFs in /Downloads into /Documents/Inbox. Show me the plan first."

  1. drive_bulk_move (or drive_bulk_trash for clean-up) without confirmed returns a plan and any problems and changes nothing.
  2. Read the plan. If it is right, say so, and Claude repeats the call with confirmed=true. It applies only if there are no problems.
  3. Trash is reversible: drive_restore brings an item back (drive_list_trash shows what is there). drive_empty_trash and drive_delete are permanent, so do not ask for those during a tidy-up.

Each call handles up to 200 items. For a first attempt on important data, use the guard layer (PROTON_DRIVE_REMOTE_ROOTS limits the folders Claude can touch).


Why this, and not just the Proton Drive CLI?

For syncing, backups and cron jobs, use the official CLI directly: it is simpler and that is what it is for. This project does not replace it; it needs it, and wraps it so an AI assistant can drive it. It is worth using when you want to work with your Drive by conversation:

  • Things the CLI does not have (it has no search, recursive listing, usage or content-reading commands, and Drive's end-to-end encryption rules out server-side search): drive_search, drive_tree, drive_usage, drive_find_duplicates (verified by sha256), drive_sharing_audit, drive_read_content, drive_sync_plan. They run locally on your computer, so encryption stays intact.
  • Safe changes by an AI: destructive or outward-facing actions need explicit confirmation, bulk move/trash is two steps (plan first, then apply), trash is reversible, and the duplicate finder never deletes anything. A bare CLI assumes you know exactly what you are doing.
  • Rough edges smoothed over: the CLI reports some per-item failures with exit code 0, returns lists in random order, and can fail with database is locked under parallel calls. The server checks per-item results, sorts and paginates lists, and retries read-only calls.

What to expect: search matches names, sizes and dates, not the text of every file (you read one file at a time); the first walk of a large drive takes minutes unless you enable the opt-in persistent index; and this is an independent project, not an official Proton product.


What you get

  • Claude manages your Proton Drive — list, upload, download, move, share, trash, restore
  • Proton Photos album management — list albums, create/delete albums, add and remove photos
  • Companion CLI — 45 of the 54 operations, scriptable and pipeable, works in cron and shell scripts (the two sync-folder tools, drive_read_file and drive_write_file, drive_audit_log and the newer drive_read_many, drive_share_expiry_report, drive_recent_changes, drive_content_index, drive_search_content and drive_refresh_index are MCP-only)
  • Full Proton Drive CLI command coverage — all 32 scriptable commands of CLI 0.8.0 have a matching tool (checked against the CLI's own help; auth login is the one command excluded, since it's an interactive browser flow). Not every optional flag is exposed: sharing invite --include-node-name is deliberately off (it would put the file name in the invitation email in clear text) and the inherited invite role is not offered; commands that accept several paths run one path per call except bulk move and bulk trash
  • Zero credential exposure — auth is handled entirely by the official Proton Drive CLI; this MCP never touches your password or session token
  • Shell injection safe — all CLI calls pass discrete argument arrays to spawn (no shell), never string interpolation
  • Privacy-native — end-to-end encryption is handled by Proton's own CLI; this server is just a thin MCP wrapper

Privacy model

Your files travel: Proton Drive (cloud, E2E encrypted) → Proton Drive CLI (local, decrypts) → this MCP server (local) → your AI client.

The Proton Drive CLI handles all cryptography locally. This MCP server calls the CLI as a subprocess and forwards results — it never receives your password, never stores credentials, and never touches the raw encrypted data. Authentication state lives in your OS keychain (macOS Keychain, Linux libsecret; the official CLI also uses Windows Credential Manager on Windows, which this project does not support), managed exclusively by the official Proton CLI.

If you use Claude Desktop with the default Anthropic API, file content you ask Claude to act on is sent to Anthropic per their privacy policy.


Prerequisites

1. Proton Drive CLI — download from proton.me/download/drive/cli and add to your PATH.

2. Authenticate the CLI — run once in your terminal:

proton-drive auth login

This opens a browser for Proton's standard sign-in flow. Credentials are stored in your OS keychain — not on disk, not in config files.

3. Node.js 22 or later — node --version to check.


Install

Via npx (no install needed):

# Used directly in Claude Desktop config — no global install required
npx -y proton-drive-mcp

Global install:

npm install -g proton-drive-mcp

Connect to Claude Desktop

Add to your claude_desktop_config.json:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows (informational only, this project does not support Windows): %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "proton-drive-mcp": {
      "command": "npx",
      "args": ["-y", "proton-drive-mcp"],
      "env": { "PROTON_DRIVE_BIN": "/absolute/path/to/proton-drive" }
    }
  }
}

Claude Desktop starts servers with a minimal PATH, so a proton-drive in ~/.local/bin is usually not found. Set PROTON_DRIVE_BIN to the output of which proton-drive (the default install location is ~/.local/bin/proton-drive, written out in full, e.g. /Users/you/.local/bin/proton-drive). If npx itself is not found, use its absolute path as command (which npx).

Restart Claude Desktop. Check + → Connectors → proton-drive-mcp to confirm the server is connected.

Tip: Make sure proton-drive auth login has been run at least once before starting Claude Desktop.

One-click install (MCPB bundle)

Instead of editing JSON, download proton-drive-mcp-<version>.mcpb from the latest GitHub release and open it (or drag it into Settings → Extensions in Claude Desktop). In the extension settings, set proton-drive CLI path to the output of which proton-drive (usually ~/.local/bin/proton-drive); optionally set the Proton Drive sync folder to enable drive_read_file / drive_write_file, and the Persistent search index switch (off by default; it stores file names in plain text on this computer, see Persistent index). You still need the official proton-drive CLI installed and proton-drive auth login done once.

If installed globally

{
  "mcpServers": {
    "proton-drive-mcp": {
      "command": "proton-drive-mcp"
    }
  }
}

Setup and diagnostics

Two commands of the companion CLI help when Claude Desktop reports "proton-drive CLI not found" (it starts servers with a minimal PATH):

# Read-only checks: Node >= 22, proton-drive CLI + version, auth, PROTON_DRIVE_SYNC_PATH, your Claude Desktop entry
proton-drive-cli doctor [--json] [--config <path>]

# Dry run: prints the entry it would add and the target file, changes nothing
proton-drive-cli setup-claude-desktop [--config <path>] [--sync-path <dir>]

# Apply it (timestamped backup first; only mcpServers["proton-drive-mcp"] is touched)
proton-drive-cli setup-claude-desktop --sync-path "$HOME/Proton Drive" --write

doctor exits 1 if any check fails (warnings do not fail). It only ever reports on the proton-drive-mcp entry of the config, never on other servers. setup-claude-desktop writes the absolute path of the running node, of this package's dist/index.js, and of the resolved proton-drive binary (PROTON_DRIVE_BIN). It refuses to run if the CLI cannot be found, the config file is not valid JSON, or the package is running from a temporary npx cache (install it first with npm install -g proton-drive-mcp). The entry pins the current node binary, so re-run it after switching Node versions (e.g. with nvm). Re-running with unchanged settings leaves the file alone; otherwise the file is replaced atomically and a timestamped .bak-… copy is kept.

The default config location is per OS (macOS ~/Library/Application Support/Claude/, Windows %APPDATA%\Claude\, Linux $XDG_CONFIG_HOME or ~/.config/Claude/); use --config or the CLAUDE_DESKTOP_CONFIG environment variable to point elsewhere. On Windows the CLI lookup honours PATHEXT.

Claude Desktop only reads its config at startup: fully quit and restart it afterwards (closing the window is not enough).


Try it: example Claude prompts

Backup a build artifact

"Upload ./dist/app-v2.zip to /my-files/Releases and tell me if it succeeded."

Morning file triage

"List everything in /my-files. Tell me what's larger than 10MB and what was modified most recently."

Share a folder with a colleague

"Share /my-files/Q2-Reports with [email protected] as editor. Add a message: 'Please review before Friday.'"

Offboarding

"Revoke [email protected]'s access from /my-files/Projects and /shared/Design. Confirm when done."

Automated download

"Download /my-files/contracts/nda-2026.pdf to ~/Documents/Legal/."

Trash cleanup

"List what's in the trash and empty it once I confirm."


CLI

proton-drive-cli <command> [args]

Auth & info

proton-drive-cli auth status          # probes /my-files; the CLI has no dedicated status command
proton-drive-cli auth logout          # log out (clears OS keychain session)
proton-drive-cli version              # CLI and SDK version

Files & folders

proton-drive-cli list /my-files
proton-drive-cli list /my-files/Reports
proton-drive-cli info /my-files/report.pdf       # full metadata, incl. revision details
proton-drive-cli read /my-files/notes.md --max-chars 5000   # text of a file, paged with --offset

proton-drive-cli mkdir /my-files/NewFolder

proton-drive-cli upload ./report.pdf /my-files/Reports
proton-drive-cli upload ./dist /my-files/Releases --file-conflict replace --folder-conflict merge

proton-drive-cli download /my-files/report.pdf ./local/report.pdf
proton-drive-cli download /my-files/Reports ./local/Reports --file-conflict rename --folder-conflict merge

proton-drive-cli rename /my-files/old-name.pdf new-name.pdf   # in place, no move
proton-drive-cli move /my-files/old-name.pdf /my-files/new-name.pdf
proton-drive-cli copy /my-files/report.pdf /my-files/Archive
proton-drive-cli delete /trash/obsolete-draft.pdf --confirm   # only works on items already in trash

# Machine-readable output (pipe-friendly)
proton-drive-cli list /my-files --json | jq '.[].name'

Sharing

proton-drive-cli share status /my-files/Reports
proton-drive-cli share invite /my-files/Reports [email protected] editor
proton-drive-cli share invite /my-files/Reports [email protected] viewer --message "FYI"
proton-drive-cli share revoke /my-files/Reports [email protected]
proton-drive-cli share remove-all /my-files/Reports --confirm   # strip every member + pending invite

proton-drive-cli share set-url /my-files/Reports --role viewer --expiration 2026-06-06
proton-drive-cli share remove-url /my-files/Reports

Trash

proton-drive-cli trash /my-files/old-draft.pdf        # move to trash
proton-drive-cli trash list                            # see what's in trash
proton-drive-cli restore /my-files/old-draft.pdf       # restore from trash
proton-drive-cli trash empty --confirm                  # permanently delete all trashed items

Search, analytics and cleanup

drive_search · drive_tree · drive_usage · drive_find_duplicates · drive_sharing_audit · drive_sync_plan · drive_bulk_move · drive_bulk_trash

proton-drive-cli tree /my-files --depth 2
proton-drive-cli search /my-files --ext pdf --min-size 1000000
proton-drive-cli usage /my-files --top 20 --older-than 365
proton-drive-cli duplicates /my-files --min-size 1000000 [--verify]
proton-drive-cli share audit /my-files
proton-drive-cli sync-plan ./local /my-files/backup --direction up
proton-drive-cli bulk-move /my-files/Archive /my-files/a.pdf /my-files/b.pdf          # plan only
proton-drive-cli bulk-trash /my-files/old1.txt /my-files/old2.txt --confirm           # apply
proton-drive-cli index status                                                         # persistent index: enabled?, path, size, age, entries
proton-drive-cli index clear                                                          # delete the saved index file
  • The first walk of a large drive can take minutes (measured about 21 s per 1,200 files at the default concurrency (12); about 25 s at concurrency 8). drive_search, drive_tree and drive_usage stop waiting after 25 s (PROTON_DRIVE_WALK_BUDGET_MS, 0 = never) and return what was listed so far with partial: true, continuing: true (the walk is still running) and a note; the same walk keeps running in the background, so repeating the call returns the full result from cache. drive_find_duplicates, drive_sharing_audit and drive_sync_plan always wait for the complete walk. Later calls reuse a 5-minute in-memory cache; refresh bypasses it. With the opt-in persistent index, a saved copy up to 24 h old can answer first (marked stale: true).
  • Walks skip .git and node_modules by default.
  • With PROTON_DRIVE_INDEX=1, results may come from a saved index (stale: true = served from the saved index, not a walk made now) while a refresh runs; repeat the call or pass refresh: true for a fresh read. On a huge drive drive_refresh_index refreshes the index in resumable slices. Off by default, see Persistent index.
  • Read-only tools (drive_search, drive_tree, drive_usage, drive_find_duplicates, drive_sharing_audit, drive_share_expiry_report, drive_recent_changes, drive_sync_plan) change nothing. drive_bulk_move and drive_bulk_trash are two-step: call without confirmed for the plan, then with confirmed: true to apply. Bulk trash is reversible with drive_restore.
  • Duplicate detection uses the sha1 the uploader claimed, which is unverified. verify: true downloads the candidates and hashes them.
  • The sharing audit flags an invitee as external when the address is outside Proton domains, so Proton users on a custom domain are over-flagged.
  • Sizes are sums of file sizes, not your account quota.
  • drive_usage trash stats always make one uncached /trash listing (~2.5 s), even when the walk is cached.

Persistent index (opt-in)

By default every new server process (each Claude Desktop session) walks the drive again on the first drive_search, drive_tree, drive_usage or drive_find_duplicates: about 21 s per 1,200 files at the default concurrency (12), minutes on big drives. Set PROTON_DRIVE_INDEX=1 to keep completed walks on disk and answer instantly after a restart.

Privacy: this is off by default. Your Drive is end-to-end encrypted, but the index is a plaintext copy of file and folder names, paths, sizes, dates and claimed sha1 hashes on your local disk. Anyone who can read your user account's files (or your backups) can read it. Enable it only on a machine you trust.

  • What is stored: the node list of up to 8 recent walks under /my-files (a failed walk or a drive_tree that stops at its depth limit is never saved; an unfinished incremental refresh saves its progress and is marked as partial, see Keeping the index fresh on huge drives), the time each folder was last listed, plus a fingerprint of your account's Drive root. No file contents, no credentials, no tokens.
  • Where: PROTON_DRIVE_INDEX_DIR if set; otherwise ~/Library/Caches/proton-drive-mcp (macOS) or $XDG_CACHE_HOME/proton-drive-mcp / ~/.cache/proton-drive-mcp (Linux). One file, walk-index.json, mode 0600 in a 0700 directory, written atomically. Use a dedicated directory: a pre-existing directory with group/other access (or owned by someone else) is refused with one warning and never chmodded; a missing one is created 0700. A symlinked directory or file is refused. A saved file with loose permissions, another owner, a future timestamp, or above 200 MB is ignored. Not written above 200 MB.
  • Account check: before any saved data is served, one list /my-files (~2 s) confirms it belongs to the account that is logged in now; if the check fails (network, rate limit) nothing is served from disk for that call and the file is kept; a proven account mismatch deletes it. Either way the drive is walked fresh.
  • Freshness: data up to PROTON_DRIVE_INDEX_MAX_AGE_H hours old (default 24; 0 = never use saved data) is returned immediately with stale: true (and refreshing: true while one background walk replaces it); a repeated call then returns the fresh walk. A failed or incomplete background walk is not retried for 5 minutes within the same server process (PROTON_DRIVE_INDEX_REFRESH_COOLDOWN_MS); a new process tries once again. The saved data is account-checked first (see above). Data older than that, and a tree from an unfinished refresh, are refreshed in place rather than walked from scratch (see the next section). drive_sync_plan, drive_find_duplicates, the sharing audit and drive_recent_changes never serve saved data; with the index on they only reuse saved folder listings read less than 5 minutes ago (the memory-cache TTL). refresh: true always does a blocking full fresh walk. Writes made through this server drop the affected entries from memory and disk.
  • Change snapshots: drive_recent_changes with snapshot stores a second plaintext file, changes-snapshot.json, in the same directory under the same rules (see Recent changes); it is only written when you ask for snapshot: "save", and index clear removes it as well.
  • Read-only directory: an index in a directory (or file) you cannot write to is ignored, because it could not be kept current after the server's own writes.
  • Depth-limited requests: drive_tree with a depth (and drive_search/drive_usage of a subfolder) is answered from a complete saved full walk that covers it and is within the max age, with its age in ageMs; it is not refreshed in the background on its own (refresh the full walk instead). A tree from an unfinished refresh does not answer it; the request walks live.
  • Limits: changes made by other clients or processes are not seen until the data is refreshed.
  • Check or remove it: proton-drive-cli index status and proton-drive-cli index clear (or just delete the file). In the MCPB bundle, the Persistent search index setting is the opt-in.

Keeping the index fresh on huge drives

Folder listings cost about 2 s each, so a full re-walk of a drive with hundreds of thousands of files takes hours. With PROTON_DRIVE_INDEX=1 the saved index is therefore refreshed incrementally, in slices that you can repeat until it is done:

  • What is remembered: for every folder, when its listing was last read (listed in walk-index.json, folder path to a timestamp; the same plaintext privacy trade-off as the names and paths next to it, removed by index clear). A folder with no timestamp was never listed.
  • The rule: a listing younger than PROTON_DRIVE_INDEX_FOLDER_MAX_AGE_H (default 24 hours; 0 disables reuse, which brings back full re-walks) is reused; folders with older or no listings are listed again, oldest first, until the time budget is used. Every call saves its progress, also when it stops early, so repeated calls converge. Whatever was not listed again keeps its old entries (nothing is deleted from a folder that was not re-listed); removals are only detected in folders that were re-listed, and a deleted, moved or renamed folder takes all its cached descendants with it. A renamed or moved folder is listed again at its new path, and an item that appears in a new folder is dropped from its old location even when the old folder's listing is reused.
  • What a partial result says: partial: true, continuing: true, complete: false, plus foldersRefreshed (listed in this call), foldersReused, foldersRemaining (still older than the allowed age or never listed; they are also in skipped) and oldestListingAgeMs (the age of the oldest listing the result is built from, also ageMs). A tree is only reported complete when every folder was listed within the allowed age.
  • drive_refresh_index (path default /my-files, timeBudgetMs default 25000, max 120000, maxAgeHours default from the environment, changes) runs one slice and returns those numbers plus etaCalls (an estimate of the calls still needed at this pace; folders found below new folders can raise it) and saved. With changes: true it also returns changes: {added, removed, modified, samples} (up to 50 sample paths) for the folders it re-listed, found by comparing each fresh listing with the previous saved one; a folder listed for the first time counts all its entries as added. Needs PROTON_DRIVE_INDEX=1 (otherwise it answers with how to enable it); it honours PROTON_DRIVE_REMOTE_ROOTS like the other walk tools and works in readonly mode (it changes only the local index file). A scheduled task can call it repeatedly; a normal drive_search, drive_tree or drive_usage on an old index also continues the refresh within its 25 s budget.
  • The other walk users: drive_content_index update asks for listings no older than one hour (PROTON_DRIVE_CONTENT_INDEX_LISTING_MAX_AGE_MIN) and reuses the saved listings for that. drive_recent_changes, drive_sync_plan, drive_find_duplicates and the sharing audit never read the saved index (they must see the live drive) and walk as before; refresh: true is a full re-walk for everybody.
  • The time budget: no new folder listing starts after about 70% of timeBudgetMs, because listings already under way are awaited; if they still run past the budget the result says by how much (budgetOverrunMs).
  • If the account cannot be verified (rate limit, network) a refresh stops with "could not verify the account, try again" and leaves the saved progress untouched; only a real account change starts over.
  • What this cannot see: the Drive listing has no usable change signal for a folder. A folder's modification time does not change when something inside it changes, so refresh is age-based and a change below a reused listing stays unseen until that listing ages out. A folder's modification time stays at its creation time when files are added, renamed or removed inside it or deeper (measured against the live Drive on 2026-11-01: no change in any listed field after a direct or a nested add, rename or trash, checked up to several minutes later), so an unchanged folder cannot be recognised and skipped. The only rule is the age: changes below a folder whose listing is within the allowed age are not seen until it ages out. Lower maxAgeHours (or use refresh: true) when you need a fresher answer.
  • Limits: every checkpoint rewrites the whole index file, which is capped at 200 MB (roughly 300,000 to 400,000 entries); a larger drive cannot be saved and drive_refresh_index reports saved: false. A write made through this server (upload, move, trash, rename) forgets only what it touched: a written file is dropped, and the listing times of its parent folder (and of a written folder and everything below it) are cleared, so the next slice lists just those folders again; the rest of the saved tree is kept, and changes: true then reports only the real difference. Run one version at a time: an index written by this version (file version 2) is not understood by 1.7.x, which reads it as no index, its own invalidation after a write does nothing to it, and it may overwrite the saved progress; this version still reads 1.7's version 1 files. Likewise one refresh at a time per folder tree is sensible: two server processes refreshing the same index keep the last writer's file.

Photos

proton-drive-cli album list
proton-drive-cli album create "Summer 2026"
proton-drive-cli album update /albums/Summer2026 --name "Summer Trip"
proton-drive-cli album add-photo /albums/Summer2026 /photos/IMG_001.jpg

proton-drive-cli photo timeline
proton-drive-cli photo download /photos/IMG_001.jpg ./local/photos --conflict rename
proton-drive-cli photo upload ./camera-roll --conflict skip

Pipe and script

# Backup build output after CI
proton-drive-cli upload ./dist /my-files/Releases/$(date +%Y-%m-%d) --file-conflict rename --folder-conflict rename

# Download all contracts for audit
proton-drive-cli download /my-files/Contracts ./audit/contracts

# Nightly backup via cron
0 2 * * * proton-drive-cli upload ~/Documents /my-files/Backups/$(date +%Y-%m-%d) --file-conflict skip --folder-conflict skip

# Check who has access before a team change
proton-drive-cli share status /my-files/Projects

Prompts

The server offers four MCP prompts (also declared in the MCPB manifest): organise-folder (path), find-files (description), storage-audit and sharing-audit. In Claude Code they are listed as /servername:promptname (MCP), and /mcp__servername__promptname also runs them. Other clients show them as prompts. A prompt is hidden when a tool it needs is outside the active tool tier: with PROTON_DRIVE_TOOL_TIER=core only find-files is offered.


Tool surface

Auth

drive_auth_status · drive_auth_logout · drive_version

Filesystem

drive_list · drive_info · drive_read_content · drive_read_many · drive_tree · drive_search · drive_mkdir · drive_upload · drive_download · drive_rename · drive_move · drive_delete

Sharing

drive_share_status · drive_share_invite · drive_share_revoke · drive_share_remove_all · drive_share_set_url · drive_share_remove_url

Trash

drive_list_trash · drive_trash · drive_restore · drive_empty_trash

Local sync (requires PROTON_DRIVE_SYNC_PATH)

drive_read_file · drive_write_file

Copy

drive_copy

Plan & bulk

drive_sync_plan · drive_bulk_move · drive_bulk_trash

Invitations

drive_list_invitations · drive_invitation_accept · drive_invitation_reject · drive_share_leave

Analytics

drive_usage · drive_find_duplicates · drive_sharing_audit · drive_share_expiry_report · drive_recent_changes

Content search (opt-in, see Content search)

drive_content_index · drive_search_content

Index refresh (opt-in, see Keeping the index fresh on huge drives)

drive_refresh_index

Audit (see Guard layer)

drive_audit_log

Photos

photos_list_albums · photos_create_album · photos_update_album · photos_delete_album · photos_list_album_photos · photos_add_to_album · photos_remove_from_album · photos_list_timeline · photos_download · photos_upload


Tool reference

Tool Description Key parameters
drive_auth_status Check if authenticated (probes /my-files — no native status command) —
drive_auth_logout Log out (clear session) ⚠️ confirmed: true
drive_version CLI and SDK version info —
drive_list List files and folders at a path (paginated, default 200; / lists the roots) path, limit?, offset?
drive_info Get metadata for one file/folder, including revision details (noise trimmed) path, verbose? (raw CLI node)
drive_read_content Read the text of a file stored in Drive (no sync folder needed): text/code, .docx, text-layer .pdf; scans and images with opt-in local OCR. Paged; content is untrusted data. See Reading file contents path, maxChars? (default 20000, max 100000), offset?
drive_read_many Read the text of up to 10 Drive files in one call, two at a time; per-file and total character caps; one failing file does not fail the rest. Content is untrusted data. See Reading file contents paths (max 10), maxCharsPerFile? (default 4000, max 20000), maxTotalChars? (default 40000, max 100000)
drive_tree Folder overview: per-folder file counts and size totals (largest first), depth-limited, cached 5 min path?, depth? (default 2, max 10), limit?, foldersOnly?, refresh?
drive_search Find files/folders under a path in one cached walk: name (substring/glob; a glob containing / matches the path relative to path), type, extension, MIME prefix, size, modified date; sortable, paginated. Reports walk.complete — false means the walk was cut short and matches may be missing query?, glob?, path?, type?, mediaType?, extensions?, minSize?, maxSize?, modifiedAfter?, modifiedBefore?, sort?, limit? (default 50, max 500), offset?, refresh?
drive_mkdir Create a new empty folder path
drive_upload Upload local file or folder localPath, remotePath, fileConflictStrategy? (skip/create-new-revision/rename/replace), folderConflictStrategy? (skip/merge/rename/replace), confirmed? (required for replace — it trashes the existing remote item)
drive_download Download to local path remotePath, localPath, fileConflictStrategy? (skip/rename/remove), folderConflictStrategy? (skip/merge/rename/remove), confirmed? (required for remove — it deletes the existing local item)
drive_rename Rename in place, no move path, newName
drive_move Move and/or rename sourcePath, destinationPath
drive_copy Copy file or folder into another Drive folder sourcePath, destinationPath (target parent folder), newName?
drive_delete Permanently delete an item already in trash ⚠️ path, confirmed: true
drive_list_trash List items currently in trash (paginated, default 100; includes uid — names are not unique in trash) limit?, offset?
drive_share_status Get sharing members and URL path
drive_usage Storage analytics for a subtree: totals, largest files/folders, extension and media-type breakdown, old files, trash stats (sum of file sizes, not the account quota) path?, top?, olderThanDays?, refresh?
drive_find_duplicates Likely duplicate groups (claimed sha1 / same size; verify downloads and sha256s candidates), wasted bytes, suggested keeper — never deletes path?, minSize?, verify?, maxVerifyBytes?, maxVerifyTotalBytes? (default 500 MB, max 2 GB), limit?, refresh?
drive_sharing_audit Public links (no URL), invitees, pending invitations and risk flags for shared items (max 100) path?, refresh?
drive_share_expiry_report Public links under a path with expiresAt, daysLeft and flags expired, expiringSoon, noExpiry, hasPassword, soonest first. Uses the sharing audit walk (max 100 shared items; capped says when more exist). Lists only links set directly on items below path: a link on the folder passed as path itself is not listed, so pass its parent. Changes nothing path?, withinDays? (default 14), refresh?
drive_recent_changes Files added or modified since a date (since: ISO date or 7d/12h/2w, default 7d), from one complete walk. With snapshot: "diff" or "save" (needs PROTON_DRIVE_INDEX=1): added, removed, modified and moved files against the previous snapshot of that path. See Recent changes path?, since?, limit? (default 50, max 500), snapshot?, refresh?
drive_content_index Opt-in (PROTON_DRIVE_CONTENT_INDEX=1): build or refresh an encrypted local full-text index of the files under one folder you name (text, markdown, .docx, text-layer .pdf); status and clear actions. Secret-looking names are skipped. Changes nothing on Drive, writes one local file (also in readonly mode). See Content search path (required for update), action? (update default, status, clear), maxFiles? (default 200), maxFileMB? (default 20), timeBudgetMs? (default 25000)
drive_search_content Search the indexed file text: all words must match, BM25 ranking, trailing * = prefix on the last word. Returns path, score, snippet, indexedAt; results reflect the last index update (stale: true). Snippets are untrusted file content. See Content search query (max 200 characters), path?, limit? (default 10, max 50)
drive_refresh_index Opt-in (PROTON_DRIVE_INDEX=1): refresh the saved folder index of a huge drive in resumable slices. Lists the folders whose saved listing is older than maxAgeHours (or never read), oldest first, within timeBudgetMs, and saves its progress; repeat until complete. Returns foldersRefreshed, foldersReused, foldersRemaining, oldestListingAgeMs, etaCalls, saved; with changes: true also counts and up to 50 sample paths of added, removed and modified entries in the re-listed folders. Changes nothing on Drive. See Keeping the index fresh on huge drives path? (default /my-files), timeBudgetMs? (default 25000, max 120000), maxAgeHours?, changes?
drive_audit_log Newest audit-log entries plus a hash-chain check (needs PROTON_DRIVE_AUDIT_LOG; works in readonly mode) limit? (default 50)
drive_share_invite Invite a user (sends an email) ⚠️ path, email, role (viewer/editor/admin), message?, confirmed: true
drive_share_revoke Revoke one person's access (fails if not a member) ⚠️ path, email, confirmed: true
drive_share_remove_all Remove every member + pending invitation at once ⚠️ path, confirmed: true
drive_share_set_url Create/replace a public share link ⚠️ (set-url replaces all link settings; if the path already has a link with a password and/or expiration that the call omits, it is refused before any change unless resetSettings: true; expiry max ~90 days) path, role? (viewer/editor), password?, expiration?, resetSettings?, confirmed: true
drive_share_remove_url Remove the public share link ⚠️ path, confirmed: true
drive_trash Move to trash path
drive_sync_plan Read-only diff of a local folder vs a Drive folder (nothing transferred) localPath, drivePath, direction? (up/down/both), ignore?, compare? (size-mtime/sha1), limit?
drive_bulk_move Move up to 200 items into an existing folder; without confirmed returns the plan and problems only sources, destinationFolder, confirmed? (required to apply)
drive_bulk_trash Trash up to 200 items (recoverable); without confirmed returns the plan and problems only paths, confirmed? (required to apply)
drive_restore Restore from trash path
drive_empty_trash Permanently delete all trash ⚠️ confirmed: true
drive_read_file Read text file from local sync folder path
drive_write_file Write text file to local sync folder ⚠️ (overwriting an existing file needs confirmation; max 5 MB) path, content, confirmed?
drive_list_invitations List pending sharing invitations received —
drive_invitation_accept Accept a pending invitation uid (from drive_list_invitations)
drive_invitation_reject Reject a pending invitation ⚠️ uid (from drive_list_invitations), confirmed: true
drive_share_leave Leave a shared folder shared with you ⚠️ path, confirmed: true
photos_list_albums List all Proton Photos albums —
photos_create_album Create a new empty album name
photos_update_album Rename an album or change its cover photo albumPath, name?, coverPhotoUid?
photos_delete_album Delete an album ⚠️ albumPath, confirmed: true, force?, save?
photos_list_album_photos List photos in an album (paginated, default 100) albumPath, loadDetails?, limit?, offset?
photos_add_to_album Add a photo from your library to an album albumPath, photoPath
photos_remove_from_album Remove a photo from an album (keeps it in library) ⚠️ albumPath, photoPath, confirmed: true
photos_list_timeline List photos in your full library timeline (paginated, default 50) loadDetails?, limit?, offset?
photos_download Download photos to a local folder photoPaths, localFolder, conflictStrategy? (skip/rename/remove), confirmed? (required for remove)
photos_upload Upload local files directly into your Photos library localPaths, conflictStrategy? (skip/rename)

⚠️ Destructive and outward-facing tools (deleting, sharing, public links, logout, and the replace/remove conflict strategies) require confirmed: true, and the CLI requires --confirm for the destructive ones. Describe the action to the user first, then pass confirmed: true. Tool arguments are validated against the published schema — unknown or mistyped arguments are rejected.


Compared with other Drive MCPs

Capability Generic S3/GDrive MCPs proton-drive-mcp
End-to-end encryption No Yes (via Proton CLI)
Credential exposure API keys in config Zero — OS keychain only
Sharing & invitations Rarely Full (invite, revoke, status)
Trash & restore Rarely Full
CLI parity No The CLI mirrors every MCP tool except drive_read_file / drive_write_file
Shell injection safe Varies Yes — spawn with argument arrays, no shell

Operational notes

  • Long listings are paginated (limit / offset, response {total, offset, limit, hasMore, items}) to keep responses small. Responses are compact JSON.
  • Local paths passed to upload/download/photos tools are checked: credential locations (~/.ssh, ~/.aws, ~/.gnupg, ~/.claude*, keychains, .env files, …) are refused. Set PROTON_DRIVE_LOCAL_ROOT to allow only specific directories.
  • The sync-folder tools (drive_read_file / drive_write_file) refuse to follow symlinks out of PROTON_DRIVE_SYNC_PATH.
  • Error messages come from the CLI's own output; the command line (and therefore any --password) is never echoed back.
  • drive_move accepts a full destination path (parent + new name) for a familiar interface, but the underlying CLI only has separate move (change parent) and rename (change name) commands — this MCP translates automatically, issuing one or both as needed.
  • drive_delete only works on items already in /trash or /photos-trash — the CLI rejects live paths. Trash an item first with drive_trash, or use drive_empty_trash to clear everything at once.
  • If the client declares MCP elicitation (form mode), a refused confirmed gate is put to the human instead, and drive_bulk_move / drive_bulk_trash ask before applying a confirmed: true call. Only an explicit approval runs the call; decline, cancel, timeout or error keep the refusal, and after 5 declined prompts in a minute the server stops prompting. This only upgrades refusals and bulk applies: a compromised model that supplies confirmed: true on any other tool is not stopped by it. Clients without elicitation behave as before. Confirmation prompts need a client that supports elicitation (Claude Code CLI today; Claude Desktop is unverified).
  • Walk-based tools (drive_tree, drive_search, drive_usage, drive_find_duplicates) read from a cache up to 5 minutes old (with the opt-in persistent index, up to 24 h old and marked stale: true; drive_sharing_audit, drive_sync_plan and drive_find_duplicates never serve the saved index, they only reuse saved folder listings read less than 5 minutes ago); changes made by other clients or processes are not seen until it expires or you pass refresh: true. The first walk of a large drive can take minutes (measured about 21 s per 1,200 files at the default concurrency (12)); drive_search, drive_tree and drive_usage return a partial: true result after 25 s and finish the walk in the background.
  • drive_auth_status has no native CLI equivalent — it probes by resolving /my-files and reports authenticated based on whether that succeeds.
  • Paths are always Drive-absolute: /my-files/folder/file.pdf. Relative paths are not supported.
  • All calls include --json automatically, except drive_version, whose underlying CLI command ignores --json and always prints plain text — this MCP parses it directly.

Token cost

tools/list is sent to the model in every session. Measured payload (JSON bytes): full 48.0 KB (54 tools), core 17.9 KB (19 tools). Set PROTON_DRIVE_TOOL_TIER=core to load only:

drive_auth_status, drive_version, drive_list, drive_info, drive_read_content, drive_list_trash, drive_search, drive_tree, drive_mkdir, drive_upload, drive_download, drive_rename, drive_move, drive_copy, drive_trash, drive_restore, drive_share_status, photos_list_timeline, photos_download.

Left out of core (use full): permanent deletion (drive_delete, drive_empty_trash), drive_auth_logout, public links, invitations and invites, album management, photos_upload and the sync-file tools. A call to a hidden tool returns an error asking for PROTON_DRIVE_TOOL_TIER=full; no CLI command runs.

Guard layer (opt-in)

Four environment variables limit what a model (or a prompt-injected one) can do with your Drive. All are read once at startup and are off by default. They apply to the MCP server only: the companion CLI (proton-drive-cli) is a tool you run yourself and is not restricted by them.

  • PROTON_DRIVE_MODE=readonly hides every tool that changes Drive or the account from tools/list and refuses it at call time (no CLI command runs). Hidden: drive_upload, drive_mkdir, drive_rename, drive_move, drive_copy, drive_trash, drive_restore, drive_delete, drive_empty_trash, drive_bulk_move, drive_bulk_trash, drive_write_file, drive_auth_logout, every drive_share_* that changes sharing (invite, revoke, set_url, remove_url, remove_all, leave), drive_invitation_accept/reject, and photos_create_album, photos_update_album, photos_delete_album, photos_add_to_album, photos_remove_from_album, photos_upload. Reads, analytics and downloads to local disk stay. An invalid value is treated as readonly. Prompts that name a hidden tool are not offered.
  • PROTON_DRIVE_REMOTE_ROOTS (list separated by : on macOS/Linux, ; on Windows, e.g. /my-files/Projects/X) confines every Drive path argument to those folders. Paths are matched by whole segment and case-sensitively (/my-files/AB is not inside /my-files/A); .. and empty (//) segments are refused. Paths include sources, destinations, bulk lists, walk roots (drive_tree, drive_search, drive_usage, drive_find_duplicates, drive_sharing_audit, drive_share_expiry_report, drive_recent_changes, drive_refresh_index, drive_sync_plan, and the optional path of drive_content_index and drive_search_content, whose results outside the roots are dropped; their default /my-files is refused, so pass a path) and the sync-file tools. The root folder itself cannot be renamed, moved, trashed or left (drive_share_leave). drive_usage leaves out the account-wide trash summary. An entry that is not a clean absolute path is dropped with a warning; if none is left everything is refused. These tools cannot be limited to a folder and are refused while roots are set: drive_auth_logout, drive_delete, drive_restore, drive_empty_trash, drive_list_trash (trash is account-wide and addressed by name or UID), drive_audit_log, drive_list_invitations, drive_invitation_accept, drive_invitation_reject, and all ten photos_* tools. drive_audit_log is refused too, because its entries name paths outside the roots (read the file directly). drive_auth_status and drive_version touch no Drive content and keep working.
  • PROTON_DRIVE_AUDIT_LOG=/absolute/path/audit.jsonl appends one JSON line per tool call, refused calls included: ts, seq, tool, redacted args, outcome (ok, error or refused), a short code (roots, readonly, tier, confirm, audit, snapshot, invalid, cli_error, ...), durationMs, and prev/hash, a SHA-256 chain over the previous hash and the record. The file is created 0600 (its folder 0700 if missing). Passwords and message bodies are never written; for drive_write_file only the byte length of the content is, and arguments a tool does not declare are recorded as present, never by value. If the log cannot be written, tools that change Drive are refused (reads continue, with a warning on stderr). drive_audit_log returns the newest entries (default 50, full tier only, not available while roots are set) and verification: {ok: true, entries, head} or the first broken seq. The chain detects edited, inserted, reordered and mid-file removed lines, not removal of the newest lines: keep head somewhere else if you need that. Several servers can share one file (appends are serialized with a <log>.lock file; if it cannot be taken within a few seconds the write counts as failed). The server refuses to start when the log lies inside PROTON_DRIVE_SYNC_PATH. An entry is written after the call finishes, so a crash or kill in the middle of an operation can leave a change that was never recorded. The hash chain is only as trustworthy as the account that can write the file.
  • PROTON_DRIVE_SNAPSHOT_BEFORE_OVERWRITE=1 keeps the previous version before an overwrite (the result carries snapshot), as <same folder>/.versions/<name>.<UTC timestamp>. drive_write_file overwrites the local sync copy, so it copies the existing local file inside the sync folder (the sync client uploads the copy; unsynced local edits and files never uploaded are preserved). drive_upload with fileConflictStrategy: replace copies the existing remote file. If the copy fails, or the remote state cannot be determined (for example the CLI is missing), the overwrite is refused. Replacing a folder is not versioned and is refused too: drive_upload of a folder with a replace strategy, or onto a remote folder, while snapshots are on. A file that does not exist yet has nothing to preserve. Snapshots are never pruned.

Reading file contents

drive_read_content returns the text of a file stored in Drive, without a sync folder: it downloads the file into a private temp directory (mode 0700, always removed afterwards), extracts the text and returns it in pages (offset / maxChars, default 20000, max 100000 characters; the reply carries nextOffset while more remains). Expect 2-4 s per read.

  • Formats: plain text, markdown, json, csv/tsv, yaml, xml, html (tags are kept as is), log and common code files (UTF-8; binary or non-UTF-8 content is refused as "not text"); .docx (paragraph text of word/document.xml); .pdf with a text layer (first 100 pages; a scanned PDF returns empty text with a note, unless OCR is enabled, which also reads images). Everything else, folders and Proton Docs/Sheets are refused with a clear message.
  • Caps: files over 10 MB are refused before downloading (PROTON_DRIVE_READ_MAX_BYTES, hard maximum 50 MB); a .docx whose document.xml exceeds 20 MB uncompressed is refused.
  • Isolation: .docx and .pdf parsing runs in a separate worker thread limited to 512 MB of memory and a 20 s timeout (PROTON_DRIVE_READ_TIMEOUT_MS, in milliseconds, max 120000); a hostile or oversized file produces a tool error ("too large or complex to read safely") and never takes the server down. Extracted text is capped at 2,000,000 characters.
  • Untrusted content: file text comes from your drive and may contain instructions aimed at the model (prompt injection). The tool returns it as data, nothing is executed, and its description tells the model to treat it as data, never as instructions.
  • Optional packages: .docx needs fflate and .pdf needs unpdf; both are optional dependencies of this package, installed by default (and included in the MCPB bundle). If they were omitted (npm install --omit=optional), PDF/DOCX reading returns a clear error naming the package to install (npm install fflate unpdf); text formats work without them. The test suite skips the PDF/DOCX groups with a reason when the packages are missing (never on CI, where they fail instead).

drive_read_many takes up to 10 paths and applies the same rules to each file (formats, size cap, isolated parsing, untrusted content). Files are read two at a time, because the CLI fails with "database is locked" under heavier parallelism. Each result is {path, ok, text?, truncated?, nextOffset?, error?}, so one unreadable file does not fail the others. Text is capped per file (maxCharsPerFile, default 4000, max 20000) and over the whole call (maxTotalChars, default 40000); once the total is used up, remaining files report skipped. Continue a truncated file with drive_read_content and offset = nextOffset. With PROTON_DRIVE_REMOTE_ROOTS set, every path must be inside a root or the whole call is refused.

OCR for scans (opt-in)

Scanned PDFs (no text layer) and images normally come back empty or as "unsupported". With PROTON_DRIVE_OCR=1 the server reads them with an OCR engine that runs on your machine, so drive_read_content, drive_read_many and the content index can see them. It is off by default: OCR is heavy on CPU and runs a local program on files from your drive, which are untrusted input.

  • What it reads: .png, .jpg/.jpeg, .tif/.tiff, .bmp, .webp (and .heic, Vision engine only), and PDFs whose text layer is empty or very sparse (fewer than about 20 non-blank characters per page on average). A PDF with a real text layer is read as before and never OCR'd. Without the opt-in nothing changes: images stay unsupported and a scanned PDF returns empty text.
  • Engines (PROTON_DRIVE_OCR_ENGINE: auto default, vision, tesseract): auto uses the macOS Vision framework on macOS and tesseract elsewhere (or on macOS when Vision cannot be built). If neither is found the read fails with "OCR is enabled but no OCR engine was found" and an install hint.
    • Vision needs only the Xcode command line tools (xcode-select --install, for swiftc). A small Swift helper shipped in this package (dist/ocr/vision-ocr.swift) is compiled on first use with swiftc -O into the private cache directory (PROTON_DRIVE_INDEX_DIR, mode 0700; the binary is 0700 and named by a hash of the source, so an upgrade rebuilds it). Building takes about a second, but macOS then prepares Vision for the new binary, which made the very first read take about 25 s in testing; later reads take a fraction of a second. With PROTON_DRIVE_OCR=1 the server builds and warms the helper in the background a few seconds after it starts (on a tiny generated blank image, never on your files; errors only appear with PROTON_DRIVE_DEBUG=1), and the per-file timeout starts only after the helper is built and warmed, so neither counts against a file. It renders PDF pages at about 200 dpi, uses the accurate recognition level with language correction and detects the language automatically. Nothing is downloaded.
    • tesseract needs tesseract (brew install tesseract tesseract-lang, or apt install tesseract-ocr tesseract-ocr-pol) and, for PDFs, pdftoppm from poppler (brew install poppler, apt install poppler-utils). Images are read with tesseract <image> stdout -l <langs>; PDFs are rasterized with pdftoppm -r 200 -png page by page into a private temp directory first; a page larger than 4000 pixels on its long side is scaled down (with pdfinfo the dpi is lowered for the largest page, without it every page is scaled to 4000 px), never cropped. Homebrew's directories are searched even when the client gives the server a minimal PATH.
    • PROTON_DRIVE_OCR_LANGS picks languages: for tesseract the codes it uses, default eng, eng+pol for several; for Vision any code is matched against what the OS supports (eng, en, pol, ...) and unsupported ones are ignored; unset means automatic detection. Only letters, _ and + are accepted.
  • Privacy: recognition happens entirely on your machine and nothing is sent anywhere by this feature. The recognized text reaches the model only when you ask Claude to read the file (or see a search snippet), exactly like any other file text, and is then sent to your model provider. Recognized text is never written to the audit log (it records arguments, not results) or to a log file; the only copy kept is the excerpt and word list in the encrypted content index if you index that folder.
  • Safety of the engine process: each OCR run uses a fresh private temp directory (mode 0700, registered for cleanup on shutdown and removed afterwards, also on error or timeout) and a fixed file name inside it (in.<ext>, an absolute path that cannot start with -; no name from Drive is ever used). Programs are started from argument arrays, never through a shell, at low priority, with a hard time limit (the whole process group is killed on timeout, on cancel and on shutdown) and a cap on the size of their output. One OCR runs at a time per server process.
  • Limits: PROTON_DRIVE_OCR_MAX_PAGES (default 30, max 200; later pages are not read and the note says so), PROTON_DRIVE_OCR_MAX_MB (largest image or scanned PDF to download and OCR, default 30 MB, max 50; independent of the 10 MB PROTON_DRIVE_READ_MAX_BYTES cap, which keeps applying to text, .docx and text-layer PDFs), PROTON_DRIVE_OCR_MAX_PIXELS (images above this many pixels, width x height, default 100 million, are refused before any engine sees them: the size is read from the file header, an image whose size cannot be read is refused too, and the Vision helper applies the same limit to the decoded image; HEIC is checked by Vision only), PROTON_DRIVE_OCR_TIMEOUT_MS (per file, all steps together, counted from when the engine is ready; default 90000, max 600000), and the usual 2,000,000-character text cap. A scanned PDF over the OCR size limit is returned as before with a note; an image over it is refused. If OCR fails on a PDF that has a thin text layer, the read still succeeds with the text layer and a note OCR unavailable/failed: ...; the longer of text layer and OCR text is kept.
  • Accuracy: OCR makes mistakes: wrong digits, dropped diacritics, scrambled tables and columns. Results carry ocr: true, engine and pagesOcrd and a note saying so; drive_read_many items and drive_search_content results carry ocr: true. Check amounts, dates and IBANs against the original before relying on them. Handwriting is not supported and usually comes out as noise. Photos at an angle, very small text and low-contrast scans read poorly.
  • Content index: scans and images in an indexed folder are OCR'd one at a time (the OCR slot is shared by everything in the process), so a folder of scans takes many calls; the time budget and partial/remaining work as before. A file whose OCR could not start before the budget ran out is not recorded half-way and is simply tried again by the next call. Files recorded as unreadable while OCR was off (images, textless PDFs) are tried once more after you enable it; files OCR found no text in are not retried until they change. An OCR timeout is recorded as a skip for that version of the file and tried again when PROTON_DRIVE_OCR_TIMEOUT_MS changes. A missing engine or an invalid PROTON_DRIVE_OCR_LANGS fails the update at once with one clear error, before any image is downloaded. The indexed documents carry ocr: true (a search result shows it, because the snippet may be imperfect). Credential-looking names are skipped for images too.
  • Known limit (tesseract only): it does not rotate pages. A scan that is upside down (or a PDF page rotated 180°) comes back as garbage text on the tesseract path, while macOS Vision handles it. Checked on small synthetic samples only; orientation detection on full-size real scans is untested. Rotate such scans before uploading.
  • Doctor: proton-drive-cli doctor reports whether OCR is off or on, which engine was found, the tesseract version and installed languages, and what is missing (for example pdftoppm).
  • Guards: drive_read_content, drive_read_many and the index tools stay read tools: available in PROTON_DRIVE_MODE=readonly, confined by PROTON_DRIVE_REMOTE_ROOTS.

Recent changes

drive_recent_changes answers "what changed in this folder?" in two ways.

  • Since a date (default): files whose original modification time or upload time is at or after since (an ISO date, or a relative age such as 7d, 12h, 2w; default 7d), newest first, from one complete walk that never serves the saved index (with PROTON_DRIVE_INDEX=1 it only reuses saved folder listings read less than 5 minutes ago). It cannot tell "added" from "modified" and sees only what the walk data shows: a file changed in place with an old claimed modification time and no re-upload is missed.
  • Against a snapshot (snapshot: "diff" or "save"): only with PROTON_DRIVE_INDEX=1, because it keeps a plaintext list of file paths, sizes, modification times and claimed sha1 hashes (the same privacy trade-off as the persistent index); otherwise the call returns an error saying so. The list is stored per walked path in changes-snapshot.json next to walk-index.json (same private 0700 directory, 0600 file, atomic write, tied to the account fingerprint, not written above 50 MB, up to 8 paths kept; proton-drive-cli index clear removes it too). diff compares the current drive with the previous snapshot of that path and reports added, removed, modified and moved (a removed and an added file with the same size and the same non-empty claimed sha1; files without a sha1 show up as removed plus added). save does the same comparison and then stores the current state as the new baseline. If the walk was incomplete, nothing is saved (a partial list would later look like mass deletions) and removed/moved are left out of the answer.

Content search (opt-in)

drive_content_index and drive_search_content let Claude find files by what is inside them (the built-in drive_search only matches names). Because Proton Drive is end-to-end encrypted, this works by keeping a searchable copy of the text on your machine, so it is off by default and you choose the folders: set PROTON_DRIVE_CONTENT_INDEX=1, then ask Claude to index a folder (for example /my-files/Documents). Nothing is indexed without an explicit path.

  • What is stored (one file, content-index.enc, in the same private directory as the walk index: mode 0600 in a 0700 directory, PROTON_DRIVE_INDEX_DIR to move it): the paths and sizes of the indexed files, the words each file contains with how often (a full-text index), and the first 64 KB of each file's text, compressed, for result snippets. All of it is encrypted. Not stored: the raw files, any encryption key, or text beyond the first 64 KB (words further in are searchable but have no snippet).
  • Encryption: AES-256-GCM in 1 MB chunks, each with its own random nonce, authenticated together with the file header, the chunk position and an end-of-file flag, so a wrong key, a changed byte, reordered, removed or appended chunks and a file from another account are all refused with an error; nothing is returned from a file that did not verify, and there is no plaintext fallback. The 32-byte key is generated on first use and kept in the macOS Keychain (service proton-drive-mcp-content-index) or the Linux Secret Service (secret-tool, if installed). It is handed over on standard input, never as a command-line argument, so it does not appear in ps. Where there is no keychain (Windows, or Linux without secret-tool) the tools refuse unless you set PROTON_DRIVE_CONTENT_INDEX_KEY yourself. The index is bound to the signed-in Proton account and is refused if another account signs in.
  • Threat model: protects the text of your drive against theft of the disk or laptop, backups and cloud sync of your home folder, and other local users. It does not protect against a process running as you that can read your keychain (it can read the key and the file), against malware on the machine, or against what you do with the results: snippets that Claude receives are sent to the model provider like any other file content.
  • Usage: drive_content_index with path indexes up to maxFiles (default 200) changed files per call, two at a time, for at most timeBudgetMs (default 25 s); when the result says partial: true with remaining, call it again with the same path to continue. Unchanged files (same size, modification time and claimed hash) are not read again, files that disappeared from the folder are dropped, and one unreadable file never fails the call. Names that look like credentials are never read (checked on every path segment, case-insensitive): .env*, *.env, *.env.*, .npmrc, .netrc, .pgpass, .htpasswd, .git-credentials, .pypirc, .dockercfg, id_rsa*, id_dsa*, id_ecdsa*, id_ed25519*, *.pem, *.key, *.p12, *.pfx, *.kdbx, *.keystore, *.jks, *.asc, *.gpg, *.keychain*, and anything containing passw (also Passwort), hasło/haslo, token, api-key/apikey, secret, credential, service-account, kubeconfig or private-key. The check is by name only: a secret in a file with an ordinary name is indexed, so index the folders you mean to. A file whose listing gives no size, time or hash is always re-read. drive_search_content takes query (all words must match, ranked by BM25; end the last word with * for a prefix, invoi*), an optional path filter and limit. It does not re-list Drive: results are as of the last update (indexedAt, stale: true). status shows counts, size, covered folders and the key backend; it never shows the key.
  • Limits: plain text/markdown/code, .docx and .pdf with a text layer only (scanned PDFs and images are recorded as having no text unless you enable OCR, which is slow: one file at a time), files up to maxFileMB and PROTON_DRIVE_READ_MAX_BYTES (10 MB by default). Expect about 2 to 4 s per file, two at a time: a first index of N files takes roughly N × 2 s ÷ 2 (1,000 files is about 20 to 30 minutes, over several calls). Words are runs of letters and digits of 2 to 40 characters; scripts written without spaces (Chinese, Japanese) are indexed as long runs and match poorly. A folder listing older than one hour (PROTON_DRIVE_CONTENT_INDEX_LISTING_MAX_AGE_MIN, default 60) is not used by an update (with the persistent index on, only those folders are listed again; otherwise it walks again), so a file added or deleted in the last hour may not be seen yet and a large folder converges over several calls minutes apart; pass a smaller value to see changes sooner; the result reports listingAgeMs and fromCache. The index file is capped (200 MB by default, PROTON_DRIVE_CONTENT_INDEX_MAX_MB). Each search decrypts and loads the whole index: roughly 1 s and 600 MB of memory near the old 500 MB size, hence the 200 MB default; keep the index to the folders you need. If an update would pass the cap, the newest documents are left out so the rest is saved, and the result says partial: true with droppedForSize.
  • Guards: both tools are read tools (they never change Drive), so they stay available in PROTON_DRIVE_MODE=readonly; note that they write the local encrypted file. With PROTON_DRIVE_REMOTE_ROOTS the path must be inside a root and results outside the roots are dropped. The audit log records the folder and the numeric arguments of an update, but for a search only the length of the query, never the words or the snippets.
  • Clear it: drive_content_index with action: "clear", or proton-drive-cli index clear (which also removes the walk index and change snapshots), or delete content-index.enc. clear also deletes the key from the macOS Keychain or Secret Service (keyRemoved in the result; a missing item is fine), so the next update generates a new key and old copies of the index file, for example in a backup, become unreadable. A key you supplied in PROTON_DRIVE_CONTENT_INDEX_KEY cannot be rotated from here: remove or change it yourself. proton-drive-cli index clear does the same for the file and key it can find from the file header. If an index file exists but its key is gone, update refuses (it never makes a new key behind an existing file) and search fails: clear it and index again.
  • No rollback detection: the file is authenticated (a changed, reordered, truncated or foreign file is refused) but not versioned, so someone with write access to the index directory can swap in an older valid copy of it and it will be accepted. This protects integrity of each version, not freshness; the encryption protects confidentiality against reading, not against replacing.
  • Read-only mode: drive_content_index (update, clear) and drive_search_content stay available with PROTON_DRIVE_MODE=readonly, because they change only the local index file and never Drive.
  • Untrusted content: snippets come from your files and may contain instructions aimed at the model; the tool says so in every result and nothing in them is executed.

Known limitations

These come from the upstream proton-drive CLI (v0.8.0), not from this server:

  • Big folders cannot be copied yet (drive_copy fails with InvalidRequirementsAPIError code 2000).
  • A " in a name becomes _ when the item is downloaded locally.
  • Public-link expiration can be at most ~90 days ahead, to the minute.
  • drive_share_status only reports sharing set directly on the item — access inherited from a shared parent folder is not shown.
  • Roots (/my-files, /photos, …) cannot be shared; drive_share_status on a root returns an error.
  • photos_list_timeline pages are not a snapshot: photos added or removed between calls shift later pages.
  • Upload/download counts include folders, not only files.
  • /albums/... paths cannot be downloaded — download a photo via /photos/<name>.
  • A name ending in a backslash (e.g. tail\, created by another client) cannot be used as a parent in a path: the CLI reads tail\/child as an escaped /, and has no escape for a literal backslash (\\ does not work either). The folder itself is reachable; its children are not reachable by path.
  • Trashed items are addressed by name only. When two items in /trash or /photos-trash share a name, drive_restore and drive_delete refuse (listing the uids) instead of acting on an arbitrary one — restore or delete that item in the Proton Drive web or desktop app.
  • When several programs use the CLI at the same moment (e.g. Claude Desktop and Claude Code), its local cache can briefly report database is locked. Read-only calls are retried automatically; writes are not (a retry could repeat the change), so just run the write again. The same read-only retry (up to two more attempts, short jittered backoff, honoring a Retry-After of at most 5 s and the call's overall timeout) also covers rate limiting (HTTP 429), single-request timeouts (Request timed out) and transient network resets; auth and not-found errors are never retried.

Compatibility

Component Tested with
Proton Drive CLI 0.8.x (SDK js 0.21)
macOS Live-tested against a real account
Linux CI with a fake CLI only
Windows Not supported (see Platform support)

proton-drive-cli doctor warns when the installed CLI is not 0.8.x, and the server logs one warning line to stderr at startup. Other versions may work but are unverified. If something breaks, open an issue at github.com/googlarz/proton-drive-mcp/issues with the output of proton-drive version and proton-drive-cli doctor.

Platform support

Developed and live-tested on macOS. CI runs the test suite on Ubuntu and macOS (Node 22 and 24). Windows is not supported. Proton does ship a Windows build of its CLI (x64 and arm64, per the CLI download page), so the blocker is on this project's side: the test suite has never passed on Windows, CI does not run it, and the Windows paths in doctor / setup-claude-desktop (%APPDATA%, PATHEXT lookup) are untested. The system-PATH warning in doctor only knows POSIX directories. Supporting Windows would need a Windows CI job, a passing test suite there, and a live test against the Windows CLI. Linux is covered by CI with the fake CLI but has not been live-tested against a real Proton account.

Testing status

Every tool group was live-tested on 2026-09-28 against a real Proton account, except drive_share_leave, drive_invitation_accept and drive_invitation_reject. Those three have never been tested against a real account, because the maintainer has no second Proton account to share from; they are only unit-tested against a fake CLI.


Environment variables

Variable Required Description
PROTON_DRIVE_SYNC_PATH Optional Absolute path to your local Proton Drive sync folder root (e.g. /Users/you/Proton Drive). Required only for drive_read_file and drive_write_file. The Proton Drive desktop app must be running to sync written files to the cloud.
PROTON_DRIVE_BIN Optional Override the proton-drive binary name or path (default: proton-drive; an empty value counts as unset). Useful for non-standard installations.
PROTON_DRIVE_LOCAL_ROOT Optional Path-delimiter-separated list of local directories that upload/download/photos tools may touch. Unset = any path except the built-in credential denylist.
PROTON_DRIVE_ALLOW_SENSITIVE_PATHS Optional Set to 1 to disable the built-in credential-location denylist (not recommended).
CLAUDE_DESKTOP_CONFIG Optional Path of the Claude Desktop config that doctor and setup-claude-desktop read/write instead of the per-OS default.
PROTON_DRIVE_RETRY_BASE_MS Optional Test hook: base backoff in ms for retrying read-only calls (default 250).
PROTON_DRIVE_WALK_TTL_MS Optional How long drive_tree/drive_search reuse a cached folder walk, in ms (default 300000; 0 disables the cache). Results can be up to this old, and changes made by other clients or processes are not seen until it expires or refresh: true. The first walk of a large drive can take minutes. The cache is dropped for any path this server writes to.
PROTON_DRIVE_WALK_BUDGET_MS Optional How long drive_search/drive_tree/drive_usage wait for a folder walk before returning a partial: true result, in ms (default 25000; 0 = wait for the whole walk). The walk keeps running and fills the cache for the next call. Duplicates, sharing audit and sync plan always wait.
PROTON_DRIVE_WALK_CONCURRENCY Optional Parallel folder listings per walk (default and maximum 12).
PROTON_DRIVE_INDEX Optional Set to 1 (or true) to keep completed folder walks in a plaintext on-disk index so searches are fast after a restart. Off by default. See Persistent index.
PROTON_DRIVE_INDEX_DIR Optional Directory for the index file (default: ~/Library/Caches/proton-drive-mcp on macOS, $XDG_CACHE_HOME or ~/.cache/proton-drive-mcp elsewhere). Use a dedicated directory: if it exists it must be yours with mode 0700 (group/other access is refused); a missing one is created 0700. The file is 0600.
PROTON_DRIVE_INDEX_MAX_AGE_H Optional Oldest saved index data that may be served, in hours (default 24; 0 = never serve saved data). Served data is marked stale: true and refreshed in the background (drive_sync_plan, drive_find_duplicates and the sharing audit never serve it).
PROTON_DRIVE_INDEX_FOLDER_MAX_AGE_H Optional With the index on: a saved folder listing younger than this is reused by an incremental refresh, older or unread folders are listed again, oldest first (default 24; 0 = reuse none, every refresh is a full re-walk). Also the default maxAgeHours of drive_refresh_index. See Keeping the index fresh on huge drives.
PROTON_DRIVE_CONTENT_INDEX Optional Set to 1 (or true) to enable the encrypted local content index behind drive_content_index and drive_search_content. Off by default; the two tools then answer with how to turn it on. Stored in the same private directory as the walk index (PROTON_DRIVE_INDEX_DIR). See Content search.
PROTON_DRIVE_CONTENT_INDEX_LISTING_MAX_AGE_MIN Optional Oldest folder listing, in minutes, that a drive_content_index update reuses (default 60; 0 = always list again). With PROTON_DRIVE_INDEX=1 only older folders are listed again.
PROTON_DRIVE_CONTENT_INDEX_MAX_MB Optional Hard size cap of the content index file in MB (default 200). An update that would exceed it stops indexing or leaves out the newest documents and says so; each search loads the whole file into memory.
PROTON_DRIVE_CONTENT_INDEX_KEY Optional 64 hex characters (openssl rand -hex 32): use this key instead of the OS keychain. For systems without a keychain (Windows, headless Linux without secret-tool). It then sits in the server's environment (for example in your MCP client config), which is weaker than the keychain. If set it is always used and the keychain is not touched.
PROTON_DRIVE_KEYCHAIN_SERVICE Optional Keychain service name for the content index key (default proton-drive-mcp-content-index; letters, digits, ., _, - only). Mainly for tests.
PROTON_DRIVE_READ_MAX_BYTES Optional Largest file drive_read_content will download, in bytes (default 10485760 = 10 MB; values above 52428800 = 50 MB are clamped). Larger files are refused before any download.
PROTON_DRIVE_OCR Optional Set to 1 (or true) to read scanned PDFs and images with a local OCR engine in drive_read_content, drive_read_many and the content index. Off by default (heavy CPU; runs a local program on untrusted files). See OCR for scans.
PROTON_DRIVE_OCR_ENGINE Optional auto (default: macOS Vision on macOS, otherwise tesseract), vision or tesseract.
PROTON_DRIVE_OCR_LANGS Optional Languages, letters, _ and + only: tesseract codes such as eng (its default) or eng+pol; Vision matches them against the languages the OS supports and detects the language itself when unset.
PROTON_DRIVE_OCR_MAX_PAGES Optional Pages OCR'd per PDF (default 30, max 200).
PROTON_DRIVE_OCR_MAX_MB Optional Largest image or scanned PDF OCR downloads and reads, in MB (default 30, max 50; may be fractional). Independent of PROTON_DRIVE_READ_MAX_BYTES (10 MB), which still applies to non-scan files.
PROTON_DRIVE_OCR_MAX_PIXELS Optional Largest image OCR accepts in pixels, width x height (default 100000000 = 100 megapixels, max 1000000000). Checked from the file header before any engine runs.
PROTON_DRIVE_OCR_TIMEOUT_MS Optional Time limit for OCR of one file, in milliseconds (default 90000, max 600000); the engine process group is killed on expiry.
PROTON_DRIVE_DEBUG Optional Set to 1 to log debug lines (for example a failed background OCR warm-up) to stderr.
PROTON_DRIVE_READ_TIMEOUT_MS Optional Hard time limit for parsing one .pdf/.docx in drive_read_content, in milliseconds (default 20000; clamped to 1-120000). On expiry the parsing worker is terminated and the call returns an error.
PROTON_DRIVE_TOOL_TIER Optional full (default, all 54 tools) or core (19 everyday tools; see Token cost). Tools outside the active tier are hidden from tools/list and refused at call time. Read once at startup; an unknown value falls back to full with a warning on stderr.
PROTON_DRIVE_MODE Optional full (default) or readonly: hide and refuse every tool that changes Drive or the account. An unknown value is treated as readonly, with a warning. See Guard layer.
PROTON_DRIVE_REMOTE_ROOTS Optional Drive folders (separated by :, or ; on Windows) that every remote path argument must stay inside, e.g. /my-files/Projects/X. Tools that cannot be limited to a folder are refused while it is set. See Guard layer.
PROTON_DRIVE_AUDIT_LOG Optional Absolute path of an append-only, hash-chained JSONL audit log (0600). If it cannot be written, tools that change Drive are refused. Read it with drive_audit_log. See Guard layer.
PROTON_DRIVE_SNAPSHOT_BEFORE_OVERWRITE Optional 1 to copy the existing file to .versions/<name>.<timestamp> in its folder before drive_write_file (local sync copy) or drive_upload (replace, remote copy) overwrites it; the overwrite is refused if the copy fails. Replacing a folder is refused. Off by default. See Guard layer.

Troubleshooting

"PROTON_DRIVE_SYNC_PATH is not set"
Add "PROTON_DRIVE_SYNC_PATH": "/absolute/path/to/your/Proton Drive" to your Claude Desktop MCP config env block. The path must point to the root folder that the Proton Drive desktop app syncs to.

"proton-drive CLI not found"
Download from proton.me/download/drive/cli and ensure the binary is in your PATH. Verify with which proton-drive.

"Not authenticated"
Run proton-drive auth login in your terminal. Auth state is stored in your OS keychain and persists across sessions.

Claude can't see the connector
Restart Claude Desktop fully after changing the MCP config. Check + → Connectors → proton-drive-mcp. The Proton Drive CLI must be in the PATH that Claude Desktop inherits (on macOS this may differ from your shell PATH — use the full binary path in config if needed).

Upload fails on image files
The CLI generates WebP thumbnails by default using Bun's image API. If Bun isn't installed or doesn't support thumbnails on your platform, the MCP passes --skip-thumbnails to bypass this. No action needed.

Custom binary path
If the proton-drive binary is installed under a non-standard name or location, set PROTON_DRIVE_BIN in your environment:

PROTON_DRIVE_BIN=/usr/local/bin/proton-drive npx proton-drive-mcp

Or in Claude Desktop config:

{
  "mcpServers": {
    "proton-drive-mcp": {
      "command": "npx",
      "args": ["-y", "proton-drive-mcp"],
      "env": { "PROTON_DRIVE_BIN": "/usr/local/bin/proton-drive" }
    }
  }
}

Windows
Windows is not supported (see Platform support). If you try anyway, use the full path to the launcher in your Claude Desktop config if npx can't find it:

{
  "mcpServers": {
    "proton-drive-mcp": {
      "command": "C:\\path\\to\\proton-drive-mcp.cmd"
    }
  }
}

Development

git clone https://github.com/googlarz/proton-drive-mcp.git
cd proton-drive-mcp
npm install
npm run build
npm test

Changelog

See CHANGELOG.md for release history.

Contributing

Bug reports and pull requests welcome: github.com/googlarz/proton-drive-mcp/issues

License

MIT

from github.com/googlarz/proton-drive-mcp

Установка Proton Drive

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/googlarz/proton-drive-mcp

FAQ

Proton Drive MCP бесплатный?

Да, Proton Drive MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Proton Drive?

Да, требуются переменные окружения: PROTON_DRIVE_BIN. Unyly подставит их в конфиг при установке.

Proton Drive — hosted или self-hosted?

Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.

Как установить Proton Drive в Claude Desktop, Claude Code или Cursor?

Открой Proton Drive на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Proton Drive with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development