# mtp-rs-cli
[](https://crates.io/crates/mtp-rs-cli)
[](https://github.com/vdavid/mtp-rs/actions/workflows/ci.yml)
[](LICENSE-MIT)
A universal MTP file transfer CLI built on [`mtp-rs`](https://crates.io/crates/mtp-rs).
Talk to Android phones, Kindles, Garmin watches, media players, and other MTP devices with the same handful of commands. No `libmtp`, no `libusb`, no FFI. Pure Rust.
## Install
```sh
cargo install mtp-rs-cli
```
The installed binary is called `mtp-rs`.
## Quick tour
```sh
# Show visible devices.
mtp-rs devices
mtp-rs devices --json
# Inspect a specific device and its storages.
mtp-rs info --device SERIAL
# List files.
mtp-rs ls /
mtp-rs ls /Music --recursive
# Upload and download files.
mtp-rs put ./song.mp3 /Music/song.mp3 --replace
mtp-rs get /Music/song.mp3 ./song.mp3
# Create and remove remote objects.
mtp-rs mkdir /Upload
mtp-rs rm /Upload/old.bin --yes
# Rename, move, and copy remote objects.
mtp-rs rename /Upload/old.bin new.bin
mtp-rs mv /Upload/new.bin /Archive/new.bin
mtp-rs cp /Archive/new.bin /Archive/new-copy.bin
# Diagnose access, storage, and common USB ownership issues.
mtp-rs doctor
```
Remote paths are POSIX-like and absolute: `/`, `/Music/song.mp3`, `/GARMIN/APPS/app.prg`. Device-specific workflows are just normal file operations. For example, Garmin Connect IQ sideloading is:
```sh
mtp-rs put ./MyApp.prg /GARMIN/APPS/MyApp.prg --replace --verify
```
## What you get
- **One CLI, every device**: phones, watches, e-readers, media players. If it speaks MTP, this works.
- **JSON output** with `--json`: every command emits structured JSON for shell pipelines and scripts.
- **Stable exit codes**: 0 success, 2 no device, 3 ambiguous selection, 4 access denied, 5 bad remote path, 6 transfer error, 7 verification failed.
- **Streaming transfers**: large uploads and downloads stream straight from disk to USB and back. No silent in-memory buffering.
- **`--verify` for uploads**: read the file back from the device and byte-compare it against the local source.
- **Cross-platform**: Linux, macOS, Windows.
## Docs
See [docs/cli.md](docs/cli.md) for the full command reference: every flag, JSON schemas, exit codes, path semantics, and troubleshooting.
## Platform notes
The CLI inherits the platform quirks of the underlying [`mtp-rs`](https://crates.io/crates/mtp-rs) library. The big one to know about is macOS:
- macOS ships `ptpcamerad` which grabs MTP devices on connect. You may need to kill it (`pkill -9 ptpcamerad`) or disable it (`sudo launchctl disable system/com.apple.ptpcamerad`) before the CLI can open a device.
- Quit `Android File Transfer.app` if you have it installed. It also grabs devices on connect.
- Recent macOS can deny USB access to processes started from background agents or random tool runners. If `mtp-rs devices` lists a device but `info` or `get` fails, try running from Terminal or iTerm with the Mac unlocked.
- On Linux, you may need udev rules. See the [lib README](../mtp-rs/README.md) for the snippet.
- Windows should work out of the box but is not extensively tested.
## Garmin sideloading example
```sh
# Find the watch.
mtp-rs devices
# Push a Connect IQ app to the watch, replace if it exists, verify after.
mtp-rs put ./MyField.prg /GARMIN/APPS/MyField.prg --replace --verify
```
The CLI auto-detects Garmin watches that expose MTP as a vendor-class interface with an `MTP` interface string (Venu 2/2S, and likely others).
## Contributing
See [CONTRIBUTING.md](../../CONTRIBUTING.md) in the repo root.
## Credits
Originally contributed by [Dmitry Tretyakov](https://github.com/dtretyakov) in [#11](https://github.com/vdavid/mtp-rs/pull/11). Maintained by [David Veszelovszki](https://github.com/vdavid).
## License
MIT OR Apache-2.0, at your option.