Skip to main content
Glama

Windows Operations MCP

attributes.py•6.48 kB
""" File attributes module. This module provides functionality for getting and setting file attributes. """ import os import ctypes import stat from pathlib import Path from typing import Dict, Any, Optional, Union, cast from .base import ( FileOperationError, validate_file_path, normalize_path, log_operation, handle_operation, GENERIC_READ, GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_ATTRIBUTE_NORMAL, OPEN_EXISTING, INVALID_HANDLE_VALUE, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY, FILE_ATTRIBUTE_OFFLINE, FILE_ATTRIBUTE_ENCRYPTED, _CreateFileW, _GetFileAttributesW, _SetFileAttributesW, _CloseHandle ) # Map of attribute names to Windows attribute constants ATTRIBUTE_MAP = { 'readonly': FILE_ATTRIBUTE_READONLY, 'hidden': FILE_ATTRIBUTE_HIDDEN, 'system': FILE_ATTRIBUTE_SYSTEM, 'archive': FILE_ATTRIBUTE_ARCHIVE, 'temporary': FILE_ATTRIBUTE_TEMPORARY, 'offline': FILE_ATTRIBUTE_OFFLINE, 'encrypted': FILE_ATTRIBUTE_ENCRYPTED } @log_operation("get_file_attributes") @handle_operation("get_file_attributes") def get_file_attributes(file_path: Union[str, Path]) -> Dict[str, bool]: """ Get file attributes for the specified file. Args: file_path: Path to the file Returns: Dictionary of attribute names and their values """ file_path = normalize_path(file_path) if not file_path.exists(): raise FileOperationError(f"File not found: {file_path}") attributes = {} if os.name == 'nt': # Windows implementation using Win32 API attrs = _GetFileAttributesW(str(file_path)) for name, flag in ATTRIBUTE_MAP.items(): attributes[name] = bool(attrs & flag) else: # Unix-like implementation using stat st = file_path.stat() # Map stat attributes to our attribute names attributes.update({ 'readonly': not bool(st.st_mode & 0o222), # Not writable by owner 'hidden': file_path.name.startswith('.'), # Hidden files start with . 'system': False, # No direct equivalent on Unix 'archive': False, # No direct equivalent on Unix 'temporary': False, # No direct equivalent on Unix 'offline': False, # No direct equivalent on Unix 'encrypted': False # No direct equivalent without checking encryption }) # Add some additional useful attributes attributes.update({ 'exists': True, 'is_file': file_path.is_file(), 'is_dir': file_path.is_dir(), 'is_symlink': file_path.is_symlink(), 'size': file_path.stat().st_size if file_path.is_file() else 0 }) return attributes @log_operation("set_file_attributes") @handle_operation("get_file_attributes") def set_file_attributes( file_path: Union[str, Path], attributes: Dict[str, bool] ) -> Dict[str, Any]: """ Set file attributes for the specified file. Args: file_path: Path to the file attributes: Dictionary of attributes to set Returns: Dictionary with operation status and updated attributes """ file_path = normalize_path(file_path) if not file_path.exists(): raise FileOperationError(f"File not found: {file_path}") if os.name == 'nt': # Windows implementation using Win32 API current_attrs = _GetFileAttributesW(str(file_path)) # Update attributes based on the provided values for name, value in attributes.items(): if name in ATTRIBUTE_MAP: if value: current_attrs |= ATTRIBUTE_MAP[name] else: current_attrs &= ~ATTRIBUTE_MAP[name] # Apply the new attributes if not _SetFileAttributesW(str(file_path), current_attrs): raise FileOperationError("Failed to set file attributes") else: # Unix-like implementation using chmod if 'readonly' in attributes: st = file_path.stat() mode = st.st_mode if attributes['readonly']: # Remove write permissions for all mode &= ~0o222 else: # Add write permissions for owner mode |= 0o200 file_path.chmod(mode) # Handle hidden files (prefix with .) if 'hidden' in attributes and attributes['hidden'] != file_path.name.startswith('.'): if attributes['hidden']: new_path = file_path.parent / ('.' + file_path.name) else: new_path = file_path.parent / file_path.name.lstrip('.') if new_path != file_path: file_path.rename(new_path) file_path = new_path # Return the updated attributes updated_attrs = get_file_attributes(file_path) updated_attrs['path'] = str(file_path) return updated_attrs # MCP Tool Wrappers def get_file_attributes_tool(file_path: str) -> Dict[str, Any]: """ MCP tool wrapper for getting file attributes. Args: file_path: Path to the file Returns: Dictionary with file attributes and operation status """ try: attrs = get_file_attributes(file_path) return { "success": True, "path": file_path, "attributes": attrs } except FileOperationError as e: return { "success": False, "error": str(e), "path": file_path } def set_file_attributes_tool( file_path: str, attributes: Dict[str, bool] ) -> Dict[str, Any]: """ MCP tool wrapper for setting file attributes. Args: file_path: Path to the file attributes: Dictionary of attributes to set Returns: Dictionary with operation status and updated attributes """ try: result = set_file_attributes(file_path, attributes) result["success"] = True return result except FileOperationError as e: return { "success": False, "error": str(e), "path": file_path }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sandraschi/windows-operations-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server