task_transfer_multi
Execute multiple SFTP file transfers using glob patterns (*, ?, []) for batch uploads or downloads between local and remote systems.
Instructions
Lance des transferts SFTP multiples avec support de patterns glob (*, ?, []).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| alias | Yes | Alias du serveur cible. | |
| direction | Yes | ||
| files | Yes | Liste des fichiers à transférer | |
| rappel | No | Définit un rappel en secondes. |
Implementation Reference
- server.js:526-542 (handler)The inline handler function for the 'task_transfer_multi' tool. It creates a job with the files array, logs it, triggers the SFTP multi-transfer execution, awaits completion or timeout, and returns the result or background notification.async (params) => { const job = queue.addJob({ type: 'sftp', ...params, status: 'pending', files: params.files }); history.logTask(job); sftp.executeMultiTransfer(job.id); const finalJob = await waitForJobCompletion(job.id, config.syncTimeout); if (finalJob) { return { content: [{ type: "text", text: `Résultat transferts multiples (tâche ${finalJob.id}):\n${JSON.stringify(finalJob, null, 2)}` }] }; } else { return { content: [{ type: "text", text: `Tâche de transferts multiples ${job.id} initiée en arrière-plan.` }] }; } }
- server.js:513-525 (schema)Input schema definition for the task_transfer_multi tool, including parameters for server alias, direction, list of local/remote file pairs supporting globs, and optional reminder.{ title: "Transférer plusieurs fichiers/dossiers (SFTP)", description: "Lance des transferts SFTP multiples avec support de patterns glob (*, ?, []).", inputSchema: z.object({ alias: z.string().describe("Alias du serveur cible."), direction: z.enum(['upload', 'download']), files: z.array(z.object({ local: z.string().describe("Chemin local ou pattern glob (ex: /home/*.txt)"), remote: z.string().describe("Chemin distant") })).describe("Liste des fichiers à transférer"), rappel: z.number().optional().describe("Définit un rappel en secondes.") }) },
- server.js:511-543 (registration)Full registration of the task_transfer_multi tool on the MCP server, including name, schema, and handler function.server.registerTool( "task_transfer_multi", { title: "Transférer plusieurs fichiers/dossiers (SFTP)", description: "Lance des transferts SFTP multiples avec support de patterns glob (*, ?, []).", inputSchema: z.object({ alias: z.string().describe("Alias du serveur cible."), direction: z.enum(['upload', 'download']), files: z.array(z.object({ local: z.string().describe("Chemin local ou pattern glob (ex: /home/*.txt)"), remote: z.string().describe("Chemin distant") })).describe("Liste des fichiers à transférer"), rappel: z.number().optional().describe("Définit un rappel en secondes.") }) }, async (params) => { const job = queue.addJob({ type: 'sftp', ...params, status: 'pending', files: params.files }); history.logTask(job); sftp.executeMultiTransfer(job.id); const finalJob = await waitForJobCompletion(job.id, config.syncTimeout); if (finalJob) { return { content: [{ type: "text", text: `Résultat transferts multiples (tâche ${finalJob.id}):\n${JSON.stringify(finalJob, null, 2)}` }] }; } else { return { content: [{ type: "text", text: `Tâche de transferts multiples ${job.id} initiée en arrière-plan.` }] }; } } );
- sftp.js:80-169 (helper)Core helper function executeTransfer that performs the actual SFTP operations. Handles multi-file transfers by looping over job.files, supports glob expansion, upload/download of files and directories, connection management, progress tracking, error handling, and job status updates.async function executeTransfer(jobId) { const job = queue.getJob(jobId); if (!job) return queue.log('error', `Tâche introuvable: ${jobId}`); let sftp = null; try { const serverConfig = await serverManager.getServer(job.alias); queue.updateJobStatus(jobId, 'running'); sftp = new SftpClient(); // Configuration de la connexion const config = { host: serverConfig.host, port: 22, username: serverConfig.user, readyTimeout: 20000, retries: 3, retry_factor: 2, retry_minTimeout: 2000 }; if (serverConfig.keyPath) { config.privateKey = await fs.readFile(serverConfig.keyPath); } else if (serverConfig.password) { config.password = serverConfig.password; } else { throw new Error(`Aucune méthode d'authentification pour '${job.alias}'.`); } await sftp.connect(config); // Déterminer si on traite plusieurs fichiers const files = job.files || [{ local: job.local, remote: job.remote }]; const isMultiple = Array.isArray(job.files) && job.files.length > 1; let successCount = 0; let failedFiles = []; let totalFiles = 0; // Traiter chaque fichier for (let i = 0; i < files.length; i++) { const file = files[i]; const progress = isMultiple ? ` (${i + 1}/${files.length})` : ''; try { if (job.direction === 'upload') { const localFiles = await expandFileList(file.local); totalFiles += localFiles.length; for (const localFile of localFiles) { queue.log('info', `Transfert${progress}: ${localFile}`); await handleUpload(sftp, localFile, file.remote); successCount++; } } else if (job.direction === 'download') { const downloadedCount = await handleDownload(sftp, file.remote, file.local); totalFiles += downloadedCount; successCount += downloadedCount; } } catch (err) { queue.log('error', `Échec transfert ${file.local || file.remote}: ${err.message}`); failedFiles.push({ file: file.local || file.remote, error: err.message }); } } await sftp.end(); // Génération du rapport let status = successCount === totalFiles ? 'completed' : 'partial'; let output = `Transfert ${job.direction}: ${successCount}/${totalFiles} fichiers réussis`; if (failedFiles.length > 0) { output += `\nÉchecs: ${failedFiles.map(f => f.file).join(', ')}`; if (successCount === 0) status = 'failed'; } queue.updateJobStatus(jobId, status, { output, failedFiles }); } catch (err) { queue.updateJobStatus(jobId, 'failed', { error: err.message }); } finally { if (sftp) { try { await sftp.end(); } catch (e) { // Ignorer les erreurs de fermeture } } } }
- sftp.js:252-258 (helper)Thin wrapper executeMultiTransfer that retrieves the job and delegates to the core executeTransfer function.async function executeMultiTransfer(jobId) { const job = queue.getJob(jobId); if (!job) return queue.log('error', `Tâche introuvable: ${jobId}`); // Utilise la même fonction mais avec support multi-fichiers return executeTransfer(jobId); }