"""MCP tools for file operations."""
import logging
from ..services.file_service import FileService
from ..core.constants import DEFAULT_ROOT
logger = logging.getLogger(__name__)
# Default configuration
READ_ONLY = False
MAX_FILE_SIZE_MB = 100
def register_file_routes(server):
"""Register all file MCP tools."""
@server.tool(
name="list_files",
description="List all files in a directory with optional glob pattern filtering",
)
def list_files(path: str = ".", pattern: str = "*") -> dict:
"""
List all files in a given directory.
Args:
path: Relative path from root directory (default: current directory)
pattern: Glob pattern to filter files (default: "*" for all files)
Returns:
Dictionary with list of files and metadata
"""
service = FileService(root=DEFAULT_ROOT, max_file_size_mb=MAX_FILE_SIZE_MB)
result = service.list_files(path, pattern)
return result.model_dump()
@server.tool(
name="read_file",
description="Read file content with chunking support "
"(returns text or base64 for binary files)",
)
def read_file(path: str, offset: int = 0, limit: int | None = None) -> dict:
"""
Read file content with optional chunking support.
For text files, content is returned as UTF-8 text.
For binary files, content is base64 encoded.
Args:
path: Relative path to the file
offset: Byte offset to start reading from (default: 0)
limit: Maximum number of bytes to read (default: None for entire file)
Returns:
Dictionary with file content and metadata
"""
service = FileService(root=DEFAULT_ROOT, max_file_size_mb=MAX_FILE_SIZE_MB)
result = service.read_file(path, offset, limit)
return result.model_dump()
@server.tool(
name="write_file",
description="Write or overwrite a file (supports text and base64-encoded binary content)."
" REQUIRES USER CONFIRMATION before execution if file exists.",
)
def write_file(path: str, content: str, is_base64: bool = False) -> dict:
"""
Write or overwrite a file.
Args:
path: Relative path to the file
content: File content (text or base64 encoded binary)
is_base64: If True, content is base64 encoded binary data (default: False)
Returns:
Dictionary with operation result
"""
logger.info(
f"API: write_file - path={path}, is_base64={is_base64}, content_length={len(content)}"
)
service = FileService(root=DEFAULT_ROOT, max_file_size_mb=MAX_FILE_SIZE_MB)
result = service.write_file(path, content, is_base64)
logger.info(f"API: write_file - result: {result.success}")
return result.model_dump()
@server.tool(name="append_file", description="Append text content to an existing file")
def append_file(path: str, content: str) -> dict:
"""
Append content to an existing file.
Args:
path: Relative path to the file
content: Text content to append
Returns:
Dictionary with operation result
"""
service = FileService(root=DEFAULT_ROOT, max_file_size_mb=MAX_FILE_SIZE_MB)
result = service.append_file(path, content)
return result.model_dump()
@server.tool(
name="delete_file",
description="Delete a file permanently. REQUIRES USER CONFIRMATION before"
" execution. This is a destructive operation.",
)
def delete_file(path: str) -> dict:
"""
Delete a file.
Args:
path: Relative path to the file
Returns:
Dictionary with operation result
"""
logger.warning(f"API: delete_file - path={path}")
service = FileService(root=DEFAULT_ROOT, max_file_size_mb=MAX_FILE_SIZE_MB)
result = service.delete_file(path)
logger.info(f"API: delete_file - result: {result.success}")
return result.model_dump()
@server.tool(
name="move_file",
description="Move or rename a file from source to destination path. "
"REQUIRES USER CONFIRMATION before execution.",
)
def move_file(source_path: str, destination_path: str) -> dict:
"""
Move or rename a file.
Args:
source_path: Relative path to the source file
destination_path: Relative path to the destination
Returns:
Dictionary with operation result
"""
service = FileService(root=DEFAULT_ROOT, max_file_size_mb=MAX_FILE_SIZE_MB)
result = service.move_file(source_path, destination_path)
return result.model_dump()
@server.tool(
name="get_file_metadata",
description="Get detailed metadata about a file (size, MIME type, timestamps, permissions)",
)
def get_file_metadata(path: str) -> dict:
"""
Get detailed metadata about a file.
Args:
path: Relative path to the file
Returns:
Dictionary with detailed file metadata
"""
service = FileService(root=DEFAULT_ROOT, max_file_size_mb=MAX_FILE_SIZE_MB)
result = service.get_file_metadata(path)
return result.model_dump()