filebridge
Drives Brave over DevTools (CDP) to upload files by setting file inputs, dropping files, or intercepting file choosers; supports snapshots, navigation, and attaching to a running Brave instance or a dedicated automation profile.
Transfers files to Dropbox using configured rclone remotes, allowing any-size file uploads to Dropbox.
Allows uploading files to Google Drive in your signed-in browser or via rclone, including large files, by driving the Drive upload form or using a configured remote.
Drives Google Chrome over DevTools (CDP) to upload files by setting file inputs, dropping files, or intercepting file choosers; supports snapshots, navigation, and attaching to a running Chrome instance or a dedicated automation profile.
Copies files to an iCloud Drive folder via local_copy, making them available through Apple's iCloud service.
Integrates with rclone to transfer files to cloud/NAS backends such as S3, R2, SFTP/NAS, Google Drive, Dropbox, OneDrive, and more, using configured remotes.
Pastes files into the Slack desktop app via clipboard_files followed by Cmd+V, effectively uploading files to Slack without native file pickers.
Pastes files into the Telegram desktop app via clipboard_files followed by Cmd+V, effectively uploading files to Telegram without native file pickers.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@filebridgeupload ~/Movies/final.mp4 to my Drive"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
filebridge
Upload any-size files into the browser you're already signed in to, from an AI agent. An MCP server and CLI for Claude Code, Codex and friends that also moves files anywhere else: cloud storage through rclone, a headless upload browser, drives and the clipboard.
Why
"Upload this video to my Drive" fails for agents in three boring ways:
Native file pickers cannot be driven. There is nothing to click, and dragging from Finder is impossible.
Browser-extension uploads are capped at about 10 MB. The file is pushed through the extension, not read from disk.
Headless browsers have no logins. A fresh automation browser is signed out of everything.
filebridge gives the agent four paths around that. Each one hands real disk paths to something that reads the file itself, so there is no size cap.
flowchart LR
A[Agent<br/>Claude Code / Codex] -->|MCP tools or CLI| F[filebridge]
F --> S["1. browser_upload_own<br/>one-time localhost links + JS snippet<br/>into YOUR signed-in browser"]
F --> H["2. CDP browser<br/>set files / drop files / click<br/>(dedicated profile, or attach to yours)"]
F --> R["3. rclone<br/>S3, R2, SFTP/NAS, Drive,<br/>Dropbox, OneDrive, ..."]
F --> L["4. Local helpers<br/>rsync copy, clipboard files"]
S --> W[Website upload form]
H --> W
R --> C[(Cloud / NAS)]
L --> D[Drives, iCloud Drive folder,<br/>Slack / Finder / Mail via Cmd+V]Which path to use:
You want to... | Use |
Upload to a site where you are already signed in, in your everyday browser |
|
Upload to a site with no login, or one you signed into in the automation profile |
|
Drive your own running Chrome/Brave over DevTools |
|
Put files on a store that has an rclone backend (S3/R2, SFTP/NAS, Dropbox, ...) |
|
Copy to a drive, NAS mount or iCloud Drive folder |
|
Paste files into a desktop app (Slack, Telegram, Mail, Finder) |
|
Related MCP server: AKIMCP
Install
Requires Python 3.12+ (uv installs one if needed). Optional: rclone for transfer, Brave or
Chrome for the browser tools.
Nothing to install up front: the MCP config below runs it with uvx. To try the CLI the same way:
uvx --from git+https://github.com/vincesector/filebridge filebridge --helpOr install it for good:
uv tool install git+https://github.com/vincesector/filebridge # or: pip install git+https://github.com/vincesector/filebridge
filebridge --helpPlatform note: developed and tested on macOS. Linux and Windows support (browser discovery on the PATH and in the
standard install folders, xclip / wl-copy and PowerShell Set-Clipboard -Path for the clipboard, xdg-open and
explorer /select, for reveal) is best effort and untested. rclone and browser_upload_own have no
platform-specific code.
Quickstart
Claude Code
claude mcp add filebridge --scope user -- uvx --from git+https://github.com/vincesector/filebridge filebridge mcpOnly need uploads? Add --slim after mcp to expose just the upload tools (browser_upload_own, serve_status,
serve_stop, browser_set_files, browser_drop_files, browser_snapshot, browser_tabs, browser_navigate,
browser_launch) and save context. With uv tool install, the command is just filebridge mcp.
Codex
In ~/.codex/config.toml:
[mcp_servers.filebridge]
command = "uvx"
args = ["--from", "git+https://github.com/vincesector/filebridge", "filebridge", "mcp"]First upload: your own signed-in browser
Ask the agent "upload ~/Movies/final.mp4 to my Drive". It calls browser_upload_own(paths=[...]), which starts a
server on 127.0.0.1 in the background and returns:
{"ok": true, "server_id": "3f9c1a2b7d4e", "urls": ["http://127.0.0.1:53817/<token>/0/final.mp4"],
"snippet": "var __fbUrls=[...]; ... JSON.stringify(__fbRes);", "expires_in_s": 1800}The agent runs snippet in the signed-in tab with any tool that executes JavaScript there (for example the Claude in
Chrome extension's JavaScript tool). The page fetches each file from localhost, then fills the <input type=file>
matching selector, or drops the files on the element at the page centre when there is no selector (how Drive, X and
Typefully listen). The snippet's result is a JSON string: {"ok": true, "action": "dropped", "files": 1, "bytes": ...}
or {"ok": false, "code": "FetchBlocked", "message": ...}. serve_status(server_id) shows what was fetched.
Pass verify_text (for example the file name or "Upload complete") or verify_selector and the result also carries a
verify_snippet: run it after the upload snippet and it waits until the page shows that, returning {verified, waited_s}.
The same from the CLI (prints the URLs and snippet, exits once every file was fetched):
filebridge serve ~/Movies/final.mp4 [--selector 'input[type=file]'] [--ttl 1800]First upload: the automation browser
filebridge browser launch --url https://example.com/upload # headless, dedicated profile
filebridge browser snapshot --tab example.com # lists e1, e2, ... with roles and names
filebridge set-files --tab example.com --ref e3 ~/big.zip --verify-text "Upload complete"For a site that needs a login, sign in once in the automation profile (a visible window, you do the login), then go back to headless:
filebridge browser launch --visible --url https://the-site.example
# log in, then:
filebridge browser launch # headless again, same saved sessionAttach to your browser
browser_launch(mode="attach", cdp_url="http://127.0.0.1:9222") (CLI: filebridge browser attach --cdp-url ...)
connects to a Chrome or Brave you started with remote debugging. filebridge never launches or closes a browser in this
mode; browser_close only detaches. Endpoints must be loopback (127.0.0.1, localhost, ::1). Without cdp_url
it tries http://127.0.0.1:9222, then the DevToolsActivePort file of the default Chrome and Brave profiles.
The honest trade-off: since Chrome 136, --remote-debugging-port is ignored on your default profile (a
hardening against cookie theft). So there are two ways in:
A separate profile you sign into once. Quit nothing; start a second instance with its own folder:
# macOS (Brave: "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser") "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-agent" # Linux: google-chrome --remote-debugging-port=9222 --user-data-dir=$HOME/.chrome-agent # Windows: "%ProgramFiles%\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir=%USERPROFILE%\chrome-agentSign in to the sites you need in that window. Logins persist in that folder. This is close to the built-in dedicated profile, with a visible window you keep using.
Chrome's own toggle, where your Chrome version has it: open
chrome://inspect/#remote-debuggingand enable it. Your normal profile then exposes a websocket (no HTTP/jsonendpoints) and Chrome asks you to allow each new DevTools connection. filebridge opens one connection per tool call, so expect a prompt per call. This path is untested.
Anything that can reach that port can drive the browser and read its cookies, so only bind it to 127.0.0.1 (the
default), and close the debugging instance when you are done.
How the browser paths work
browser_snapshotreturns a compact list of interactive elements (role, name, text) with refs likee12: buttons, links, fields, file inputs (also hidden ones), and drop zones (found through theirdrop/dragoverlisteners or upload-style text).browser_set_files,browser_drop_files,browser_clickandbrowser_typeacceptrefinstead ofselector. Refs are valid until the page navigates or reloads; a stale ref is an error, never a wrong element. Cross-site iframes and closed shadow roots are not in the snapshot (set_files without a selector still finds their file inputs).browser_set_filesuses CDPDOM.setFileInputFiles, so the browser reads the file from disk. It searches the page, open and closed shadow roots, and same-origin and cross-site iframes. Hidden inputs work. With no selector or ref it acts only if exactly one file input exists; otherwise it returns the candidates.browser_drop_filessends realInput.dispatchDragEventevents carrying disk paths. If the page receives no files it falls back to an in-pageDataTransferbuilt from disk-backed File objects (still no size cap, but the events are synthetic,isTrusted=false). The result says which method ran.browser_click(..., files=[...])always intercepts file choosers, so a native picker never appears. Use it for "Upload file" menu items that create the input on click.verify_text/verify_selectoron set_files and drop wait (up toverify_timeout) for the page to show that text or element afterwards and returnverified: true/false.When an upload target is missing and the page looks like a sign-in page (a password field, or a login/auth URL), the error code is
NotSignedIninstead ofSelectorNotFound.browser_navigatealso warns about it.tabis a tab id or a unique part of its URL or title.In headless mode
browser_textandbrowser_screenshotare how you see the page.
CLI reference
Add --json to any command for machine-readable output, and --allow-path DIR (repeatable) to allow reading files
under DIR for that run. Exit code 1 on failure, with the error code printed (error [PathBlocked]: ...). Long jobs
return a job id; add --wait to block until done.
Command | What it does |
| Run the MCP server on stdio (what Claude Code / Codex launch); |
| Serve files to your own signed-in browser with one-time links and print the upload snippet |
| List configured rclone remotes |
| Copy/move/sync between local paths and rclone remotes as a background job |
| Progress of a background job |
| Recent background jobs |
| Stop a running job |
| List a remote or local path |
| Shareable link for a remote file or folder |
| Create a remote folder |
| Does a remote path exist; size and type |
| Exact commands to add a remote (drive, dropbox, onedrive, icloud, s3, r2, sftp) |
| Local rsync copy as a background job |
| Put files on the clipboard as file references |
| Show a path in Finder / the file manager (opens a window) |
| Attach local files to a file input |
| Drag-and-drop local files onto a drop zone |
| Start or reuse the automation browser (headless unless |
| Use your running Chrome/Brave over DevTools (never launched or closed by filebridge) |
| Close the automation browser (profile kept); in attach mode, detach |
| List tabs |
| Interactive elements with refs |
| Point a tab at a URL |
| Read the visible text of a page or element |
| Save a PNG of a tab |
| Click an element; |
| Type into a field |
| Wait for a selector or text |
Paths must be absolute or start with ~. See Security for which files can be read.
MCP tools
The MCP server and the CLI call the same code (filebridge/core.py).
Group | Tools |
Your own browser |
|
CDP browser |
|
rclone |
|
Local |
|
Nothing here deletes anything. move removes the source only after rclone verified the copy. sync can delete on the
destination and requires a prior dry_run (or confirm=true). Copies skip existing files unless overwrite=true.
Errors
Failures come back as {"ok": false, "code": "...", "message": "..."} (plus details such as candidates or path),
with the MCP error flag set when the call itself failed.
Code | Meaning |
| The file matches the hard denylist (keys, |
| Outside the allowed folders and the user said no, or could not be asked. |
| The local path does not exist. |
| Over |
| Selector or ref matched nothing (or the ref is stale). |
| The page looks like a sign-in page. |
| No tab, or several, match |
| A wait, load or command ran out of time. |
| (snippet) The browser could not reach localhost: it blocked the request, or the server already stopped. |
| (snippet) That one-time link was already used. |
| Unknown rclone remote. |
| What they say. |
Security
Which local files can be read
Every tool that reads local files (browser_set_files, browser_drop_files, browser_click(files=),
browser_upload_own / serve, clipboard_files, local_copy, and transfer from a local source) resolves the real
path (following symlinks) and checks it against ~/.filebridge/config.toml, created with these defaults on first run:
allowed_roots = ["~/Projects", "~/Movies", "~/Downloads", "~/Documents", "<cwd>"]
blocked_globs = ["**/.ssh/**", "**/.gnupg/**", "**/*.pem", "**/*.key", "**/id_rsa*", "**/.env", "**/.env.*",
"**/.aws/**", "**/.config/gcloud/**", "**/Library/Keychains/**", "**/.netrc", "**/.npmrc",
"**/.pypirc", "**/*secrets*.json", "**/Cookies", "**/Login Data", "**/.config/rclone/**"]
max_bytes = 0 # largest single file, 0 = no limitBlocked (the requested path or the resolved one matches a blocked glob, case-insensitively): refused with
PathBlocked, always. Approval cannot lift it,FILEBRIDGE_UNRESTRICTEDcannot lift it, and the built-in patterns apply even if you delete them from the file (entries you add extend the list). A folder is scanned and refused if anything inside matches.Inside an allowed root: proceeds.
<cwd>is the folder the MCP client (or the CLI) was started in; it is ignored when that is/or your home folder.Anywhere else: filebridge asks you through MCP elicitation: "filebridge wants to upload /path/file.mov (1.2 GiB) to the automation browser (tab 'drive'). Allow?" Yes allows that one call. No, or a client that does not support elicitation, returns
PathNotAllowednaming theallowed_rootskey to add. The CLI asksy/Non a terminal and refuses when stdin is not a TTY;--allow-path DIRadds a root for one run.FILEBRIDGE_UNRESTRICTED=1in the server environment turns the allowlist off (never the denylist).
The client's own permission mode can auto-accept elicitations. An agent client running in a "bypass permissions" or auto-approve mode may answer "yes" without showing you anything, so treat the allowlist as a convenience and the denylist as the hard floor. Hard links cannot be told apart from the original file, so a hard link to a secret inside an allowed folder is not caught by path rules.
One-time links (browser_upload_own / serve)
The server binds 127.0.0.1 only. Every URL carries a random token, each file URL works exactly once (a second
request gets 410 Gone), and the server stops and closes its socket once every file was fetched or the TTL (default
1800 s) runs out. It sends permissive CORS and Private Network Access headers so a page on another origin can fetch
from it, which is why the token matters: do not paste the URLs or snippet anywhere you do not trust. A file over 1 GiB
gets a warning, because the tab holds the whole file in memory while uploading.
Browsers
The automation browser uses a dedicated profile (
~/.filebridge/browser-profile) with DevTools on127.0.0.1:9229only, and filebridge refuses that port if the listener was not started with that profile or binds beyond loopback. Sign in to only the sites you need.Attach mode talks only to loopback endpoints, refuses a debugging port bound beyond loopback, and never launches or closes your browser. Anything with access to that port controls the browser, so keep it on
127.0.0.1.rclone remotes are configured by a human.
setup_instructionsprints the command; filebridge never configures real accounts. Secrets stay in rclone's own config and are never printed.No
shell=Trueanywhere; subprocesses take argument lists.Job state is stored in
~/.filebridge/jobs/<id>.{json,log}and~/.filebridge/jobs.jsonl.
Limitations
macOS is the tested platform; Linux and Windows are best effort and untested.
browser_clickandbrowser_drop_filesact on the main page and same-origin iframes, not cross-site iframes.Sites with bot detection may block headless Chrome-family browsers. CAPTCHAs and 2FA are the human's job (use the visible sign-in, or attach to your own browser).
browser_upload_ownfetches through the page, so the page's Content Security Policy or the browser's local-network protection can block it (FetchBlocked), and the snippet has to be run in the tab by something that can execute JavaScript there.The
iclouddriverclone backend is fragile (Apple blocks some accounts; Advanced Data Protection must be off). To reach iCloud Drive,local_copyinto its local folder is more reliable.No delete tool, by design.
FAQ
Why not just use the browser extension's upload tool? It caps files at about 10 MB. browser_upload_own exists
for exactly that case: your signed-in tab pulls the file from localhost, no extension cap involved.
Does set_files really have no size limit? The browser reads the file from disk itself. A 300 MB file went through
every browser path with a matching page-side SHA-256.
Will a window pop up on my screen? Not unless you launch with --visible, attach to your own browser, or call
reveal. The automation browser runs --headless=new.
Can I use it without MCP? Yes, every action is a CLI command, so scripts and cron/launchd jobs can use it.
Do I need rclone? Only for transfer, remotes, ls, link, mkdir, stat and setup_instructions.
Why does it ask me before uploading a file? The file is outside your allowed folders. Add the folder to
allowed_roots in ~/.filebridge/config.toml to stop the questions for it.
Development
uv sync
.venv/bin/python tests/test7_policy_offline.py # path policy, elicitation, single-use links, error codes, --slim, config
.venv/bin/python tests/test4_mcp_listing.py # tool list over stdio
.venv/bin/python tests/test_local.py # rsync job, reveal validation
.venv/bin/python tests/test3_clipboard.py # macOS pasteboardTests that need Brave/Chrome (all headless): test8_browser_v02.py (snapshot refs, verification, NotSignedIn, the
upload snippet in a real page, attach mode), test2_browser.py (300 MB through every browser path),
test5_cli_headless.py, test6_browser_extras.py. Needs rclone: test1_transfer.py (2 GiB through a local alias
remote). Manual checks against real sites are in docs/LIVE_TESTS.md; design notes in
docs/DESIGN.md; changes in CHANGELOG.md.
License
This server cannot be deployed
Maintenance
Related MCP Connectors
Use your Mac, Windows or Linux computer from ChatGPT, Claude or Codex: files, commands, documents.
Persistent file storage for AI agents via MCP and curl. Upload, download, and version files.
OCR, transcription, file extraction, and image generation for AI agents via MCP.
Publish and schedule videos to TikTok, YouTube Shorts, Instagram, Facebook, LinkedIn, Pinterest, Bluesky, Threads and X from Claude, Cursor or any MCP client. Upload once, post everywhere, track views in unified analytics, and retry failed posts. Official platform APIs only, free plan available. Docs: https://docs.multi-upload-tool.com/mcp
Related MCP Servers
AlicenseNot gradedqualityCmaintenanceMCP server that enables AI tools to control local browser sessions for ChatGPT, Claude, and other AI services, supporting querying, navigation, file uploads, and artifact management.21 npm567Mozilla Public 2.0- FlicenseNot gradedqualityAmaintenanceConnects web-based AI chat clients such as Claude, ChatGPT, and Grok to a local machine through a single OAuth-gated MCP endpoint so they can browse, read, write, and edit files, run whitelisted shell commands, search content, use Git, query SQLite, drive browsers and DevTools, and manage background tasks, ports, and clipboard. It also exposes localhost and LAN services via a protected HTTP client, letting remote or mobile clients debug and operate local projects without granting unrestricted shell access.-
- AlicenseNot gradedqualityAmaintenanceEnables web-based AI clients such as Claude, ChatGPT, Grok, and Postman to securely operate a local machine through a single OAuth-gated MCP endpoint exposing 38 governed tools. Covers file read/write/edit, whitelisted shell commands, search, Git, SQLite, browser automation, DevTools, background tasks, localhost fetching, clipboard, notifications, port management, and Postman control.MIT
- AlicenseNot gradedqualityAmaintenanceEnables web-based AI clients like Claude, ChatGPT, and Grok to securely operate a local machine through OAuth-gated MCP tools covering files, shell, Git, databases, browser automation, and background tasks.MIT