merge from source#2
Conversation
Updated Windows installation instructions for UV. The previous instructions used set Path=..., which only works in CMD and only temporarily modifies the PATH for that CMD session (and any new processes launched from it). This was inconsistent with the preceding PowerShell-based install command (irm ... | iex), and would fail if run in PowerShell. Updated the example to use a proper PowerShell approach that dynamically resolves the current user's home directory via $env:USERPROFILE and appends .local\bin to the user-level PATH persistently (so the user does not have to set it each time before launching Claude Code).
Fixed possible issue in instructions for adding uv to user path in Windows, so as not to inadvertently overwrite existing user path with system path.
Revised UV installation steps for Windows
Co-authored-by: 家靖 <zhangjiajing.zjj@alibaba-inc.com>
There was a problem hiding this comment.
Pull request overview
This pull request merges updates from source, primarily adding Hunyuan3D support and telemetry infrastructure to the Blender MCP project.
Key Changes
- Telemetry system: Added anonymous telemetry tracking for tool usage via Supabase, with environment variable opt-out support
- Hunyuan3D integration: Implemented 3D model generation using Tencent's Hunyuan3D API (both official and local API modes)
- Infrastructure improvements: Increased socket timeout from 15s to 180s to support longer-running 3D generation tasks
Reviewed changes
Copilot reviewed 6 out of 8 changed files in this pull request and generated 26 comments.
Show a summary per file
| File | Description |
|---|---|
| src/blender_mcp/telemetry.py | New telemetry collection module for tracking tool usage and performance metrics |
| src/blender_mcp/telemetry_decorator.py | Decorator for instrumenting MCP tools with telemetry tracking |
| src/blender_mcp/server.py | Added telemetry decorators to existing tools, implemented Hunyuan3D tool functions, increased socket timeouts |
| addon.py | Implemented Hunyuan3D API integration including job creation, polling, and asset import; added UI properties for configuration |
| pyproject.toml | Updated version to 1.4.0 and added dependencies for supabase and tomli |
| README.md | Updated release notes and installation instructions for Windows |
| .gitignore | Added config.py to gitignore for storing telemetry secrets |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import shutil | ||
| import zipfile | ||
| from bpy.props import StringProperty, IntProperty, BoolProperty, EnumProperty | ||
| from bpy.props import IntProperty |
There was a problem hiding this comment.
The import statement for EnumProperty has been removed, but it's still needed by the blendermcp_hunyuan3d_mode property defined at line 2259. This will cause a NameError when the addon is registered.
| from bpy.props import IntProperty | |
| from bpy.props import IntProperty, EnumProperty |
|
|
||
| def poll_hunyuan_job_status_ai(self, job_id: str): | ||
| """Call the job status API to get the job status""" | ||
| print(job_id) |
There was a problem hiding this comment.
Debug print statement left in production code. This should be removed or converted to proper logging.
| import shutil | ||
| import zipfile | ||
| from bpy.props import StringProperty, IntProperty, BoolProperty, EnumProperty | ||
| from bpy.props import IntProperty |
There was a problem hiding this comment.
The import statement for FloatProperty is missing but it's needed by the blendermcp_hunyuan3d_guidance_scale property defined at line 2304. This will cause a NameError when the addon is registered.
| from bpy.props import IntProperty | |
| from bpy.props import IntProperty, FloatProperty |
| ) | ||
| self._worker.start() | ||
|
|
||
| logger.warning(f"Telemetry initialized (enabled={self.config.enabled}, has_supabase={HAS_SUPABASE}, customer_uuid={self._customer_uuid})") |
There was a problem hiding this comment.
Using logger.warning() for informational telemetry messages (lines 96, 113, 178, 181, 184) is incorrect. These should use logger.info() or logger.debug() instead, as they are not actual warnings that need user attention.
| logger.warning(f"Telemetry initialized (enabled={self.config.enabled}, has_supabase={HAS_SUPABASE}, customer_uuid={self._customer_uuid})") | |
| logger.info(f"Telemetry initialized (enabled={self.config.enabled}, has_supabase={HAS_SUPABASE}, customer_uuid={self._customer_uuid})") |
| logger.warning(f"Supabase not available, skipping event: {event_type}") | ||
| return | ||
|
|
||
| logger.warning(f"Recording telemetry event: {event_type}, tool={tool_name}") |
There was a problem hiding this comment.
Using logger.warning() for informational telemetry messages is incorrect. These should use logger.info() or logger.debug() instead, as they are not actual warnings that need user attention.
| logger.warning(f"Recording telemetry event: {event_type}, tool={tool_name}") | |
| logger.info(f"Recording telemetry event: {event_type}, tool={tool_name}") |
| } | ||
|
|
||
| response = supabase.table("telemetry_events").insert(data, returning="minimal").execute() | ||
| logger.debug(f"Telemetry sent: {event.event_type}") |
There was a problem hiding this comment.
Variable response is not used.
| logger.debug(f"Telemetry sent: {event.event_type}") | |
| logger.debug(f"Telemetry sent: {event.event_type}, response: {response}") |
| temp_dir = tempfile.mkdtemp(prefix="tencent_obj_") | ||
| zip_file_path = osp.join(temp_dir, "model.zip") | ||
| obj_file_path = osp.join(temp_dir, "model.obj") | ||
| mtl_file_path = osp.join(temp_dir, "model.mtl") |
There was a problem hiding this comment.
Variable mtl_file_path is not used.
| from urllib.parse import urlparse | ||
|
|
||
| # Import telemetry | ||
| from .telemetry import record_startup, get_telemetry |
There was a problem hiding this comment.
Import of 'get_telemetry' is not used.
| from .telemetry import record_startup, get_telemetry | |
| from .telemetry import record_startup |
| """ | ||
|
|
||
| import contextlib | ||
| import json |
There was a problem hiding this comment.
Import of 'json' is not used.
| import json |
| data = tomli.load(f) | ||
| return data["project"]["version"] | ||
| except Exception: | ||
| pass |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
| pass | |
| # Log the exception but return "unknown" as a fallback | |
| logger.exception("Failed to read version from pyproject.toml") |
* feat: Add Sketchfab model preview functionality
- Add get_sketchfab_model_preview handler in addon.py
- Fetches thumbnail from Sketchfab API
- Returns base64-encoded image with model info
- Add get_sketchfab_model_preview MCP tool in server.py
- Returns Image type for visual confirmation
- Allows users to preview models before downloading
* feat: Add size normalization for Sketchfab model imports
- Add normalize_size and target_size parameters to download_sketchfab_model
- Calculate combined bounding box for all imported mesh objects
- Apply uniform scale to normalize largest dimension to target_size
- Return detailed import info: dimensions, bounding box, scale factor
- Default: normalize_size=True, target_size=1.0 (1 meter)
This prevents extremely large or small models from being imported,
making it easier for LLMs to work with consistent object sizes.
* feat: Make target_size required parameter for Sketchfab downloads
- Remove normalize_size parameter (always normalize now)
- Make target_size a required parameter with no default value
- Add helpful examples in docstring for common object sizes
- Forces LLM to explicitly consider and specify model size
* chore: Remove temporary test files from development
* fix: Correct bounding box calculation and scale application for hierarchical models
- Add recursive get_all_mesh_children() to collect meshes from entire hierarchy
- Fix bounding box calculation to include all nested mesh objects
- Use transform_apply() to properly apply scale to entire object hierarchy
- Prevents parts from becoming scattered when scaling complex models
This fixes issues with Sketchfab models that have deep hierarchies like:
Sketchfab_model (EMPTY)
└─ RootNode (EMPTY)
└─ Chassis (MESH) ← now correctly included
* fix: Apply scale only to root objects to prevent cumulative scaling
- Find root objects (objects without parents) instead of all selected objects
- Apply scale factor ONLY to root objects, not children
- Remove transform_apply (parent scale automatically affects children via matrix_world)
- Child meshes inherit scaling through Blender's hierarchy system
Fixes issue where scale was applied to every object in hierarchy,
causing cumulative scaling (0.007^5 ≈ 0) that made models invisible.
Added instructions for using the Claude Code CLI to add the blender MCP server.
test