iflow-mcp_cwahlfeldt_blender-mcp 0.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.
Files changed (25) hide show
  1. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/.gitignore +1 -0
  2. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/2985_process.log +4 -0
  3. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/PKG-INFO +117 -0
  4. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/README.md +104 -0
  5. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/blender/__init__.py +1 -0
  6. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/blender/executor.py +160 -0
  7. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/blender/uv_tools.py +323 -0
  8. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/examples/create_save_blend.py +67 -0
  9. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/examples/hello_cube.py +22 -0
  10. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/examples/modify_blend_file.py +33 -0
  11. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/examples/uv_mapping.py +315 -0
  12. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/language.json +1 -0
  13. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/package_name +1 -0
  14. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/push_info.json +5 -0
  15. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/pyproject.toml +39 -0
  16. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/requirements.txt +1 -0
  17. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/script_files/metadata.json +1 -0
  18. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/scripts/__init__.py +1 -0
  19. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/scripts/manager.py +200 -0
  20. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/server.py +87 -0
  21. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/utils/__init__.py +1 -0
  22. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/utils/helpers.py +206 -0
  23. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/utils/uv_integration.py +264 -0
  24. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/utils/uv_manager.py +64 -0
  25. iflow_mcp_cwahlfeldt_blender_mcp-0.1.0/uv.lock +405 -0
@@ -0,0 +1 @@
1
+ __pycache__
@@ -0,0 +1,4 @@
1
+ [2026-02-04 04:40:28] [SUCCESS] 获取项目: fork并克隆项目到本地成功,github_url=https://github.com/cwahlfeldt/blender-mcp, fork_github_url=https://github.com/iflow-mcp/cwahlfeldt-blender-mcp, name=cwahlfeldt-blender-mcp
2
+ [2026-02-04 04:40:53] [SUCCESS] 阅读代码: 项目类型为Python MCP服务端项目,使用FastMCP框架,支持stdio协议,非SKILL项目,非MCP代理服务,项目未过期
3
+ [2026-02-04 04:42:56] [SUCCESS] 本地测试: 构建和测试成功,修复了f-string语法错误,获取到4个工具(add_script, edit_script, execute_script, remove_script),无需环境变量配置
4
+ [2026-02-04 04:43:12] [SUCCESS] 推送iflow分支: 成功推送iflow分支到远程仓库 https://github.com/iflow-mcp/cwahlfeldt-blender-mcp
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.4
2
+ Name: iflow-mcp_cwahlfeldt_blender-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for executing Blender scripts
5
+ Author: Blender MCP Team
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: mcp>=0.1.0
8
+ Provides-Extra: dev
9
+ Requires-Dist: black>=23.0.0; extra == 'dev'
10
+ Requires-Dist: isort>=5.12.0; extra == 'dev'
11
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Blender MCP Server
15
+
16
+ A Model Context Protocol (MCP) server for managing and executing Blender scripts.
17
+
18
+ ## Features
19
+
20
+ - Add, edit, execute, and remove Blender Python scripts
21
+ - Execute scripts in a headless Blender environment
22
+ - View execution results and errors
23
+ - Track script metadata (creation date, last modified, execution count)
24
+
25
+ ## Requirements
26
+
27
+ - Python 3.7+
28
+ - Blender installed and accessible
29
+ - MCP library (`pip install mcp`)
30
+
31
+ ## Usage
32
+
33
+ 1. Start the server:
34
+ ```
35
+ python server.py
36
+ ```
37
+
38
+ 2. Connect to the server using an MCP client (like Claude Desktop)
39
+
40
+ 3. Use the provided tools to manage scripts:
41
+ - `add_script(name, content)` - Add a new script
42
+ - `edit_script(name, content)` - Edit an existing script
43
+ - `execute_script(name, blend_file=None)` - Execute a script in Blender, optionally specifying a .blend file
44
+ - `remove_script(name)` - Remove a script
45
+
46
+ 4. Access resources to get information:
47
+ - `scripts://list` - Get list of available scripts
48
+ - `script://{name}` - Get content of a specific script
49
+ - `result://{name}` - Get execution result of a script
50
+
51
+ ## Examples
52
+
53
+ ### Basic Example
54
+
55
+ ```python
56
+ # Add a simple script
57
+ add_script("hello_cube", '''
58
+ import bpy
59
+
60
+ # Clear existing objects
61
+ bpy.ops.object.select_all(action='SELECT')
62
+ bpy.ops.object.delete()
63
+
64
+ # Create a cube
65
+ bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, 0))
66
+ print("Cube created!")
67
+ ''')
68
+
69
+ # Execute the script
70
+ execute_script("hello_cube")
71
+
72
+ # Get the result
73
+ # Access using: result://hello_cube
74
+ ```
75
+
76
+ ### Working with Blend Files
77
+
78
+ ```python
79
+ # Add a script that works with a blend file
80
+ add_script("analyze_scene", '''
81
+ import bpy
82
+
83
+ # Print information about the current scene
84
+ print(f"Current Blender version: {bpy.app.version_string}")
85
+ print(f"Current file: {bpy.data.filepath}")
86
+
87
+ # List all objects in the scene
88
+ print("\\nObjects in the scene:")
89
+ for obj in bpy.data.objects:
90
+ print(f" - {obj.name} ({obj.type})")
91
+ ''')
92
+
93
+ # Execute with a specific blend file
94
+ execute_script("analyze_scene", blend_file="/path/to/your/project.blend")
95
+
96
+ # Get the result
97
+ # Access using: result://analyze_scene
98
+ ```
99
+
100
+ ## How It Works
101
+
102
+ 1. When a script is added, it's stored in the `script_files/scripts` directory
103
+ 2. When executed, the script is run in a headless Blender instance
104
+ - If a blend file is specified, Blender will open that file before running the script
105
+ - Otherwise, a default empty Blender scene is used
106
+ 3. Output and errors are captured and stored in the `script_files/results` directory
107
+ 4. Metadata about scripts is tracked in `script_files/metadata.json`
108
+
109
+ ## Installation
110
+
111
+ 1. Clone this repository
112
+ 2. Install the MCP library: `pip install mcp`
113
+ 3. Ensure Blender is installed and accessible from your PATH
114
+
115
+ ## License
116
+
117
+ MIT
@@ -0,0 +1,104 @@
1
+ # Blender MCP Server
2
+
3
+ A Model Context Protocol (MCP) server for managing and executing Blender scripts.
4
+
5
+ ## Features
6
+
7
+ - Add, edit, execute, and remove Blender Python scripts
8
+ - Execute scripts in a headless Blender environment
9
+ - View execution results and errors
10
+ - Track script metadata (creation date, last modified, execution count)
11
+
12
+ ## Requirements
13
+
14
+ - Python 3.7+
15
+ - Blender installed and accessible
16
+ - MCP library (`pip install mcp`)
17
+
18
+ ## Usage
19
+
20
+ 1. Start the server:
21
+ ```
22
+ python server.py
23
+ ```
24
+
25
+ 2. Connect to the server using an MCP client (like Claude Desktop)
26
+
27
+ 3. Use the provided tools to manage scripts:
28
+ - `add_script(name, content)` - Add a new script
29
+ - `edit_script(name, content)` - Edit an existing script
30
+ - `execute_script(name, blend_file=None)` - Execute a script in Blender, optionally specifying a .blend file
31
+ - `remove_script(name)` - Remove a script
32
+
33
+ 4. Access resources to get information:
34
+ - `scripts://list` - Get list of available scripts
35
+ - `script://{name}` - Get content of a specific script
36
+ - `result://{name}` - Get execution result of a script
37
+
38
+ ## Examples
39
+
40
+ ### Basic Example
41
+
42
+ ```python
43
+ # Add a simple script
44
+ add_script("hello_cube", '''
45
+ import bpy
46
+
47
+ # Clear existing objects
48
+ bpy.ops.object.select_all(action='SELECT')
49
+ bpy.ops.object.delete()
50
+
51
+ # Create a cube
52
+ bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, 0))
53
+ print("Cube created!")
54
+ ''')
55
+
56
+ # Execute the script
57
+ execute_script("hello_cube")
58
+
59
+ # Get the result
60
+ # Access using: result://hello_cube
61
+ ```
62
+
63
+ ### Working with Blend Files
64
+
65
+ ```python
66
+ # Add a script that works with a blend file
67
+ add_script("analyze_scene", '''
68
+ import bpy
69
+
70
+ # Print information about the current scene
71
+ print(f"Current Blender version: {bpy.app.version_string}")
72
+ print(f"Current file: {bpy.data.filepath}")
73
+
74
+ # List all objects in the scene
75
+ print("\\nObjects in the scene:")
76
+ for obj in bpy.data.objects:
77
+ print(f" - {obj.name} ({obj.type})")
78
+ ''')
79
+
80
+ # Execute with a specific blend file
81
+ execute_script("analyze_scene", blend_file="/path/to/your/project.blend")
82
+
83
+ # Get the result
84
+ # Access using: result://analyze_scene
85
+ ```
86
+
87
+ ## How It Works
88
+
89
+ 1. When a script is added, it's stored in the `script_files/scripts` directory
90
+ 2. When executed, the script is run in a headless Blender instance
91
+ - If a blend file is specified, Blender will open that file before running the script
92
+ - Otherwise, a default empty Blender scene is used
93
+ 3. Output and errors are captured and stored in the `script_files/results` directory
94
+ 4. Metadata about scripts is tracked in `script_files/metadata.json`
95
+
96
+ ## Installation
97
+
98
+ 1. Clone this repository
99
+ 2. Install the MCP library: `pip install mcp`
100
+ 3. Ensure Blender is installed and accessible from your PATH
101
+
102
+ ## License
103
+
104
+ MIT
@@ -0,0 +1 @@
1
+ # blender module initialization
@@ -0,0 +1,160 @@
1
+ import subprocess
2
+ import os
3
+ import tempfile
4
+ from pathlib import Path
5
+ import logging
6
+
7
+ class BlenderExecutor:
8
+ """Class to handle script execution in Blender"""
9
+
10
+ def __init__(self, blender_path=None, timeout=60):
11
+ """
12
+ Initialize the BlenderExecutor
13
+
14
+ Args:
15
+ blender_path (str, optional): Path to the Blender executable. If None, will try to find it.
16
+ timeout (int, optional): Timeout for script execution in seconds
17
+ """
18
+ self.blender_path = blender_path or self._find_blender_executable()
19
+ self.timeout = timeout
20
+ self.temp_dir = Path(tempfile.gettempdir()) / "blender_mcp"
21
+ self._setup()
22
+
23
+ def _setup(self):
24
+ """Setup the executor, create necessary directories"""
25
+ os.makedirs(self.temp_dir, exist_ok=True)
26
+
27
+ def _find_blender_executable(self):
28
+ """Find Blender executable path"""
29
+ # Try common locations
30
+ common_paths = [
31
+ "blender", # If it's in PATH
32
+ "/usr/bin/blender",
33
+ "/usr/local/bin/blender",
34
+ "/Applications/Blender.app/Contents/MacOS/Blender",
35
+ "C:\\Program Files\\Blender Foundation\\Blender\\blender.exe",
36
+ ]
37
+
38
+ for path in common_paths:
39
+ try:
40
+ # Just check if we can run it with --version
41
+ subprocess.run([path, "--version"],
42
+ stdout=subprocess.PIPE,
43
+ stderr=subprocess.PIPE,
44
+ timeout=5)
45
+ return path
46
+ except (subprocess.SubprocessError, FileNotFoundError):
47
+ continue
48
+
49
+ # If we couldn't find it, default to "blender" and hope it's in PATH
50
+ return "blender"
51
+
52
+ def execute(self, script_name, script_content, blend_file=None):
53
+ """
54
+ Execute a script in Blender
55
+
56
+ Args:
57
+ script_name (str): Name of the script
58
+ script_content (str): Content of the script to execute
59
+ blend_file (str, optional): Path to a .blend file to use
60
+
61
+ Returns:
62
+ str: Output of the script execution
63
+ """
64
+ # Create a temporary script file
65
+ script_file = self.temp_dir / f"{script_name}.py"
66
+ output_file = self.temp_dir / f"{script_name}.out"
67
+
68
+ # Prepare variables to avoid f-string backslash issues
69
+ output_file_str = str(output_file)
70
+ newlines = "\n\n"
71
+
72
+ # Write the script content with output capture
73
+ with open(script_file, "w") as f:
74
+ # Add code to capture stdout and stderr
75
+ indented_script = script_content.replace('\n', '\n ')
76
+ wrapped_script = f"""
77
+ import sys
78
+ import io
79
+ import traceback
80
+
81
+ # Redirect stdout and stderr
82
+ old_stdout = sys.stdout
83
+ old_stderr = sys.stderr
84
+ stdout_buffer = io.StringIO()
85
+ stderr_buffer = io.StringIO()
86
+ sys.stdout = stdout_buffer
87
+ sys.stderr = stderr_buffer
88
+
89
+ try:
90
+ # Execute the script
91
+ {indented_script}
92
+ except Exception as e:
93
+ print(f"Error executing script: {{e}}")
94
+ traceback.print_exc()
95
+ finally:
96
+ # Restore stdout and stderr
97
+ sys.stdout = old_stdout
98
+ sys.stderr = old_stderr
99
+
100
+ # Write output to file
101
+ with open(r"{output_file_str}", "w") as output:
102
+ output.write(stdout_buffer.getvalue())
103
+ output.write("{newlines}")
104
+ output.write(stderr_buffer.getvalue())
105
+ """
106
+ f.write(wrapped_script)
107
+
108
+ try:
109
+ # Run Blender with the script
110
+ cmd = [
111
+ self.blender_path,
112
+ "--background", # Run without GUI
113
+ ]
114
+
115
+ # Add blend file if provided
116
+ if blend_file:
117
+ if os.path.exists(blend_file):
118
+ cmd.extend(["--file", blend_file])
119
+ else:
120
+ return f"Error: Blend file not found: {blend_file}"
121
+
122
+ # Add Python script
123
+ cmd.extend(["--python", str(script_file)])
124
+
125
+ process = subprocess.run(
126
+ cmd,
127
+ stdout=subprocess.PIPE,
128
+ stderr=subprocess.PIPE,
129
+ timeout=self.timeout,
130
+ text=True
131
+ )
132
+
133
+ # Check if the output file exists
134
+ if output_file.exists():
135
+ with open(output_file, "r") as f:
136
+ script_output = f.read()
137
+ else:
138
+ script_output = "No output captured from script."
139
+
140
+ # Add Blender's stdout/stderr if there was an error
141
+ if process.returncode != 0:
142
+ script_output += "\n\nBlender process output:\n"
143
+ script_output += f"STDOUT: {process.stdout}\n"
144
+ script_output += f"STDERR: {process.stderr}"
145
+
146
+ return script_output
147
+
148
+ except subprocess.TimeoutExpired:
149
+ return f"Script execution timed out after {self.timeout} seconds"
150
+ except Exception as e:
151
+ return f"Error executing script: {str(e)}"
152
+ finally:
153
+ # Clean up temp files
154
+ try:
155
+ if script_file.exists():
156
+ script_file.unlink()
157
+ if output_file.exists():
158
+ output_file.unlink()
159
+ except Exception as e:
160
+ logging.warning(f"Failed to clean up temp files: {e}")