Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
This filesystem MCP server has EXPLICIT tool definitions with schemas and descriptions visible in the source code. However, it has significant quality gaps: (1) Parameter descriptions are minimal (many are single-sentence and lack guidance on format/constraints); (2) Output schemas are not explicitly documented for tools returning complex types (e.g., get_file_info returns a Dict with undocumented structure); (3) Error handling lacks recovery guidance, exceptions are logged but not shaped into actionable LLM responses; (4) No input validation constraints (enums, ranges, patterns) are declared in parameter descriptions; (5) Tool descriptions lack context about when to use each tool vs. alternatives (e.g., when to use search_files vs. list_directory); (6) No documentation of security implications or permission model. The tools themselves are clearly named and have consistent verb_noun structure, which is a positive. However, the parameter documentation is sparse (average ~15 chars per param description, vs. baseline 72 chars), and tool descriptions average ~35 chars, below the 194 baseline. Most critically, responses from tools like get_file_info and list_directory return unstructured data without documented field contracts, forcing LLMs to guess at response structure.
Output schemas not documented. Tools like get_file_info return complex Dict[str, Any] with fields (size, created, modified, accessed, is_directory, is_file, permissions) but no schema contract is visible in tool registration. LLMs cannot plan downstream calls without knowing the response structure.
Parameter descriptions are minimalist (average 15-20 chars). Baseline is 72 chars. Descriptions lack format guidance, constraints, or decision criteria. E.g., 'Pattern to search for' does not explain if it's regex, glob, substring matching, or case-sensitive. LLMs cannot infer these details.
Tool descriptions are terse (average 30-35 chars, baseline 194). They state WHAT but not WHEN or WHY. No guidance on which tool to choose when multiple could work (e.g., list_directory vs. search_files). LLMs waste reasoning cycles on tool selection.
Recommendations
Document output schemas for all tools. For get_file_info, explicitly define the response object: {size: int (bytes), created: ISO8601 string, modified: ISO8601 string, accessed: ISO8601 string, is_directory: bool, is_file: bool, permissions: string (octal)}. For list_directory, document that each entry is a string like '[DIR] foldername' or '[FILE] filename'. For search_files, clarify it returns a list of absolute paths as strings.
Expand parameter descriptions to 50-150 chars. For 'path' parameters, add: 'Absolute or relative path. Relative paths are resolved from the working directory. Path must be within allowed directories (see server configuration). Symlinks are followed; use canonical paths if symlink behavior is a concern.' For 'pattern' in search_files, add: 'Case-insensitive substring match. LLMs typically expect glob patterns (*.txt), clarify if your implementation differs.'
Expand tool descriptions to 100-200 chars. For list_directory, add: 'List contents of a directory with type annotations ([DIR] or [FILE]). Use this for interactive browsing or when you need to see what files are available. For searching across many files, use search_files instead.' For search_files, add: 'Search for files by substring pattern across a directory tree. Useful for finding files by name when the exact path is unknown. Does not search file contents.'
Add recovery guidance to tool descriptions and error responses. For write_file: '...If the parent directory does not exist, call create_directory() first.' For read_file: '...If the path is uncertain, call search_files() to locate the file first.' For move_file: '...Source must exist. If destination exists, the operation fails, call create_directory() if parent dir is missing.'
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
No error recovery guidance in tool descriptions or documented error responses. When a file is not found or permission is denied, the implementation logs and re-raises, but LLMs get a raw exception. No actionable guidance like 'Try search_files() if path is uncertain' or 'Check permissions with get_file_info().'
No input validation constraints declared. Parameter 'path' in all tools has no guidance on valid formats, allowed characters, relative vs. absolute path handling, or symlink behavior. Parameter 'pattern' in search_files does not specify regex vs. glob vs. substring semantics.
No documentation of idempotency or state-modifying side effects. Descriptions should flag which tools are safe to retry and which have irreversible consequences. E.g., write_file and move_file can destroy data, but this is not signaled to LLMs.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) visible in source code. These optional but recommended annotations help clients understand tool semantics at a glance.
Path traversal attack surface not documented. The implementation validates paths are within allowed_dirs, but this security guarantee is not conveyed to LLMs. No description warns that symlinks, .. sequences, or environment variable expansion could escape the sandbox.
Add tool annotations to the tool registration. Mark write_file, create_directory, move_file, and append_to_file with destructiveHint=true or idempotentHint=false (as appropriate). Mark read_file, list_directory, get_file_info, and search_files with readOnlyHint=true.
Document the allowed_dirs security boundary in every tool description or server welcome prompt. E.g., 'All paths are constrained to: /home/user, /tmp/project. Attempts to access outside these directories will be rejected.'
Return structured, documented responses. Instead of free-form Dict[str, Any], define Pydantic models with explicit field names and types: class FileInfo(BaseModel): size_bytes: int; modified_at: str (ISO8601); is_directory: bool; permissions_octal: str. Return these as JSON with typed fields, not untyped dicts.
Add pagination support to list_directory and search_files. These can return hundreds of results. Accept optional limit (default 50, max 500) and offset parameters. Return {items: [...], total: int, has_more: bool}. This prevents context window exhaustion.
Validate input early and return actionable error messages. Instead of catching generic Exception and logging, catch specific errors: FileNotFoundError -> 'File not found: {path}. Call search_files() to find it.'; PermissionError -> 'Permission denied: {path}. Check you have read/write access.'; IsADirectoryError -> '{path} is a directory, not a file. Call list_directory() instead.'