Skip to content

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.

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.

probe-mcp exposes eight remote-fs tools, all prefixed probe_. Each is a thin wrapper over the REST endpoints below.

List every open Files connection. No parameters. Returns each connection's id, protocol, host, server label, home path, and whether the transport is encrypted.

List a directory's entries.

| 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. |

Returns: each entry's name, path, isDir, size, and — when the backend reports them — modifiedMs, permissions, owner, symlinkTarget.

Create a directory.

| Parameter | Type | Description | | --- | --- | --- | | connection_id | string | Required. | | path | string | Required. Absolute path of the directory to create. |

Rename or move an entry.

| Parameter | Type | Description | | --- | --- | --- | | connection_id | string | Required. | | from | string | Required. Current absolute path. | | to | string | Required. New absolute path. |

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 }is_dir (default false) tells backends like S3 that distinguish an object from a prefix. |

Enqueue a download to a local file. Returns a transferId immediately — poll probe_remote_fs_transfers for progress.

| Parameter | Type | Description | | --- | --- | --- | | connection_id | string | Required. | | remote_path | string | Required. Absolute remote source path. | | local_path | string | Required. Absolute local destination path. |

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 local source path. | | remote_path | string | Required. Absolute remote destination path. |

List the transfer queue. No parameters. Returns every tracked transfer with its transferId, connectionId, kind, state (queued / running / paused / done / cancelled / error), remote and local paths, and byte offset.

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" } | { "path", "entries": [ … ] } | | 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 } | | POST /remote-fs/connections/{id}/download | { "remote_path": "…", "local_path": "…" } | 202 · { "transferId": "tr_…" } | | POST /remote-fs/connections/{id}/upload | { "local_path": "…", "remote_path": "…" } | 202 · { "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.

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 | | I/O or transport failure | 500 |

Terminal window
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 connection
CID=$(curl -s -H "Authorization: Bearer $TOKEN" \
"$BASE/remote-fs/connections" | jq -r '.connections[0].id')
# 2. List a directory
curl -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 queue
curl -s -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"remote_path":"/var/www/config.yaml","local_path":"/tmp/config.yaml"}' \
"$BASE/remote-fs/connections/$CID/download"
# {"transferId":"tr_rest_..."}
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/remote-fs/transfers" | jq