jitora 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jitora-1.1.0/PKG-INFO +103 -0
- jitora-1.1.0/README.md +83 -0
- jitora-1.1.0/pyproject.toml +39 -0
- jitora-1.1.0/pyproject.toml.orig +31 -0
- jitora-1.1.0/src/jitora/__init__.py +355 -0
- jitora-1.1.0/src/jitora/__main__.py +6 -0
jitora-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jitora
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: sample mcp tool
|
|
5
|
+
Keywords: image,management,processing,ai,organization,mcp
|
|
6
|
+
Author: sunshine-kjh
|
|
7
|
+
Author-email: sunshine-kjh <kimjihoon0@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
13
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Dist: fastmcp>=4.0.3
|
|
17
|
+
Requires-Dist: pillow>=12.3.0
|
|
18
|
+
Requires-Python: >=3.14
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# jictora
|
|
22
|
+
|
|
23
|
+
A powerful image management tool designed to work with AI systems for intelligent image organization. This tool enables AI to read, understand, and organize local image files into appropriate folders based on their content and characteristics.
|
|
24
|
+
|
|
25
|
+
## Project Purpose
|
|
26
|
+
|
|
27
|
+
This tool is specifically designed to:
|
|
28
|
+
- Allow AI systems to access and analyze local image files
|
|
29
|
+
- Enable AI-driven image categorization and organization
|
|
30
|
+
- Provide a robust interface for AI to manage and process images
|
|
31
|
+
- Support automated image sorting and folder management
|
|
32
|
+
- Facilitate AI-powered image content understanding and classification
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
### Installing uvx
|
|
37
|
+
If uvx is not installed on your system, please refer to the [uv installation guide](https://docs.astral.sh/uv/getting-started/installation/) to install it according to your environment.
|
|
38
|
+
|
|
39
|
+
### Installation via MCP (Claude Desktop)
|
|
40
|
+
|
|
41
|
+
Add the following configuration to your MCP settings file:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"jictora": {
|
|
46
|
+
"command": "uvx",
|
|
47
|
+
"args": ["jictora"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## MCP API Features
|
|
53
|
+
|
|
54
|
+
### Directory Management
|
|
55
|
+
- **create_directory**: Creates a new directory at the specified path. Can optionally create parent directories and handle existing directories. Essential for AI-driven folder organization.
|
|
56
|
+
|
|
57
|
+
### Image File Operations
|
|
58
|
+
- **list_image_files**: Scans a directory and returns a formatted list of all valid image files found, including file count and alphabetical listing. Enables AI to discover and analyze available images.
|
|
59
|
+
- **read_image**: Reads an image file and returns it as an Image object for further processing. Allows AI to access and analyze image content.
|
|
60
|
+
- **copy_image**: Copies an image file to a new location while preserving all metadata. Used by AI to organize images into appropriate categories.
|
|
61
|
+
- **move_image**: Moves an image file to a new location, with options to handle existing files and preserve metadata. Enables AI to reorganize images based on content analysis.
|
|
62
|
+
- **delete_image**: Safely deletes an image file with optional confirmation. Provides AI with the ability to manage unwanted or duplicate images.
|
|
63
|
+
- **create_image**: Generates a new blank image with specified dimensions, color, and format. Useful for AI-generated image processing tasks.
|
|
64
|
+
|
|
65
|
+
### Supported Image Formats
|
|
66
|
+
The tool supports the following image formats for AI analysis:
|
|
67
|
+
- JPG/JPEG
|
|
68
|
+
- PNG
|
|
69
|
+
- GIF
|
|
70
|
+
- BMP
|
|
71
|
+
- WebP
|
|
72
|
+
- TIFF
|
|
73
|
+
- ICO
|
|
74
|
+
- JFIF
|
|
75
|
+
- SVG
|
|
76
|
+
|
|
77
|
+
### File Management Features
|
|
78
|
+
- Automatic directory creation for AI-driven organization
|
|
79
|
+
- Overwrite protection with optional override
|
|
80
|
+
- Comprehensive error handling and status reporting
|
|
81
|
+
- File metadata preservation during operations
|
|
82
|
+
- Validation of image files before processing
|
|
83
|
+
- Support for batch operations and automated organization
|
|
84
|
+
|
|
85
|
+
## AI Integration
|
|
86
|
+
|
|
87
|
+
This tool is designed to work seamlessly with AI systems, providing:
|
|
88
|
+
- Direct access to local image files for AI analysis
|
|
89
|
+
- Tools for AI-driven image organization
|
|
90
|
+
- Support for automated folder creation and management
|
|
91
|
+
- Metadata preservation during AI-driven reorganization
|
|
92
|
+
- Robust error handling for automated operations
|
|
93
|
+
|
|
94
|
+
## Error Handling
|
|
95
|
+
All operations include comprehensive error handling and return detailed status information including:
|
|
96
|
+
- Success/failure status
|
|
97
|
+
- Error messages (if any)
|
|
98
|
+
- File metadata
|
|
99
|
+
- Operation details
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
This project is distributed under the MIT License.
|
jitora-1.1.0/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# jictora
|
|
2
|
+
|
|
3
|
+
A powerful image management tool designed to work with AI systems for intelligent image organization. This tool enables AI to read, understand, and organize local image files into appropriate folders based on their content and characteristics.
|
|
4
|
+
|
|
5
|
+
## Project Purpose
|
|
6
|
+
|
|
7
|
+
This tool is specifically designed to:
|
|
8
|
+
- Allow AI systems to access and analyze local image files
|
|
9
|
+
- Enable AI-driven image categorization and organization
|
|
10
|
+
- Provide a robust interface for AI to manage and process images
|
|
11
|
+
- Support automated image sorting and folder management
|
|
12
|
+
- Facilitate AI-powered image content understanding and classification
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### Installing uvx
|
|
17
|
+
If uvx is not installed on your system, please refer to the [uv installation guide](https://docs.astral.sh/uv/getting-started/installation/) to install it according to your environment.
|
|
18
|
+
|
|
19
|
+
### Installation via MCP (Claude Desktop)
|
|
20
|
+
|
|
21
|
+
Add the following configuration to your MCP settings file:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"jictora": {
|
|
26
|
+
"command": "uvx",
|
|
27
|
+
"args": ["jictora"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## MCP API Features
|
|
33
|
+
|
|
34
|
+
### Directory Management
|
|
35
|
+
- **create_directory**: Creates a new directory at the specified path. Can optionally create parent directories and handle existing directories. Essential for AI-driven folder organization.
|
|
36
|
+
|
|
37
|
+
### Image File Operations
|
|
38
|
+
- **list_image_files**: Scans a directory and returns a formatted list of all valid image files found, including file count and alphabetical listing. Enables AI to discover and analyze available images.
|
|
39
|
+
- **read_image**: Reads an image file and returns it as an Image object for further processing. Allows AI to access and analyze image content.
|
|
40
|
+
- **copy_image**: Copies an image file to a new location while preserving all metadata. Used by AI to organize images into appropriate categories.
|
|
41
|
+
- **move_image**: Moves an image file to a new location, with options to handle existing files and preserve metadata. Enables AI to reorganize images based on content analysis.
|
|
42
|
+
- **delete_image**: Safely deletes an image file with optional confirmation. Provides AI with the ability to manage unwanted or duplicate images.
|
|
43
|
+
- **create_image**: Generates a new blank image with specified dimensions, color, and format. Useful for AI-generated image processing tasks.
|
|
44
|
+
|
|
45
|
+
### Supported Image Formats
|
|
46
|
+
The tool supports the following image formats for AI analysis:
|
|
47
|
+
- JPG/JPEG
|
|
48
|
+
- PNG
|
|
49
|
+
- GIF
|
|
50
|
+
- BMP
|
|
51
|
+
- WebP
|
|
52
|
+
- TIFF
|
|
53
|
+
- ICO
|
|
54
|
+
- JFIF
|
|
55
|
+
- SVG
|
|
56
|
+
|
|
57
|
+
### File Management Features
|
|
58
|
+
- Automatic directory creation for AI-driven organization
|
|
59
|
+
- Overwrite protection with optional override
|
|
60
|
+
- Comprehensive error handling and status reporting
|
|
61
|
+
- File metadata preservation during operations
|
|
62
|
+
- Validation of image files before processing
|
|
63
|
+
- Support for batch operations and automated organization
|
|
64
|
+
|
|
65
|
+
## AI Integration
|
|
66
|
+
|
|
67
|
+
This tool is designed to work seamlessly with AI systems, providing:
|
|
68
|
+
- Direct access to local image files for AI analysis
|
|
69
|
+
- Tools for AI-driven image organization
|
|
70
|
+
- Support for automated folder creation and management
|
|
71
|
+
- Metadata preservation during AI-driven reorganization
|
|
72
|
+
- Robust error handling for automated operations
|
|
73
|
+
|
|
74
|
+
## Error Handling
|
|
75
|
+
All operations include comprehensive error handling and return detailed status information including:
|
|
76
|
+
- Success/failure status
|
|
77
|
+
- Error messages (if any)
|
|
78
|
+
- File metadata
|
|
79
|
+
- Operation details
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
This project is distributed under the MIT License.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "jitora"
|
|
3
|
+
version = "1.1.0"
|
|
4
|
+
license = "MIT"
|
|
5
|
+
description = "sample mcp tool"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.14"
|
|
8
|
+
keywords = [
|
|
9
|
+
"image",
|
|
10
|
+
"management",
|
|
11
|
+
"processing",
|
|
12
|
+
"ai",
|
|
13
|
+
"organization",
|
|
14
|
+
"mcp",
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
21
|
+
"Topic :: Multimedia :: Graphics",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
"Operating System :: OS Independent",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"fastmcp>=4.0.3",
|
|
27
|
+
"pillow>=12.3.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[[project.authors]]
|
|
31
|
+
name = "sunshine-kjh"
|
|
32
|
+
email = "kimjihoon0@gmail.com"
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
jitora = "jitora:main"
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["uv_build>=0.12.3,<0.13.0"]
|
|
39
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "jitora"
|
|
3
|
+
version = "1.1.0"
|
|
4
|
+
license = "MIT"
|
|
5
|
+
description = "sample mcp tool"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.14"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "sunshine-kjh", email = "kimjihoon0@gmail.com" }
|
|
10
|
+
]
|
|
11
|
+
keywords = ["image", "management", "processing", "ai", "organization", "mcp"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 5 - Production/Stable",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
17
|
+
"Topic :: Multimedia :: Graphics",
|
|
18
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
19
|
+
"Operating System :: OS Independent"
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"fastmcp>=4.0.3",
|
|
23
|
+
"pillow>=12.3.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
jitora = "jitora:main"
|
|
28
|
+
|
|
29
|
+
[build-system]
|
|
30
|
+
requires = ["uv_build>=0.12.3,<0.13.0"]
|
|
31
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
from fastmcp import FastMCP
|
|
2
|
+
from fastmcp.utilities.types import Image
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from PIL import Image as PILImage
|
|
6
|
+
from io import BytesIO
|
|
7
|
+
from typing import Dict, Any
|
|
8
|
+
|
|
9
|
+
mcp = FastMCP("Jitora")
|
|
10
|
+
|
|
11
|
+
SUPPORTED_IMAGE_EXTENSIONS = {
|
|
12
|
+
'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp',
|
|
13
|
+
'.tiff', '.tif', '.ico', '.jfif', '.svg'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
def is_valid_image(filepath: str) -> bool:
|
|
17
|
+
"""
|
|
18
|
+
Check if the file is a valid image file.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
filepath (str): File path to check
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
bool: True if the file is an image, False otherwise.
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
_, ext = os.path.splitext(filepath.lower())
|
|
28
|
+
if ext in SUPPORTED_IMAGE_EXTENSIONS:
|
|
29
|
+
with PILImage.open(filepath) as _:
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
except Exception:
|
|
33
|
+
pass
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@mcp.tool()
|
|
38
|
+
def create_directory(
|
|
39
|
+
directory_path: str,
|
|
40
|
+
exist_ok: bool = True,
|
|
41
|
+
parents: bool = True
|
|
42
|
+
) -> Dict[str, Any]:
|
|
43
|
+
"""
|
|
44
|
+
Creates a directory at the specified path.
|
|
45
|
+
Creates a new directory if it doesn't exist and handles existing directories according to settings.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
directory_path (str): Path of the directory to create
|
|
49
|
+
exist_ok (bool): Whether to ignore errors if directory exists (default: True)
|
|
50
|
+
parents (bool): Whether to create parent directories if needed (default: True)
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Dict[str, Any]: Directory creation result information
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
directory_path = os.path.abspath(directory_path) # 절대경로로 변환. 포맷 동일화
|
|
58
|
+
already_exists = os.path.exists(directory_path)
|
|
59
|
+
|
|
60
|
+
if already_exists:
|
|
61
|
+
if not os.path.isdir(directory_path): # not directory
|
|
62
|
+
return {
|
|
63
|
+
"success": False,
|
|
64
|
+
"error": f"Path exists but is not a directory: {directory_path}"
|
|
65
|
+
}
|
|
66
|
+
elif not exist_ok: # exist_ok = False
|
|
67
|
+
return {
|
|
68
|
+
"success": False,
|
|
69
|
+
"error": f"Directory already exists: {directory_path}"
|
|
70
|
+
}
|
|
71
|
+
else:
|
|
72
|
+
return {
|
|
73
|
+
"success": True,
|
|
74
|
+
"message": f"Directory already exists: {directory_path}",
|
|
75
|
+
"path": directory_path,
|
|
76
|
+
"created": False
|
|
77
|
+
}
|
|
78
|
+
if parents:
|
|
79
|
+
os.makedirs(directory_path)
|
|
80
|
+
else:
|
|
81
|
+
try:
|
|
82
|
+
os.mkdir(directory_path)
|
|
83
|
+
except FileNotFoundError:
|
|
84
|
+
return {
|
|
85
|
+
"success": False,
|
|
86
|
+
"error": f"Parent path does not exist. Set parents = True: {directory_path}"
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
"success": True,
|
|
90
|
+
"message": f"Directory created successfully: {directory_path}",
|
|
91
|
+
"path": directory_path,
|
|
92
|
+
"created": True
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
except Exception as e:
|
|
96
|
+
return {
|
|
97
|
+
"success": False,
|
|
98
|
+
"error": str(e)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@mcp.tool()
|
|
102
|
+
def list_image_files(folder: str) -> str:
|
|
103
|
+
"""
|
|
104
|
+
Return a text list of image files in the specified folder.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
folder (Str): Folder path to search for image files.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
str: Text list of image files.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
folder = os.path.abspath(folder)
|
|
115
|
+
|
|
116
|
+
if not os.path.exists(folder):
|
|
117
|
+
return f"Error: Folder dose not exist: {folder}"
|
|
118
|
+
|
|
119
|
+
if not os.path.isdir(folder):
|
|
120
|
+
return f"Error: Specified path is not a directory: {folder}"
|
|
121
|
+
|
|
122
|
+
image_files = []
|
|
123
|
+
for filename in os.listdir(folder):
|
|
124
|
+
filepath = os.path.join(folder, filename)
|
|
125
|
+
if os.path.isfile(filepath) and is_valid_image:
|
|
126
|
+
image_files.append(filename)
|
|
127
|
+
|
|
128
|
+
if not image_files:
|
|
129
|
+
return f"No image files found in folder: {folder}"
|
|
130
|
+
|
|
131
|
+
result_lines = [
|
|
132
|
+
f"Folder: {folder}",
|
|
133
|
+
f"Number of image files: {len(image_files)}",
|
|
134
|
+
"---",
|
|
135
|
+
*[f"{i+1}. {name}" for i, name in enumerate(image_files)]
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
return "\n".join(result_lines)
|
|
139
|
+
|
|
140
|
+
except Exception as e:
|
|
141
|
+
return f"Error occurred: {str(e)}"
|
|
142
|
+
|
|
143
|
+
@mcp.tool()
|
|
144
|
+
def read_image(image_path: str) -> Image:
|
|
145
|
+
"""
|
|
146
|
+
Read an image file and return it as an Image odject.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
image_path (str) : Path to the image file
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Image: Image object
|
|
153
|
+
"""
|
|
154
|
+
img = PILImage.open(image_path)
|
|
155
|
+
buffer = BytesIO()
|
|
156
|
+
img_format = img.format.lower() if img.format else "png"
|
|
157
|
+
img.save(buffer, format=img_format)
|
|
158
|
+
return Image(data=buffer.getvalue(), format=img_format)
|
|
159
|
+
|
|
160
|
+
@mcp.tool()
|
|
161
|
+
def copy_image(
|
|
162
|
+
source_path: str,
|
|
163
|
+
destination_path: str,
|
|
164
|
+
overwrite: bool = False
|
|
165
|
+
) -> Dict[str, Any]:
|
|
166
|
+
"""
|
|
167
|
+
Copy an image file to a new location.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
source_path (str): Source image file path
|
|
171
|
+
destination_path (str): Destination image file path (including filename)
|
|
172
|
+
overwrite (bool): Whether to overwrite if destination file exists
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Dict[str, Any]: Copy result information
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
"""
|
|
179
|
+
try:
|
|
180
|
+
source_path = os.path.abspath(source_path)
|
|
181
|
+
destination_path = os.path.abspath(destination_path)
|
|
182
|
+
|
|
183
|
+
if not os.path.exists(source_path):
|
|
184
|
+
return {
|
|
185
|
+
"success": False,
|
|
186
|
+
"error": f"Source file does not exist: {source_path}"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if not is_valid_image(source_path):
|
|
190
|
+
return {
|
|
191
|
+
"success": False,
|
|
192
|
+
"error": f"Source file is not a valid image: {source_path}"
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
destination_dir = os.path.dirname(destination_path)
|
|
196
|
+
if not os.path.exists(destination_dir):
|
|
197
|
+
os.makedirs(destination_dir)
|
|
198
|
+
|
|
199
|
+
shutil.copy2(source_path, destination_path)
|
|
200
|
+
|
|
201
|
+
file_size = os.path.getsize(destination_path)
|
|
202
|
+
with PILImage.open(destination_path) as img:
|
|
203
|
+
width, height = img.size
|
|
204
|
+
format_name = img.format
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
"success": True,
|
|
208
|
+
"message": "Image file copied successfully.",
|
|
209
|
+
"source_path": source_path,
|
|
210
|
+
"destination_path": destination_path,
|
|
211
|
+
"file_size": file_size,
|
|
212
|
+
"width": width,
|
|
213
|
+
"height": height,
|
|
214
|
+
"format": format_name
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
return {
|
|
219
|
+
"success": False,
|
|
220
|
+
"error": str(e)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@mcp.tool()
|
|
224
|
+
def move_image(
|
|
225
|
+
source_path: str,
|
|
226
|
+
destination_path: str,
|
|
227
|
+
overwrite: bool = False
|
|
228
|
+
) -> Dict[str, Any]:
|
|
229
|
+
"""
|
|
230
|
+
Move an image file.
|
|
231
|
+
Can move to the same or different path, with the same or different filename.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
source_path (str): Source image file path
|
|
235
|
+
destination_path (str): Destination image file path (including filename)
|
|
236
|
+
overwrite (bool): Whether to overwrite if destination file exists
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
Dict[str, Any]: Move result information
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
try:
|
|
243
|
+
source_path = os.path.abspath(source_path)
|
|
244
|
+
destination_path = os.path.abspath(destination_path)
|
|
245
|
+
|
|
246
|
+
if not os.path.exists(source_path):
|
|
247
|
+
return {
|
|
248
|
+
"success": False,
|
|
249
|
+
"error": f"Source file does not exists: {source_path}"
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if not is_valid_image(source_path):
|
|
253
|
+
return {
|
|
254
|
+
"success": False,
|
|
255
|
+
"error": f"Source file is not a valid image: {source_path}"
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if os.path.exists(destination_path) and not overwrite:
|
|
259
|
+
return {
|
|
260
|
+
"success": False,
|
|
261
|
+
"error": f"Destination file already exists and overwrite is not allowed: {destination_path}"
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
file_name = os.path.basename(source_path)
|
|
265
|
+
file_size = os.path.getsize(source_path)
|
|
266
|
+
with PILImage.open(source_path) as img:
|
|
267
|
+
width, height = img.size
|
|
268
|
+
format_name = img.format
|
|
269
|
+
|
|
270
|
+
destination_dir = os.path.dirname(destination_path)
|
|
271
|
+
if not os.path.exists(destination_dir):
|
|
272
|
+
os.makedirs(destination_dir)
|
|
273
|
+
|
|
274
|
+
shutil.move(source_path, destination_path)
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
"success": True,
|
|
278
|
+
"message" : "Image file moved successfully.",
|
|
279
|
+
"source_path": source_path,
|
|
280
|
+
"destination_path": destination_path,
|
|
281
|
+
"file_name": file_name,
|
|
282
|
+
"file_size": file_size,
|
|
283
|
+
"width": width,
|
|
284
|
+
"height": height,
|
|
285
|
+
"format": format_name
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
except Exception as e:
|
|
289
|
+
return{
|
|
290
|
+
"success": False,
|
|
291
|
+
"error": str(e)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
@mcp.tool()
|
|
295
|
+
def delete_image(
|
|
296
|
+
image_path: str,
|
|
297
|
+
confirm: bool = True
|
|
298
|
+
) -> Dict[str, Any]:
|
|
299
|
+
"""
|
|
300
|
+
Delete an image file:
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
image_path (str): Path to the image file to delete
|
|
304
|
+
confirm (bool): Confirmation for deletion (default: True, prevents accidental deletion)
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
Dict[str, Any]: Deletion result information
|
|
308
|
+
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
try:
|
|
312
|
+
image_path = os.path.abspath(image_path)
|
|
313
|
+
|
|
314
|
+
if not os.path.exists(image_path):
|
|
315
|
+
return {
|
|
316
|
+
"success": False,
|
|
317
|
+
"error": f"File does not exist: {image_path}"
|
|
318
|
+
}
|
|
319
|
+
if not is_valid_image(image_path):
|
|
320
|
+
return {
|
|
321
|
+
"succcess": False,
|
|
322
|
+
"error": f"File is not a valid image: {image_path}"
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if not confirm:
|
|
326
|
+
return {
|
|
327
|
+
"success": False,
|
|
328
|
+
"error": "File deletion not confirmed. Set conform=True to conform deletion."
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
file_size = os.path.getsize(image_path)
|
|
332
|
+
file_name = os.path.basename(image_path)
|
|
333
|
+
|
|
334
|
+
os.remove(image_path)
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
"success": True,
|
|
338
|
+
"message": "Image file deleted successfully.",
|
|
339
|
+
"deleted_path": image_path,
|
|
340
|
+
"file_name": file_name,
|
|
341
|
+
"file_size": file_size
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
except Exception as e:
|
|
345
|
+
return {
|
|
346
|
+
"success": False,
|
|
347
|
+
"error": str(e)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
def main():
|
|
351
|
+
mcp.run(transport="stdio")
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# 23차시
|