Open an FTP or FTPS server as a folder in Memona

This commit is contained in:
Danny Kim
2026-09-25 11:57:46 +09:00
commit 95a2b1a086
14 changed files with 1359 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
# Memona FTP plugin
Opens an FTP or FTPS server as a folder in [Memona](https://memona.app), so
files on it are browsed, read, written and renamed like local ones, and agents
work in them.
The plugin is a WebAssembly component built against the Memona filesystem
contract, `memona:filesystem@0.1.0`. It uses only the host's sockets; it has no
ambient filesystem, environment or network access of its own.
## What it registers
One provider, `ftp`, for the `ftp` and `ftps` schemes. A connection is
configured with a server name, an optional port, a TLS toggle for FTPS, and an
optional username and password. An empty username signs in anonymously.
Listing needs a server that answers `MLSD`, the machine-readable listing
command. A server without it reports the folder as unsupported rather than
guessing at the older, human-formatted listing. FTP carries no version token,
so a conditional write is reported as unsupported rather than simulated.
## Passive mode and the port range
Transfers are passive: the plugin asks the server for a data port with `EPSV`
or `PASV` and connects out to it. The server picks a fresh port for every
transfer and announces it only as the transfer begins, so the range that has to
be reachable is wide.
`manifest.json` declares `networkPorts` as 21 and 1024-65535, and `networkHosts`
as `*` because a server can be anywhere. Declaring is not granting: a
connection reaches only the host and ports the person grants it, and a grant
never accepts a wildcard host. Grant the control port and the span the server
uses for its data channel, usually `21` and `1024-65535`.
## Build
```sh
rustup target add wasm32-wasip2
cargo build --locked --release --target wasm32-wasip2
```
The component lands at
`target/wasm32-wasip2/release/memona_plugin_ftp.wasm`.
`sdk/` is a vendored copy of the Memona plugin SDK, the WIT contract plus its
generated Rust bindings, so this repository builds without the Memona repository
present.
## Package for the plugin store
Copy the component to `plugin.wasm` and ZIP it at the archive root together
with `manifest.json`, `README.md` and `LICENSE`:
```sh
cp target/wasm32-wasip2/release/memona_plugin_ftp.wasm plugin.wasm
zip memona-plugin-ftp.memona-plugin \
manifest.json plugin.wasm README.md LICENSE
```
The archive must have no wrapping directory. Memona validates the package and
its digest, and checks the component's imports against the supported WIT API,
before activation.
## License
MIT. See [LICENSE](LICENSE).