#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import fs from "fs-extra";
import path from "path";
import { fileURLToPath } from "url";
import { FileOperations } from "./tools/fileOperations.js";
import { DirectoryOperations } from "./tools/directoryOperations.js";
import { SearchOperations } from "./tools/searchOperations.js";
import { AdvancedOperations } from "./tools/advancedOperations.js";
import { SecurityManager } from "./tools/securityManager.js";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Handle version command
if (process.argv.includes('--version') || process.argv.includes('-v')) {
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
console.log(`Tafa MCP v${packageJson.version}`);
process.exit(0);
}
// Handle help command
if (process.argv.includes('--help') || process.argv.includes('-h')) {
console.log(`
🚀 Tafa MCP Server - Fast file system operations for Claude Desktop
Usage: tafa-mcp [options] <directory1> [directory2] ...
Options:
-h, --help Show this help message
-v, --version Show version number
Examples:
tafa-mcp ~/Documents ~/Desktop
tafa-mcp /Users/username/Projects
tafa-mcp "C:\\Users\\username\\Documents" (Windows)
For more information, visit: https://github.com/your-org/tafa-mcp
`);
process.exit(0);
}
class TafaMcpServer {
constructor() {
this.server = new McpServer({
name: "tafa-mcp",
version: "1.0.0",
});
// Get allowed directories from command line arguments
const allowedDirs = process.argv.slice(2);
if (allowedDirs.length === 0) {
console.error("❌ Error: No directories specified. Usage: tafa-mcp <directory1> [directory2] ...");
process.exit(1);
}
// Validate and normalize directories
this.allowedDirectories = allowedDirs.map(dir => {
const resolved = path.resolve(dir);
if (!fs.existsSync(resolved)) {
console.error(`❌ Error: Directory does not exist: ${resolved}`);
process.exit(1);
}
return resolved;
});
console.log(`🚀 Tafa MCP Server initialized with directories:`);
this.allowedDirectories.forEach(dir => console.log(` 📁 ${dir}`));
// Initialize security manager
this.securityManager = new SecurityManager(this.allowedDirectories);
// Initialize operation handlers
this.fileOps = new FileOperations(this.securityManager);
this.dirOps = new DirectoryOperations(this.securityManager);
this.searchOps = new SearchOperations(this.securityManager);
this.advancedOps = new AdvancedOperations(this.securityManager);
this.setupTools();
}
setupTools() {
// File Operations
this.server.tool("read_file", {
path: z.string().describe("Path to the file to read"),
}, async ({ path: filePath }) => {
return await this.fileOps.readFile(filePath);
});
this.server.tool("write_file", {
path: z.string().describe("Path where to write the file"),
content: z.string().describe("Content to write to the file"),
backup: z.boolean().default(true).describe("Create backup before writing"),
}, async ({ path: filePath, content, backup }) => {
return await this.fileOps.writeFile(filePath, content, backup);
});
this.server.tool("append_file", {
path: z.string().describe("Path to the file to append to"),
content: z.string().describe("Content to append to the file"),
}, async ({ path: filePath, content }) => {
return await this.fileOps.appendFile(filePath, content);
});
this.server.tool("copy_file", {
source: z.string().describe("Source file path"),
destination: z.string().describe("Destination file path"),
}, async ({ source, destination }) => {
return await this.fileOps.copyFile(source, destination);
});
this.server.tool("move_file", {
source: z.string().describe("Source file path"),
destination: z.string().describe("Destination file path"),
}, async ({ source, destination }) => {
return await this.fileOps.moveFile(source, destination);
});
this.server.tool("delete_file", {
path: z.string().describe("Path to the file to delete"),
backup: z.boolean().default(true).describe("Create backup before deleting"),
}, async ({ path: filePath, backup }) => {
return await this.fileOps.deleteFile(filePath, backup);
});
this.server.tool("get_file_info", {
path: z.string().describe("Path to the file"),
}, async ({ path: filePath }) => {
return await this.fileOps.getFileInfo(filePath);
});
// Directory Operations
this.server.tool("create_directory", {
path: z.string().describe("Path of the directory to create"),
}, async ({ path: dirPath }) => {
return await this.dirOps.createDirectory(dirPath);
});
this.server.tool("list_directory", {
path: z.string().describe("Path of the directory to list"),
recursive: z.boolean().default(false).describe("List recursively"),
showHidden: z.boolean().default(false).describe("Show hidden files"),
}, async ({ path: dirPath, recursive, showHidden }) => {
return await this.dirOps.listDirectory(dirPath, recursive, showHidden);
});
this.server.tool("delete_directory", {
path: z.string().describe("Path of the directory to delete"),
backup: z.boolean().default(true).describe("Create backup before deleting"),
}, async ({ path: dirPath, backup }) => {
return await this.dirOps.deleteDirectory(dirPath, backup);
});
// Search Operations
this.server.tool("search_files", {
directory: z.string().describe("Directory to search in"),
pattern: z.string().describe("File name pattern to search for"),
recursive: z.boolean().default(true).describe("Search recursively"),
}, async ({ directory, pattern, recursive }) => {
return await this.searchOps.searchFiles(directory, pattern, recursive);
});
this.server.tool("search_content", {
directory: z.string().describe("Directory to search in"),
searchTerm: z.string().describe("Text to search for in file contents"),
filePattern: z.string().default("*").describe("File pattern to limit search"),
recursive: z.boolean().default(true).describe("Search recursively"),
}, async ({ directory, searchTerm, filePattern, recursive }) => {
return await this.searchOps.searchContent(directory, searchTerm, filePattern, recursive);
});
// Advanced Operations
this.server.tool("compress_files", {
sourcePaths: z.array(z.string()).describe("Array of file/directory paths to compress"),
destinationPath: z.string().describe("Path for the archive file"),
format: z.enum(["zip", "tar"]).default("zip").describe("Archive format"),
}, async ({ sourcePaths, destinationPath, format }) => {
return await this.advancedOps.compressFiles(sourcePaths, destinationPath, format);
});
this.server.tool("extract_archive", {
archivePath: z.string().describe("Path to the archive file"),
destinationPath: z.string().describe("Directory to extract to"),
}, async ({ archivePath, destinationPath }) => {
return await this.advancedOps.extractArchive(archivePath, destinationPath);
});
this.server.tool("batch_rename", {
directory: z.string().describe("Directory containing files to rename"),
pattern: z.string().describe("Regular expression pattern to match"),
replacement: z.string().describe("Replacement string"),
}, async ({ directory, pattern, replacement }) => {
return await this.advancedOps.batchRename(directory, pattern, replacement);
});
this.server.tool("organize_files", {
directory: z.string().describe("Directory to organize"),
organizationType: z.enum(["extension", "size", "date"]).default("extension").describe("How to organize files"),
}, async ({ directory, organizationType }) => {
return await this.advancedOps.organizeFiles(directory, organizationType);
});
this.server.tool("find_duplicates", {
directory: z.string().describe("Directory to search for duplicates"),
minSize: z.number().default(0).describe("Minimum file size to consider"),
}, async ({ directory, minSize }) => {
return await this.searchOps.findDuplicates(directory, minSize);
});
// Quick utility tools
this.server.tool("get_server_info", {}, async () => {
return {
content: [{
type: "text",
text: JSON.stringify({
name: "Tafa MCP Server",
version: "1.0.0",
description: "Fast and efficient file system operations",
allowedDirectories: this.allowedDirectories,
availableTools: [
"read_file", "write_file", "append_file", "copy_file", "move_file", "delete_file", "get_file_info",
"create_directory", "list_directory", "delete_directory",
"search_files", "search_content", "find_duplicates",
"compress_files", "extract_archive", "batch_rename", "organize_files"
]
}, null, 2)
}]
};
});
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.log("🎯 Tafa MCP Server connected and ready!");
}
}
// Start the server
const server = new TafaMcpServer();
server.start().catch(console.error);