Announcing mtp-rs: pure-Rust MTP library, 4x faster than libmtp

Pure-Rust async MTP/PTP, no C dependencies. 1.06–4.04x faster than libmtp.

Why I built this

I’m building Cmdr, a file manager. I wanted to add phone file access. I copy family photos from our phones regularly, and it’s also a great way to test my own file manager.

The protocol for talking to phones over USB is MTP (Media Transfer Protocol). The go-to library for it is libmtp, a C library that’s been around for ~20 years. All the Rust options were wrappers around it.

I thought, maybe we can roll our own in Rust and make it faster? Turns out, yes. Quite a lot faster.

Also, TBH, I’m not a seasoned Rust dev, and when I saw the word unsafe, it scared me. 😅 So I wanted to avoid C bindings to avoid unsafe code. My current understanding is that unsafe isn’t really meant to be scary, but it scared me, so I decided to write this Rust lib.

What it does

mtp-rs is a pure-Rust, async MTP/PTP library. No C dependencies, no libmtp, no libusb, no FFI. Built on top of nusb for USB access.

It has two layers:

  • mtp:: for Android phones and media devices (list, download, upload, delete, move, copy, rename)
  • ptp:: for cameras and low-level protocol work (device properties, capture, raw operations)

MTP is built on top of PTP, and the library reflects that.

Tested with:

  • Pixel 9 Pro XL (my phone)
  • Samsung Galaxy S23 Ultra (my wife’s phone)
  • Fujifilm X-T4 (my camera — for PTP)

It handles device quirks automatically. Android’s recursive listing is broken, Samsung returns errors for root listing, Fuji advertises write support it doesn’t actually have. mtp-rs detects and works around these. To be fair, libmtp does this to tens of thousands of devices, but my research found that none of those devices are really interesting now. Anything built in the past 10 years should be covered by mtp-rs, too. That said, we definitely need to test with more devices. So far, all three devices I tried needed 1–2 lines of change (but not more!).

Quick start

Benchmarks

I benchmarked mtp-rs against libmtp on a Pixel 9 Pro XL. 5 warmup + 10 measured runs per scenario.

OperationSizemtp-rslibmtpSpeedup
Download1 MB34 ms45 ms1.34x
Download10 MB258 ms391 ms1.51x
Download100 MB2,447 ms9,897 ms4.04x
Upload1 MB76 ms115 ms1.51x
Upload10 MB327 ms345 ms1.06x
Upload100 MB2,388 ms2,796 ms1.17x
List files16 ms25 ms1.61x

Median times, Pixel 9 Pro XL, USB, macOS, from 5 warmup + 10 measured runs.

mtp-rs is 1.06–4.04x faster across all operations. The advantage grows with file size for downloads.

But the most interesting part is consistency. At 100 MB download:

  • mtp-rs std dev: 4.7 ms (0.2% of median!)
  • libmtp std dev: 4,612 ms (46.6% of median!)

libmtp’s 100 MB downloads ranged from 3.7s to 18.2s. That’s a 5x spread. mtp-rs stayed within a 15 ms band. With mtp-rs, a 100 MB transfer always takes ~2.4s. With libmtp, you might wait 4s or 18s.

People say MTP is slow. Some use ADB instead to copy their photos. I think MTP isn’t actually slow. libmtp has been the only real option for ~20 years, and it supports an impressive number of legacy devices. That overhead adds up. I wonder if more people would use MTP if it was 4x faster.

The benchmark tool is in the repo. You can reproduce it with any MTP device:

cargo run -p mtp-bench -- --warmup 5 --runs 10

How I built it

I don’t know Rust. I’d never written Rust before 2026. But I’ve built software for ~4 decades, so I know how to do it, and with the right tools, it’s very fast these days. So I took my friend Claude to help me, and we shipped this in about 5 coding days.

The timeline:

  • Day 1 (Jan 30): From zero to working library. Spec → types → protocol → transport → high-level API → integration tests. Also handled Android quirks and Samsung fallback. 21 commits.
  • Day 2 (Jan 31): More Samsung fixes, docs rewrite.
  • Day 3 (Feb 1): PTP camera support.
  • Day 4 (Feb 2): Fujifilm camera testing, directory listing performance.
  • Day 5 (Feb 3): Big polish day. Streaming, property-based testing (proptest), refactoring, Rust 1.75 compatibility. 28 commits.

Then some cleanup, v0.1.0 on crates.io (Feb 20), benchmarks + v0.2.0 (Mar 17).

You can see how the codebase evolved on gitstrata (also my project, source on GitHub).

Now, “Built with AI” can easily sound like “vibe-coded crap”. I get that. Here’s why I don’t think it is:

  • The best proof for me: I personally tested it on 3 physical devices. I’ve now used it to copy my personal files for a few weeks without issue.
  • We have an extensive test suite: unit tests, property-based tests (proptest), and fuzz tests on all parsers.
  • I run clippy, cargo deny, and cargo audit in CI on all of Linux, macOS, and Windows.

Btw, the MTP spec is a 282-page PDF from USB.org. Not great for feeding to AI agents. I converted it to Markdown in about an hour. Pretty cool as a standalone resource. I sent it to mtp-chair@usb.org to see if they’d use/link it, but haven’t heard back. 🤷‍♂️

Try it!

cargo add mtp-rs

The quickest way to verify it works with your device:

# Clone the repo and run the read-only integration tests
git clone https://github.com/vdavid/mtp-rs && cd mtp-rs
cargo test --test integration readonly -- --ignored --nocapture --test-threads=1

This connects to your device, lists storages and files, and downloads a file. Read-only, won’t write anything.

There are also runnable examples in the repo for listing files, downloading images, and camera diagnostics.

Links:

Help me test it!

I’ve tested mtp-rs with 2 phones and a camera. There are thousands of MTP devices out there: Android phones from every brand, e-readers, Kindles, cameras. I need community help to test with devices I don’t have.

If you have an MTP device and 5 minutes, try it and open an issue if something doesn’t work. Every device test makes this better for everyone. But honestly, a PR is even better because even if I hear about a device not working, I can’t test it. I recommend taking and agentic coding tool to run the tests on your phone and fix it until it works. I designed the test suite so that only read-only tests will run until you feel confident enough to do the write tests too. So it won’t accidentally brick/wipe your device even if it’s incompatible because of a quirk. Thanks for any help in advance!