Automation (REST & MCP)
Every Files operation except opening a connection is available over Probe's internal REST API and, through it, the MCP server. That lets a script — or an AI assistant in Claude or Cursor — list a bucket, download an object, tidy a directory, or push a build artifact as part of a larger task, against connections you've already opened in the app. These calls run beside your own work in the Files tab: a listing never moves the folder you're looking at, and a long transfer doesn't hold up other commands.
Why there is no connect endpoint
Section titled “Why there is no connect endpoint”There is deliberately no REST or MCP way to open a connection. Credentials — passwords and S3 secret keys — stay entirely in the UI path: they cross into Probe's core once, at connect time, and are never persisted there, and the loopback REST surface is meant for local AI tooling that should not carry secrets. So the automation surface can only operate on connections you have already opened in the app. It lists them and drives file operations and transfers against their ids.
MCP tools
Section titled “MCP tools”probe-mcp exposes nine remote-fs tools, all prefixed probe_. Each is a thin wrapper over the REST endpoints below.
probe_list_remote_fs_connections
Section titled “probe_list_remote_fs_connections”List every open Files connection. No parameters. Returns each connection's id, protocol, host, server label, home path, and whether the transport is encrypted.
probe_remote_fs_list_dir
Section titled “probe_remote_fs_list_dir”List a directory's entries, one page at a time.
| Parameter | Type | Description |
|---|---|---|
connection_id | string | Required. Id from probe_list_remote_fs_connections. |
path | string | Required. Absolute remote directory path, e.g. /var/www. |
cursor | string | next_cursor from the previous page; omit it for the first page. |
limit | integer | Entries per page, 1–5000 (default 500). |
Returns: each entry's name, path, isDir, size, and — when the backend reports them — modifiedMs, permissions, owner, symlinkTarget; total (entries in the directory) and next_cursor (null on the last page).
probe_remote_fs_mkdir
Section titled “probe_remote_fs_mkdir”Create a directory.
| Parameter | Type | Description |
|---|---|---|
connection_id | string | Required. |
path | string | Required. Absolute path of the directory to create. |
probe_remote_fs_rename
Section titled “probe_remote_fs_rename”Rename or move an entry.
| Parameter | Type | Description |
|---|---|---|
connection_id | string | Required. |
from | string | Required. Current absolute path. |
to | string | Required. New absolute path. |
probe_remote_fs_delete
Section titled “probe_remote_fs_delete”Delete one or more entries.
| Parameter | Type | Description |
|---|---|---|
connection_id | string | Required. |
paths | array | Required. Entries to delete. Each item is { "path": string, "is_dir"?: boolean } (a probe_remote_fs_list_dir entry works as-is: its isDir is used and name, size, modifiedMs, permissions, owner, symlinkTarget are ignored; any other member is refused) — is_dir (default false) tells backends like S3 that distinguish an object from a prefix. |
Directory deletes are recursive on S3 (every object under the prefix) and WebDAV (the server deletes the whole collection), and not recursive on SFTP and FTP/FTPS, where a non-empty directory fails. Every path is attempted even if an earlier one fails; the result lists deleted, and failed entries ({path, error: {code, message}}) when some couldn't be removed.
probe_remote_fs_download
Section titled “probe_remote_fs_download”Enqueue a download to a local file. Returns a transferId immediately — poll probe_remote_fs_transfers for progress, or stop it with probe_remote_fs_cancel_transfer. The transfer also shows in the app's transfer queue, where you can pause or cancel it.
| Parameter | Type | Description |
|---|---|---|
connection_id | string | Required. |
remote_path | string | Required. Absolute remote source path. |
local_path | string | Required. Absolute local destination path inside ~/Downloads or Probe's transfers folder ~/.probe/transfers (Windows: %USERPROFILE%\Downloads, %USERPROFILE%\.probe\transfers). A relative path, a .., a symbolic link, a directory, a missing folder or a path outside those folders is refused. |
overwrite | boolean | Replace local_path if it exists. Default false: an existing file is refused. |
probe_remote_fs_upload
Section titled “probe_remote_fs_upload”Enqueue an upload of a local file. Returns a transferId immediately — poll probe_remote_fs_transfers.
| Parameter | Type | Description |
|---|---|---|
connection_id | string | Required. |
local_path | string | Required. Absolute path of an existing regular file inside ~/Downloads or Probe's transfers folder ~/.probe/transfers (Windows: %USERPROFILE%\Downloads, %USERPROFILE%\.probe\transfers) — copy another file there first. Symbolic links are refused. |
remote_path | string | Required. Absolute remote destination path. |
probe_remote_fs_transfers
Section titled “probe_remote_fs_transfers”List the transfer queue: active transfers plus the 100 most recently finished. No parameters. Returns each transfer's transferId, connectionId, kind, state (queued / running / paused / done / cancelled / error), remote and local paths, byte offset, and — in the error state — error: { code, message }.
probe_remote_fs_cancel_transfer
Section titled “probe_remote_fs_cancel_transfer”Cancel a queued, running or paused transfer, whether it started in the app or over MCP. It stays in the queue with state cancelled; a partly written destination file is left in place. Errors for an unknown id or a transfer that already finished.
| Parameter | Type | Description |
|---|---|---|
transfer_id | string | Required. transferId from a download/upload or probe_remote_fs_transfers. |
REST endpoints
Section titled “REST endpoints”All paths are under http://127.0.0.1:<port>/api/v1/ and require the Authorization: Bearer <token> header — see Discovery & auth. Connection ids are URL-encoded in the path.
| Method & path | Body | Returns |
|---|---|---|
GET /remote-fs/connections | — | { "connections": [ … ] } |
GET /remote-fs/transfers | — | { "transfers": [ … ] } |
POST /remote-fs/connections/{id}/list | { "path": "/var/www", "cursor"?, "limit"? } | { "path", "entries": [ … ], "total", "next_cursor" } |
POST /remote-fs/connections/{id}/mkdir | { "path": "/var/www/new" } | { "ok": true } |
POST /remote-fs/connections/{id}/rename | { "from": "…", "to": "…" } | { "ok": true } |
POST /remote-fs/connections/{id}/delete | { "paths": [ { "path": "…", "is_dir": false } ] } | { "ok": true, "deleted": [ … ] } · 207 with failed on partial success |
POST /remote-fs/connections/{id}/download | { "remote_path": "…", "local_path": "…", "overwrite": false } | 202 · { "transferId": "tr_…" } |
POST /remote-fs/connections/{id}/upload | { "local_path": "…", "remote_path": "…" } | 202 · { "transferId": "tr_…" } |
POST /remote-fs/transfers/{id}/cancel | — | { "ok": true, "transferId": "tr_…" } |
Transfers are asynchronous: the enqueue call returns 202 Accepted with a transferId, and you poll GET /remote-fs/transfers to watch it move through queued → running → done.
Errors
Section titled “Errors”Failures return { "error": { "code", "message" } } with an HTTP status matched to the cause:
| Cause | HTTP |
|---|---|
| Auth / permission denied | 403 |
| Not found | 404 |
| Already exists / cancelled | 409 |
| Host unreachable / host key rejected | 502 |
| Unsupported / protocol error | 400 |
Invalid local_path (code invalidArgument), or cancelling a finished transfer | 400 |
| I/O or transport failure | 500 |
The Files engine didn't answer in time (code timeout) | 504 |
Example
Section titled “Example”PORT=$(jq -r .port ~/.probe/api-handshake.json)TOKEN=$(jq -r .token ~/.probe/api-handshake.json)BASE="http://127.0.0.1:$PORT/api/v1"
# 1. Find an open connectionCID=$(curl -s -H "Authorization: Bearer $TOKEN" \ "$BASE/remote-fs/connections" | jq -r '.connections[0].id')
# 2. List a directorycurl -s -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"path":"/var/www"}' \ "$BASE/remote-fs/connections/$CID/list" | jq
# 3. Enqueue a download, then poll the queuecurl -s -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"remote_path":"/var/www/config.yaml","local_path":"/Users/me/Downloads/config.yaml"}' \ "$BASE/remote-fs/connections/$CID/download"# {"transferId":"tr_rest_..."}
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/remote-fs/transfers" | jq