File Transfers
Serial file transfers are useful when you need to move files to or from devices that lack network connectivity: embedded systems running a bootloader, legacy industrial equipment, air-gapped machines, or remote hardware accessed through a serial console.
All of the operations described in this guide are performed through your MCP client. Ask the assistant to send or receive files, and it will call the appropriate mcserial transfer tools on your behalf. The tool call notation below shows exactly what the assistant invokes.
mcserial implements four protocol variants, all built in without external dependencies.
Protocol comparison
Section titled “Protocol comparison”| Protocol | Block Size | Batch | Resume | Error Detection | Best For |
|---|---|---|---|---|---|
| XMODEM | 128 bytes | No | No | Checksum or CRC-16 | Legacy compatibility, simple devices |
| XMODEM-1K | 1024 bytes | No | No | CRC-16 | Faster XMODEM with wider block size |
| YMODEM | 1024 bytes | Yes | No | CRC-16 | Multiple files, preserves filenames |
| ZMODEM | Streaming | Yes | Yes | CRC-32 | Everything else (recommended) |
ZMODEM is the recommended protocol in nearly all cases. It streams data without waiting for per-block acknowledgment, supports batch transfers, can resume interrupted transfers, and uses 32-bit CRC for reliable error detection.
Use XMODEM only when the remote device does not support anything newer — some bootloaders and legacy equipment only speak XMODEM.
Sending a file
Section titled “Sending a file”Use file_transfer_send to transmit a file to the remote device.
// file_transfer_send(// port="/dev/ttyUSB0",// file_path="/home/user/firmware.bin",// protocol="zmodem"// ){ "success": true, "protocol": "zmodem", "file": "/home/user/firmware.bin", "bytes_sent": 65536, "blocks_sent": 64}Receiving a file
Section titled “Receiving a file”Use file_transfer_receive to download a file from the remote device.
The meaning of save_path depends on the protocol:
- XMODEM:
save_pathis the full file path (e.g.,/tmp/received.bin). XMODEM does not transmit filenames. - YMODEM / ZMODEM:
save_pathis a directory. The filename comes from the sender’s metadata.
// Receiving with XMODEM (save_path is a file path)// file_transfer_receive(// port="/dev/ttyUSB0",// save_path="/tmp/received.bin",// protocol="xmodem"// ){ "success": true, "protocol": "xmodem", "file": "/tmp/received.bin", "bytes_received": 8192}
// Receiving with ZMODEM (save_path is a directory)// file_transfer_receive(// port="/dev/ttyUSB0",// save_path="/tmp/downloads/",// protocol="zmodem"// ){ "success": true, "protocol": "zmodem", "files_received": 1, "bytes_received": 65536}Set overwrite=true if you want to replace existing files at the destination. By default, the transfer fails if a file already exists.
Batch transfers
Section titled “Batch transfers”YMODEM and ZMODEM support sending multiple files in a single session. Use file_transfer_send_batch:
// file_transfer_send_batch(// port="/dev/ttyUSB0",// file_paths=[// "/home/user/firmware.bin",// "/home/user/config.json",// "/home/user/certs/device.pem"// ],// protocol="zmodem"// ){ "success": true, "protocol": "zmodem", "files_sent": 3, "total_bytes": 98304}XMODEM does not support batch transfers — it has no concept of filenames or session boundaries. If you try to use file_transfer_send_batch with XMODEM, you will get an error.
Security
Section titled “Security”mcserial validates all file paths during transfers:
- Directory traversal prevention: Filenames received from the remote side are sanitized. Paths containing
..or absolute path components are rejected. - Overwrite protection: By default, receiving a file that already exists on disk returns an error. Pass
overwrite=trueto allow replacement. - Parent directory creation: When receiving, mcserial creates parent directories as needed using
mkdir -pbehavior.
Practical example: uploading firmware
Section titled “Practical example: uploading firmware”This example walks through uploading a firmware binary to an embedded device over its serial debug port.
-
Open the serial port at the bootloader’s baud rate
Most bootloaders use 115200 baud. Check your device’s documentation.
// open_serial_port(port="/dev/ttyUSB0", baudrate=115200){"success": true,"port": "/dev/ttyUSB0","baudrate": 115200} -
Reset the device into bootloader mode
For an Arduino-style device, pulse DTR. For other devices, you may need to hold a specific button or send a command.
// pulse_line(port="/dev/ttyUSB0", line="dtr", duration_ms=100, active_low=true) -
Wait for the bootloader prompt
Read lines until you see the bootloader’s ready message.
// read_serial_lines(port="/dev/ttyUSB0", max_lines=10){"success": true,"lines": ["Bootloader v2.1","Waiting for XMODEM transfer..."],"count": 2} -
Send the firmware file
Match the protocol to what the bootloader expects. Many embedded bootloaders support XMODEM; more capable ones may support YMODEM or ZMODEM.
// file_transfer_send(// port="/dev/ttyUSB0",// file_path="/home/user/build/firmware.bin",// protocol="xmodem"// ){"success": true,"protocol": "xmodem","file": "/home/user/build/firmware.bin","bytes_sent": 32768,"blocks_sent": 256} -
Verify the device booted with the new firmware
After the transfer completes, the bootloader typically flashes the firmware and reboots. Read the startup output to confirm.
// read_serial_lines(port="/dev/ttyUSB0", max_lines=10){"success": true,"lines": ["Firmware v3.0.1 loaded","CRC OK","Booting..."],"count": 3}
Protocol details
Section titled “Protocol details”XMODEM
Section titled “XMODEM”The oldest and simplest protocol (1977). Data is sent in 128-byte blocks with a 1-byte checksum or 16-bit CRC. The receiver must acknowledge each block before the next is sent, which makes it slow on high-latency connections.
XMODEM-1K is identical except it uses 1024-byte blocks, reducing overhead.
YMODEM
Section titled “YMODEM”An extension of XMODEM that adds batch capability. The first block of each file contains the filename and size as metadata. After all files are sent, a null filename block signals the end of the batch.
ZMODEM
Section titled “ZMODEM”A streaming protocol that does not wait for per-block acknowledgments. It sends data continuously and only pauses if the receiver reports an error. Features include:
- Auto-start: receivers detect the ZMODEM init sequence and begin automatically
- Resume: interrupted transfers can pick up where they left off
- CRC-32: stronger error detection than XMODEM/YMODEM’s CRC-16
- Variable block size: adapts to line quality
Error Recovery
Section titled “Error Recovery”Interrupted Transfers
Section titled “Interrupted Transfers”Transfers can fail due to cable disconnection, power loss, or communication errors. Each protocol handles recovery differently:
| Protocol | Recovery Method | Resume Supported |
|---|---|---|
| XMODEM | Restart from beginning | No |
| XMODEM-1K | Restart from beginning | No |
| YMODEM | Restart from beginning | No |
| ZMODEM | Automatic resume from interruption point | Yes |
ZMODEM resume: When a ZMODEM transfer is interrupted and restarted, the receiver compares the incoming file header with any partial file on disk. If the file matches (same name, size, and modification time), it requests the sender to skip already-received data:
// Transfer interrupted at 50% — just retry// file_transfer_send(// port="/dev/ttyUSB0",// file_path="/home/user/large_firmware.bin",// protocol="zmodem"// ){ "success": true, "protocol": "zmodem", "bytes_sent": 32768, "resumed_at": 32768, "total_size": 65536}For XMODEM and YMODEM, you must delete the partial file on the receiver and restart the entire transfer.
Detecting Partial Transfers
Section titled “Detecting Partial Transfers”ZMODEM and YMODEM include file size metadata in their headers. XMODEM does not — it pads the final block to 128 or 1024 bytes, so the received file may be slightly larger than the original.
Verify transfer integrity:
- Compare file sizes — YMODEM/ZMODEM receivers know the expected size
- Check CRC/hash — calculate a checksum on both ends
- Look for padding — XMODEM files end with padding bytes (typically 0x1A or 0x00)
Block Corruption
Section titled “Block Corruption”All protocols detect corruption via checksum or CRC. When corruption is detected:
- Receiver sends NAK — requests retransmission
- Sender resends block — the same block, not the entire file
- Retry limit — after several failed attempts, the transfer aborts
Excessive retries indicate:
- Electrical noise — use shielded cables, shorter runs
- Baud rate too high — reduce speed for better reliability
- Flow control mismatch — enable RTS/CTS if available
// Conservative settings for unreliable links// configure_serial(port="/dev/ttyUSB0", baudrate=9600, rtscts=true)Common Transfer Errors
Section titled “Common Transfer Errors”| Error | Likely Cause | Solution |
|---|---|---|
| ”Receiver not ready” | Receiver not started | Start receiver before sender |
| Immediate timeout | Wrong protocol | Match protocol on both ends |
| Repeated NAKs | Line noise or baud mismatch | Lower baud rate, check cables |
| File exists error | Overwrite protection | Pass overwrite=true or delete existing |
| Size mismatch | XMODEM padding | Use YMODEM/ZMODEM for exact sizes |