SFTP (SSH file transfer) backend binding plugin for mcpg. Lists a directory, gets a file, or puts a file over SSH (russh + russh-sftp) as MCP tools/resources — with path-traversal defense and a size cap. FTP (suppaftp) and SMB (pavao) are deferred follow-ons.
Three tools with clear naming (fs.list, fs.get, fs.put) and basic descriptions. All tools have input schemas with parameter descriptions. However, descriptions are minimal (10-50 chars), lacking context on WHEN to use each tool, prerequisites, or return value structure. No output schemas documented. Parameter descriptions exist but are terse. Missing error handling guidance and recovery paths. No tool annotations (readOnlyHint/destructiveHint). Schemas are present but sparse, no examples, no constraints on path format beyond traversal defense mention.
Read a file's contents over SFTP (capped at max_bytes)
List a directory's entries over SFTP
Write a file over SFTP (truncate/create)
Descriptions are under 50 characters and lack actionable context. 'List a directory's entries over SFTP' does not explain when to call this vs other discovery tools, what structure is returned, or prerequisites (e.g., must have SFTP credentials configured). LLMs cannot infer selection criteria from minimal text.
No output schema documented. Callers cannot see what fields fs.list returns (entries structure?), what fs.get returns (text vs base64 encoding?), or what fs.put returns (bytes written?). LLMs must guess, risking misuse.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). fs.put is destructive (truncates/overwrites) but LLMs have no signal that this is irreversible. fs.list and fs.get are read-only but lack explicit marking.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 52 | 2026-07-28+ | v2 |
Parameter descriptions are terse. 'The file path to read (joined under the configured root, with .. segments rejected)' mentions path-traversal defense but does not explain format (absolute? relative?), encoding (UTF-8?), or max length. LLMs cannot validate inputs.
fs.put has two mutually exclusive parameters (content as base64, text as UTF-8) but descriptions do not state this dependency. LLMs may pass both or neither, causing ambiguous failures.