diff --git a/src/tools/calculate_directory_size.rs b/src/tools/calculate_directory_size.rs index af8d56c..4af70ea 100644 --- a/src/tools/calculate_directory_size.rs +++ b/src/tools/calculate_directory_size.rs @@ -15,7 +15,7 @@ pub enum FileSizeOutputFormat { #[mcp_tool( name = "calculate_directory_size", - title="Calculate Directory Size", + title="Calculate directory size", description = concat!("Calculates the total size of a directory specified by `root_path`.", "It recursively searches for files and sums their sizes. ", "The result can be returned in either a `human-readable` format or as `bytes`, depending on the specified `output_format` argument.", diff --git a/src/tools/create_directory.rs b/src/tools/create_directory.rs index 6fcbbc1..d4db74a 100644 --- a/src/tools/create_directory.rs +++ b/src/tools/create_directory.rs @@ -8,7 +8,7 @@ use crate::fs_service::FileSystemService; #[mcp_tool( name = "create_directory", - title="Create Directory", + title="Create directory", description = concat!("Create a new directory or ensure a directory exists. ", "Can create multiple nested directories in one operation. ", "If the directory already exists, this operation will succeed silently. ", diff --git a/src/tools/directory_tree.rs b/src/tools/directory_tree.rs index 33cf29d..160526c 100644 --- a/src/tools/directory_tree.rs +++ b/src/tools/directory_tree.rs @@ -8,7 +8,7 @@ use crate::fs_service::FileSystemService; #[mcp_tool( name = "directory_tree", - title= "Directory Tree", + title= "Directory tree", description = concat!("Get a recursive tree view of files and directories as a JSON structure. ", "Each entry includes 'name', 'type' (file/directory), and 'children' for directories. ", "Files have no children array, while directories always have a children array (which may be empty). ", diff --git a/src/tools/edit_file.rs b/src/tools/edit_file.rs index e59ceff..955e1c3 100644 --- a/src/tools/edit_file.rs +++ b/src/tools/edit_file.rs @@ -19,7 +19,7 @@ pub struct EditOperation { #[mcp_tool( name = "edit_file", - title="Edit File", + title="Edit file", description = concat!("Make line-based edits to a text file. ", "Each edit replaces exact line sequences with new content. ", "Returns a git-style diff showing the changes made. ", diff --git a/src/tools/find_duplicate_files.rs b/src/tools/find_duplicate_files.rs index 15465c0..d3c3828 100644 --- a/src/tools/find_duplicate_files.rs +++ b/src/tools/find_duplicate_files.rs @@ -8,7 +8,7 @@ use std::{collections::BTreeMap, fmt::Write}; #[mcp_tool( name = "find_duplicate_files", - title="Calculate Directory Size", + title="Find duplicate files", description = concat!("Find duplicate files within a directory and return list of duplicated files as text or json format", "Optional `pattern` argument can be used to narrow down the file search to specific glob pattern.", "Optional `exclude_patterns` can be used to exclude certain files matching a glob.", diff --git a/src/tools/find_empty_directories.rs b/src/tools/find_empty_directories.rs index 0b35b4e..dcfec43 100644 --- a/src/tools/find_empty_directories.rs +++ b/src/tools/find_empty_directories.rs @@ -7,10 +7,10 @@ use std::path::Path; use crate::fs_service::{FileSystemService, utils::OutputFormat}; -// head_file +// find_empty_directories #[mcp_tool( name = "find_empty_directories", - title="Find Empty Directories", + title="Find empty directories", description = concat!("Recursively finds all empty directories within the given root path.", "A directory is considered empty if it contains no files in itself or any of its subdirectories.", "Operating system metadata files `.DS_Store` (macOS) and `Thumbs.db` (Windows) will be ignored.", diff --git a/src/tools/get_file_info.rs b/src/tools/get_file_info.rs index 8d29309..07bc2e3 100644 --- a/src/tools/get_file_info.rs +++ b/src/tools/get_file_info.rs @@ -8,7 +8,7 @@ use crate::fs_service::FileSystemService; #[mcp_tool( name = "get_file_info", - title="Get File Info", + title="Get file info", description = concat!("Retrieve detailed metadata about a file or directory. ", "Returns comprehensive information including size, creation time, ", "last modified time, permissions, and type. ", diff --git a/src/tools/list_allowed_directories.rs b/src/tools/list_allowed_directories.rs index 40ed8ee..613ef04 100644 --- a/src/tools/list_allowed_directories.rs +++ b/src/tools/list_allowed_directories.rs @@ -6,7 +6,7 @@ use crate::fs_service::FileSystemService; #[mcp_tool( name = "list_allowed_directories", - title="List Allowed Directories", + title="List allowed directories", description = concat!("Returns a list of directories that the server has permission ", "to access Subdirectories within these allowed directories are also accessible. ", "Use this to identify which directories and their nested paths are available ", diff --git a/src/tools/list_directory.rs b/src/tools/list_directory.rs index e86ca3f..6669b37 100644 --- a/src/tools/list_directory.rs +++ b/src/tools/list_directory.rs @@ -8,7 +8,7 @@ use crate::fs_service::FileSystemService; #[mcp_tool( name = "list_directory", - title="List Directory", + title="List directory", description = concat!("Get a detailed listing of all files and directories in a specified path. ", "Results clearly distinguish between files and directories with [FILE] and [DIR] ", "prefixes. This tool is essential for understanding directory structure and ", diff --git a/src/tools/list_directory_with_sizes.rs b/src/tools/list_directory_with_sizes.rs index 91bf2a8..a7cb55b 100644 --- a/src/tools/list_directory_with_sizes.rs +++ b/src/tools/list_directory_with_sizes.rs @@ -9,7 +9,7 @@ use crate::fs_service::utils::format_bytes; #[mcp_tool( name = "list_directory_with_sizes", - title="List Directory With File Sizes", + title="List directory with file sizes", description = concat!("Get a detailed listing of all files and directories in a specified path, including sizes. " , "Results clearly distinguish between files and directories with [FILE] and [DIR] prefixes. " , "This tool is useful for understanding directory structure and " , diff --git a/src/tools/move_file.rs b/src/tools/move_file.rs index 12d59ca..efa6b6b 100644 --- a/src/tools/move_file.rs +++ b/src/tools/move_file.rs @@ -8,7 +8,7 @@ use crate::fs_service::FileSystemService; #[mcp_tool( name = "move_file", - title="Move File", + title="Move file", description = concat!("Move or rename files and directories. Can move files between directories ", "and rename them in a single operation. If the destination exists, the ", "operation will fail. Works across different directories and can be used ", diff --git a/src/tools/read_file_lines.rs b/src/tools/read_file_lines.rs index 86109d5..cff99dc 100644 --- a/src/tools/read_file_lines.rs +++ b/src/tools/read_file_lines.rs @@ -7,10 +7,10 @@ use rust_mcp_sdk::{ use crate::fs_service::FileSystemService; -// head_file +// read_file_lines #[mcp_tool( name = "read_file_lines", - title="Read File Lines", + title="Read file lines", description = concat!("Reads lines from a text file starting at a specified line offset (0-based) and continues for the specified number of lines if a limit is provided.", "This function skips the first 'offset' lines and then reads up to 'limit' lines if specified, or reads until the end of the file otherwise.", "It's useful for partial reads, pagination, or previewing sections of large text files.", diff --git a/src/tools/read_multiple_media_files.rs b/src/tools/read_multiple_media_files.rs index 38b64f7..43a5143 100644 --- a/src/tools/read_multiple_media_files.rs +++ b/src/tools/read_multiple_media_files.rs @@ -5,7 +5,7 @@ use rust_mcp_sdk::schema::{CallToolResult, schema_utils::CallToolError}; #[mcp_tool( name = "read_multiple_media_files", - title="Read Multiple Media (Image/Audio) Files", + title="Read multiple media (Image/Audio) files", description = concat!("Reads multiple image or audio files and returns their Base64-encoded contents along with corresponding MIME types. ", "This method is more efficient than reading files individually. ", "The max_bytes argument could be used to enforce an upper limit on the size of a file to read ", diff --git a/src/tools/read_multiple_text_files.rs b/src/tools/read_multiple_text_files.rs index 0389c78..91923e4 100644 --- a/src/tools/read_multiple_text_files.rs +++ b/src/tools/read_multiple_text_files.rs @@ -7,7 +7,7 @@ use std::path::Path; #[mcp_tool( name = "read_multiple_text_files", - title="Read Multiple Text Files", + title="Read multiple text files", description = concat!("Read the contents of multiple text files simultaneously as text. ", "This is more efficient than reading files one by one when you need to analyze ", "or compare multiple files. Each file's content is returned with its ", diff --git a/src/tools/search_file.rs b/src/tools/search_file.rs index 0bdd81c..34a569c 100644 --- a/src/tools/search_file.rs +++ b/src/tools/search_file.rs @@ -7,7 +7,7 @@ use rust_mcp_sdk::schema::{CallToolResult, schema_utils::CallToolError}; use crate::fs_service::FileSystemService; #[mcp_tool( name = "search_files", - title="Search Files", + title="Search files", description = concat!("Recursively search for files and directories matching a pattern. ", "Searches through all subdirectories from the starting path. The search is case-insensitive ", "and matches partial names. Returns full paths to all matching items.", diff --git a/src/tools/search_files_content.rs b/src/tools/search_files_content.rs index 85a371c..a5e2fd4 100644 --- a/src/tools/search_files_content.rs +++ b/src/tools/search_files_content.rs @@ -6,7 +6,7 @@ use rust_mcp_sdk::schema::{CallToolResult, schema_utils::CallToolError}; use std::fmt::Write; #[mcp_tool( name = "search_files_content", - title="Move Files Content", + title="Move files content", description = concat!("Searches for text or regex patterns in the content of files matching matching a GLOB pattern.", "Returns detailed matches with file path, line number, column number and a preview of matched text.", "By default, it performs a literal text search; if the 'is_regex' parameter is set to true, it performs a regular expression (regex) search instead.", diff --git a/src/tools/tail_file.rs b/src/tools/tail_file.rs index b808660..bc40e55 100644 --- a/src/tools/tail_file.rs +++ b/src/tools/tail_file.rs @@ -7,10 +7,10 @@ use rust_mcp_sdk::{ use crate::fs_service::FileSystemService; -// head_file +// tail_file #[mcp_tool( - name = "head_file", - title="Head file", + name = "tail_file", + title="Tail file", description = concat!("Reads and returns the last N lines of a text file.", "This is useful for quickly previewing file contents without loading the entire file into memory.", "If the file has fewer than N lines, the entire file will be returned.", diff --git a/src/tools/write_file.rs b/src/tools/write_file.rs index 3d09d53..77b8b4f 100644 --- a/src/tools/write_file.rs +++ b/src/tools/write_file.rs @@ -9,7 +9,7 @@ use rust_mcp_sdk::schema::{CallToolResult, schema_utils::CallToolError}; use crate::fs_service::FileSystemService; #[mcp_tool( name = "write_file", - title="Write File", + title="Write file", description = concat!("Create a new file or completely overwrite an existing file with new content. ", "Use with caution as it will overwrite existing files without warning. ", "Handles text content with proper encoding. Only works within allowed directories."), diff --git a/src/tools/zip_unzip.rs b/src/tools/zip_unzip.rs index b81e885..00b7b8b 100644 --- a/src/tools/zip_unzip.rs +++ b/src/tools/zip_unzip.rs @@ -6,7 +6,7 @@ use crate::fs_service::FileSystemService; #[mcp_tool( name = "zip_files", - title="Zip Files", + title="Zip files", description = concat!("Creates a ZIP archive by compressing files. ", "It takes a list of files to compress and a target path for the resulting ZIP file. ", "Both the source files and the target ZIP file should reside within allowed directories."), diff --git a/tests/test_tools.rs b/tests/test_tools.rs index ef702cf..ef7b502 100644 --- a/tests/test_tools.rs +++ b/tests/test_tools.rs @@ -4,7 +4,7 @@ pub mod common; use common::setup_service; use rust_mcp_filesystem::tools::*; use rust_mcp_sdk::schema::{ContentBlock, schema_utils::CallToolError}; -use std::fs; +use std::{collections::HashSet, fs}; #[tokio::test] async fn test_create_directory_new_directory() { @@ -129,5 +129,41 @@ async fn test_create_directory_invalid_path() { assert!(matches!(err, CallToolError { .. })); } +// Github Issue #54 +// https://github.com/rust-mcp-stack/rust-mcp-filesystem/issues/54 +#[tokio::test] +async fn ensure_tools_duplication() { + let mut names = HashSet::new(); + let mut duplicate_names = vec![]; + + let mut titles = HashSet::new(); + let mut duplicate_titles = vec![]; + + let mut descriptions = HashSet::new(); + let mut duplicate_descriptions = vec![]; + + for t in FileSystemTools::tools() { + if !names.insert(t.name.to_string()) { + duplicate_names.push(t.name.to_string()); + } + + if let Some(title) = t.title { + if !titles.insert(title.to_string()) { + duplicate_titles.push(title.to_string()); + } + } + + if let Some(description) = t.description { + if !descriptions.insert(description.to_string()) { + duplicate_descriptions.push(description.to_string()); + } + } + } + + assert_eq!(duplicate_names.join(","), ""); + assert_eq!(duplicate_titles.join(","), ""); + assert_eq!(duplicate_descriptions.join(","), ""); +} + #[tokio::test] async fn adhoc() {}