feat: support glob patterns and directories in send_files and receive_files
Apra Fleet is an open-source MCP server
Brought to you by:
apralabs
Originally created by: kumaakh
send_files and receive_files currently accept only individual file paths. To send a directory like src/, you must enumerate every file manually. This is cumbersome and error-prone.
Support glob patterns and directory paths in local_paths (for send_files) and remote_paths (for receive_files):
{ "local_paths": ["src/", "tests/*.ts"] }
scp -r or rsyncsrc/services/sftp.ts — uploadViaSFTP / downloadViaSFTPsrc/services/file-transfer.tssrc/tools/send-files.ts, src/tools/receive-files.ts — schema descriptions🌱 This is a good first issue for contributors familiar with Node.js fs and SSH/SFTP.
Originally posted by: kumaakh
Technical direction: Extend
src/services/sftp.tswith recursive directory and glob support, then expose it through the tool schemas.Approach:
src/services/sftp.ts(uploadViaSFTP): before the transfer loop, expand each path: if it is a directory, walk it recursively withfs.readdirSync/fs.statSyncto produce a flat list of files with their relative paths preserved. If it contains glob characters, expand with a library likefast-glob(already likely in devDeps via vitest) or Node 22fs.glob.downloadViaSFTP(receive side): use the SFTPreaddir+statAPI to walk remote directories recursively.src/foo/bar.tsuploaded todest_subdirshould land atdest_subdir/src/foo/bar.ts, notdest_subdir/bar.ts.src/tools/send-files.tsandsrc/tools/receive-files.tsto document glob and directory support.Key files:
src/services/sftp.ts— core recursive walksrc/services/file-transfer.ts— may need changes if it wraps sftpsrc/tools/send-files.ts,src/tools/receive-files.ts— schema descriptionsRelated
Tickets:
#175Originally posted by: kumaakh
Research: Glob Pattern Support in send_files / receive_files
1. Where does path expansion happen today?
It doesn't. Paths are treated as literal file references throughout the pipeline:
src/tools/send-files.ts:61-79— iteratesinput.local_pathsfor basename collision checks, then passes array directly tostrategy.transferFiles()src/tools/receive-files.ts:37-59— validates eachremote_pathfor null bytes and work folder containment, then passes array tostrategy.receiveFiles()src/services/strategy.ts—LocalStrategy.transferFiles()(line 99-122) andRemoteStrategy.transferFiles()(line 32-34) both loop over paths withfs.copyFileSync()or SFTPfastPut()src/services/sftp.ts:57-87(uploadViaSFTP) — loops overlocalPathscallingsftp.fastPut()per filesrc/services/sftp.ts:89-117(downloadViaSFTP) — loops overremotePathscallingsftp.fastGet()per fileNo glob expansion or directory traversal occurs anywhere.
2. Existing glob library?
None installed. Current deps:
ssh2,zod,uuid,smol-toml,@inquirer/password,@modelcontextprotocol/sdk.Recommendation:
fast-glob"type": "module"), full cross-platform supportAlternative: Node.js built-in
fs.glob()(available since 18.17, but still experimental — project targets Node 22+)3. Minimal code changes needed
src/utils/glob-expansion.tsexpandLocalGlobs(patterns, basePath)andexpandRemoteGlobs(agent, patterns, basePath)utility functionssrc/tools/send-files.tsexpandLocalGlobs()after input validation, BEFORE basename collision check (line ~58). Update schema description (line 13).src/tools/receive-files.tssrc/services/strategy.tsRemoteStrategy.receiveFiles()needs remote glob expansion logic (shell command over SSH, parse results)package.jsonfast-globdependencyThe
receive_filesremote case is the trickiest — glob expansion must happen on the member's filesystem, not locally.4. Edge cases and risks
fast-globhas built-in loop detection; use{ followSymbolicLinks: false }by default**/*on thousands of files could be slow/memory-heavymaxResultslimit (e.g. 1000); document performance implications../../../etc/passwdcould escape work_folder..); validate all results with existingisContainedInWorkFolder()fast-globhandles this internally;src/utils/platform.ts:9-30already normalizes paths*.txtcould match files with same basename in different dirs*doesn't match dotfiles by default (standard glob behavior).*is needed for dotfiles5. Complexity estimate
MEDIUM (~11-15 hours)
Not SMALL because remote expansion and cross-platform edge cases require careful handling. Not LARGE because the core logic is simple and existing validation patterns can be reused.