Files
memona-plugin-ftp/README.md
T
Danny Kim 55a4f458b6
CI / checks (pull_request) Successful in 1m6s
Explain connection permissions and supported transports
2026-09-30 15:46:45 +09:00

78 lines
3.1 KiB
Markdown

# 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.
In Memona's connection permissions, enter the server's hostname or IP in
**Allowed hosts**, without a scheme, port or path. An empty list blocks the
connection. Turn on **Private network** as well for localhost or a private
network; this switch does not grant a host by itself. Save and reconnect after
changing permissions.
The TLS toggle currently starts TLS on the control connection only. Protected
data connections and explicit `AUTH TLS` negotiation are not implemented, so
the plugin does not yet provide a complete FTPS connection.
Listing and stat need a server that answers `MLSD` and `MLST`, the
machine-readable listing commands. A server without them reports the folder as
unsupported rather than guessing at the older, human-formatted listing or
changing its working directory to find out. 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`
and connects out to it; `PASV` fallback is not implemented. 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).