proton-drive-mcp
v1.5.1
Published
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.
Downloads
2,388
Maintainers
Readme
____ ____ ___ _____ ___ _ _ ____ ____ _____ _______
| _ \| _ \ / _ \_ _/ _ \| \ | | | _ \| _ \|_ _\ \ / / ____|
| |_) | |_) | | | || || | | | \| | | | | | |_) || | \ \ / /| _|
| __/| _ <| |_| || || |_| | |\ | | |_| | _ < | | \ V / | |___
|_| |_| \_\\___/ |_| \___/|_| \_| |____/|_| \_\___| \_/ |_____|
MCP server and CLI · Full Proton Drive control for ClaudeGive 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.
Quick start (60 seconds)
- Install the official Proton Drive CLI, then sign in once:
proton-drive auth login. - Connect Claude Desktop, either way:
- Bundle: install
proton-drive-mcp-<version>.mcpbfrom the latest release and set proton-drive CLI path to the output ofwhich proton-drive. - Global install:
npm install -g proton-drive-mcp, thenproton-drive-cli doctor, thenproton-drive-cli setup-claude-desktop --write. (setup-claude-desktoprefuses to run from a temporarynpxcache, so install globally first.) Fully quit and restart Claude Desktop afterwards.
- Bundle: install
- 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_trashpreview first, nothing changes until you confirm)
- "Find files named invoice in my Drive." (
- Optional:
PROTON_DRIVE_INDEX=1keeps a plaintext local copy of file names so searches are instant after a restart (details);PROTON_DRIVE_TOOL_TIER=coreexposes a smaller tool set.
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 lockedunder 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 47 operations, scriptable and pipeable, works in cron and shell scripts (the two sync-folder tools,
drive_read_fileanddrive_write_file, are MCP-only) - Full Proton Drive CLI coverage — every scriptable Proton Drive CLI command has a matching tool (verified against the CLI's own source;
auth loginis the one command excluded, since it's an interactive browser flow) - 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 use
execFilewith discrete argument arrays, 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 loginThis 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-mcpGlobal install:
npm install -g proton-drive-mcpConnect 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 loginhas 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" --writedoctor 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 versionFiles & 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/ReportsTrash
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 itemsSearch, 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_treeanddrive_usagestop waiting after 25 s (PROTON_DRIVE_WALK_BUDGET_MS, 0 = never) and return what was listed so far withpartial: true,continuing: true(the walk is still running) and anote; the same walk keeps running in the background, so repeating the call returns the full result from cache.drive_find_duplicates,drive_sharing_auditanddrive_sync_planalways wait for the complete walk. Later calls reuse a 5-minute in-memory cache;refreshbypasses it. With the opt-in persistent index, a saved copy up to 24 h old can answer first (markedstale: true). - Walks skip
.gitandnode_modulesby 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 passrefresh: truefor a fresh read. Off by default, see Persistent index. - Read-only tools (
drive_search,drive_tree,drive_usage,drive_find_duplicates,drive_sharing_audit,drive_sync_plan) change nothing.drive_bulk_moveanddrive_bulk_trashare two-step: call withoutconfirmedfor the plan, then withconfirmed: trueto apply. Bulk trash is reversible withdrive_restore. - Duplicate detection uses the sha1 the uploader claimed, which is unverified.
verify: truedownloads 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_usagetrash stats always make one uncached/trashlisting (~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 complete walks under
/my-files(partial or failed walks are never saved, so adrive_treethat stops at its depth limit is not stored), plus a fingerprint of your account's Drive root. No file contents, no credentials, no tokens. - Where:
PROTON_DRIVE_INDEX_DIRif 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, mode0600in a0700directory, 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 created0700. 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_Hhours old (default 24;0= never use saved data) is returned immediately withstale: true(andrefreshing: truewhile 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).drive_sync_plan,drive_find_duplicatesand the sharing audit never use saved data.refresh: truealways does a blocking fresh walk. Writes made through this server drop the affected entries from memory and disk. - 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.
- Limits:
drive_treewith a depth limit is not answered from the saved full walk (it walks live); changes made by other clients or processes are not seen until the data is refreshed. - Check or remove it:
proton-drive-cli index statusandproton-drive-cli index clear(or just delete the file). In the MCPB bundle, the Persistent search index setting is the opt-in.
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 skipPipe 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/ProjectsPrompts
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_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
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. Paged; content is untrusted data. See Reading file contents | path, maxChars? (default 20000, max 100000), offset? |
| 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_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 ⚠️ (re-running without password/expiration removes them; expiry max ~90 days) | path, role? (viewer/editor), password?, expiration?, 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/removeconflict strategies) requireconfirmed: true, and the CLI requires--confirmfor the destructive ones. Describe the action to the user first, then passconfirmed: 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 — execFile only |
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,.envfiles, …) are refused. SetPROTON_DRIVE_LOCAL_ROOTto allow only specific directories. - The sync-folder tools (
drive_read_file/drive_write_file) refuse to follow symlinks out ofPROTON_DRIVE_SYNC_PATH. - Error messages come from the CLI's own output; the command line (and therefore any
--password) is never echoed back. drive_moveaccepts a full destination path (parent + new name) for a familiar interface, but the underlying CLI only has separatemove(change parent) andrename(change name) commands — this MCP translates automatically, issuing one or both as needed.drive_deleteonly works on items already in/trashor/photos-trash— the CLI rejects live paths. Trash an item first withdrive_trash, or usedrive_empty_trashto clear everything at once.- If the client declares MCP elicitation (form mode), a refused
confirmedgate is put to the human instead, anddrive_bulk_move/drive_bulk_trashask before applying aconfirmed: truecall. 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 suppliesconfirmed: trueon 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 markedstale: true;drive_sharing_audit,drive_sync_plananddrive_find_duplicatesnever use the saved index); changes made by other clients or processes are not seen until it expires or you passrefresh: 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_treeanddrive_usagereturn apartial: trueresult after 25 s and finish the walk in the background. drive_auth_statushas no native CLI equivalent — it probes by resolving/my-filesand 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
--jsonautomatically, exceptdrive_version, whose underlying CLI command ignores--jsonand 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 40.1 KB (47 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.
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 ofword/document.xml);.pdfwith a text layer (first 100 pages; a scanned PDF returns empty text with a note). 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.docxwhosedocument.xmlexceeds 20 MB uncompressed is refused. - Isolation:
.docxand.pdfparsing 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:
.docxneedsfflateand.pdfneedsunpdf; 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).
Known limitations
These come from the upstream proton-drive CLI (v0.8.0), not from this server:
- Big folders cannot be copied yet (
drive_copyfails withInvalidRequirementsAPIErrorcode 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_statusonly 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_statuson a root returns an error. photos_list_timelinepages 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 readstail\/childas 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
/trashor/photos-trashshare a name,drive_restoreanddrive_deleterefuse (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 aRetry-Afterof 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 use it). |
| 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_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 47 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. |
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-mcpOr 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 testChangelog
See CHANGELOG.md for release history.
Contributing
Bug reports and pull requests welcome: github.com/googlarz/proton-drive-mcp/issues
License
MIT
