We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ShirshovDIM/retopoflow_blender_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""
Modifier tools for retopology workflows.
Provides safe, parameterized tools for adding and configuring Blender modifiers.
"""
from typing import Dict, Any, List, Optional
from mcp.server.fastmcp import Context
import logging
logger = logging.getLogger("BlenderMCPServer")
# ============================================================================
# MIRROR MODIFIER
# ============================================================================
def add_mirror_modifier(
ctx: Context,
blender_connection,
axis: str = "X",
use_clip: bool = True,
use_bisect: bool = True,
mirror_object: Optional[str] = None
) -> str:
"""
Add a Mirror modifier to the active mesh object.
Creates a Mirror modifier that mirrors the mesh along the specified axis
with optional clipping and bisecting.
Parameters:
- axis: Mirror axis - 'X', 'Y', or 'Z' (default: 'X')
- use_clip: Prevent vertices from crossing the mirror plane (default: true)
- use_bisect: Cut the mesh at the mirror plane (default: true)
- mirror_object: Name of object to use as mirror plane (optional)
Returns status message with modifier details.
"""
try:
if axis not in ['X', 'Y', 'Z']:
return f"Error: Invalid axis '{axis}'. Must be 'X', 'Y', or 'Z'."
result = blender_connection.send_command("add_mirror_modifier", {
"axis": axis,
"use_clip": use_clip,
"use_bisect": use_bisect,
"mirror_object": mirror_object
})
if "error" in result:
return f"Error: {result['error']}"
output = "Mirror Modifier Added!\n\n"
output += f"Mirror Axis: {axis}\n"
output += f"Clipping: {use_clip}\n"
output += f"Bisect: {use_bisect}\n"
if mirror_object:
output += f"Mirror Object: {mirror_object}\n"
return output
except Exception as e:
logger.error(f"Error adding mirror modifier: {str(e)}")
return f"Error adding mirror modifier: {str(e)}"
# ============================================================================
# SHRINKWRAP MODIFIER
# ============================================================================
def add_shrinkwrap_modifier(
ctx: Context,
blender_connection,
target: str,
method: str = "NEAREST_SURFACEPOINT",
offset: float = 0.0,
on_cage: bool = True,
cull_backfaces: bool = False
) -> str:
"""
Add a Shrinkwrap modifier to project low-poly mesh onto high-poly surface.
Projects vertices of the active object onto the target surface using the
specified method. Essential for retopology workflows.
Parameters:
- target: Name of the target object to shrinkwrap to
- method: Wrap method - 'NEAREST_SURFACEPOINT', 'PROJECT', 'NEAREST_VERTEX', 'TARGET_PROJECT' (default: 'NEAREST_SURFACEPOINT')
- offset: Distance to offset from target surface (default: 0.0)
- on_cage: Project in screen space for retopology (default: true)
- cull_backfaces: Don't project to backfaces (default: false)
Returns status message with modifier details.
"""
try:
valid_methods = ['NEAREST_SURFACEPOINT', 'PROJECT', 'NEAREST_VERTEX', 'TARGET_PROJECT']
if method not in valid_methods:
return f"Error: Invalid method '{method}'. Must be one of {valid_methods}."
result = blender_connection.send_command("add_shrinkwrap_modifier", {
"target": target,
"method": method,
"offset": offset,
"on_cage": on_cage,
"cull_backfaces": cull_backfaces
})
if "error" in result:
return f"Error: {result['error']}"
output = "Shrinkwrap Modifier Added!\n\n"
output += f"Target: {target}\n"
output += f"Method: {method}\n"
output += f"Offset: {offset}\n"
output += f"On Cage: {on_cage}\n"
output += f"Cull Backfaces: {cull_backfaces}\n"
return output
except Exception as e:
logger.error(f"Error adding shrinkwrap modifier: {str(e)}")
return f"Error adding shrinkwrap modifier: {str(e)}"
# ============================================================================
# WEIGHTED NORMAL MODIFIER
# ============================================================================
def add_weighted_normal_modifier(
ctx: Context,
blender_connection,
mode: str = "FACE_AREA",
weight: int = 50,
keep_sharp: bool = True,
face_influence: bool = True
) -> str:
"""
Add a Weighted Normal modifier to improve hard-surface shading.
Recalculates custom normals using face area or corner angle weighting
to improve shading on hard-surface models without adding geometry.
Parameters:
- mode: Weighting mode - 'FACE_AREA', 'CORNER_ANGLE', 'FACE_AREA_WITH_ANGLE' (default: 'FACE_AREA')
- weight: Weight influence 0-100 (default: 50)
- keep_sharp: Keep sharp edges (default: true)
- face_influence: Use face influence (default: true)
Returns status message with modifier details.
"""
try:
valid_modes = ['FACE_AREA', 'CORNER_ANGLE', 'FACE_AREA_WITH_ANGLE']
if mode not in valid_modes:
return f"Error: Invalid mode '{mode}'. Must be one of {valid_modes}."
if not 0 <= weight <= 100:
return f"Error: Weight must be between 0 and 100."
result = blender_connection.send_command("add_weighted_normal_modifier", {
"mode": mode,
"weight": weight,
"keep_sharp": keep_sharp,
"face_influence": face_influence
})
if "error" in result:
return f"Error: {result['error']}"
output = "Weighted Normal Modifier Added!\n\n"
output += f"Mode: {mode}\n"
output += f"Weight: {weight}\n"
output += f"Keep Sharp: {keep_sharp}\n"
output += f"Face Influence: {face_influence}\n"
return output
except Exception as e:
logger.error(f"Error adding weighted normal modifier: {str(e)}")
return f"Error adding weighted normal modifier: {str(e)}"
# ============================================================================
# DATA TRANSFER MODIFIER
# ============================================================================
def add_data_transfer_modifier(
ctx: Context,
blender_connection,
source: str,
data_types: List[str],
mapping: str = "NEAREST_FACE",
mix_factor: float = 1.0
) -> str:
"""
Add a Data Transfer modifier to copy data from high-poly to low-poly.
Transfers various data types (normals, UVs, vertex colors, etc.) from
a source object to the active object using specified mapping method.
Parameters:
- source: Name of the source object to transfer data from
- data_types: List of data types to transfer - ['CUSTOM_NORMAL', 'UV', 'VCOL', 'VGROUP_WEIGHTS']
- mapping: Mapping method - 'NEAREST_FACE', 'NEAREST_VERTEX', 'POLYINTERP_NEAREST', 'POLYINTERP_LNORPROJ' (default: 'NEAREST_FACE')
- mix_factor: Blend factor 0-1 (default: 1.0)
Returns status message with modifier details.
"""
try:
valid_data_types = ['CUSTOM_NORMAL', 'UV', 'VCOL', 'VGROUP_WEIGHTS']
for dt in data_types:
if dt not in valid_data_types:
return f"Error: Invalid data type '{dt}'. Must be one of {valid_data_types}."
valid_mappings = ['NEAREST_FACE', 'NEAREST_VERTEX', 'POLYINTERP_NEAREST', 'POLYINTERP_LNORPROJ']
if mapping not in valid_mappings:
return f"Error: Invalid mapping '{mapping}'. Must be one of {valid_mappings}."
if not 0.0 <= mix_factor <= 1.0:
return f"Error: Mix factor must be between 0.0 and 1.0."
result = blender_connection.send_command("add_data_transfer_modifier", {
"source": source,
"data_types": data_types,
"mapping": mapping,
"mix_factor": mix_factor
})
if "error" in result:
return f"Error: {result['error']}"
output = "Data Transfer Modifier Added!\n\n"
output += f"Source: {source}\n"
output += f"Data Types: {', '.join(data_types)}\n"
output += f"Mapping: {mapping}\n"
output += f"Mix Factor: {mix_factor}\n"
return output
except Exception as e:
logger.error(f"Error adding data transfer modifier: {str(e)}")
return f"Error adding data transfer modifier: {str(e)}"
# ============================================================================
# DECIMATE MODIFIER
# ============================================================================
def add_decimate_modifier(
ctx: Context,
blender_connection,
mode: str = "COLLAPSE",
ratio: float = 0.5,
iterations: int = 1
) -> str:
"""
Add a Decimate modifier to reduce polygon count predictably.
Reduces mesh complexity using collapse, dissolve, or un-subdivide modes
while attempting to preserve overall shape.
Parameters:
- mode: Decimation mode - 'COLLAPSE', 'DISSOLVE', 'UNSUBDIV' (default: 'COLLAPSE')
- ratio: For COLLAPSE: reduction ratio 0-1 (default: 0.5). For others: 1.0
- iterations: For UNSUBDIV: number of iterations (default: 1)
Returns status message with modifier details and predicted face count.
"""
try:
valid_modes = ['COLLAPSE', 'DISSOLVE', 'UNSUBDIV']
if mode not in valid_modes:
return f"Error: Invalid mode '{mode}'. Must be one of {valid_modes}."
if mode == 'COLLAPSE' and not 0.0 < ratio <= 1.0:
return f"Error: For COLLAPSE mode, ratio must be between 0 and 1."
if mode == 'UNSUBDIV' and iterations < 1:
return f"Error: For UNSUBDIV mode, iterations must be at least 1."
result = blender_connection.send_command("add_decimate_modifier", {
"mode": mode,
"ratio": ratio,
"iterations": iterations
})
if "error" in result:
return f"Error: {result['error']}"
output = "Decimate Modifier Added!\n\n"
output += f"Mode: {mode}\n"
if mode == 'COLLAPSE':
output += f"Ratio: {ratio}\n"
if mode == 'UNSUBDIV':
output += f"Iterations: {iterations}\n"
if 'face_count' in result:
output += f"Current Face Count: {result['face_count']}\n"
if 'predicted_faces' in result:
output += f"Predicted Face Count: {result['predicted_faces']}\n"
return output
except Exception as e:
logger.error(f"Error adding decimate modifier: {str(e)}")
return f"Error adding decimate modifier: {str(e)}"
# ============================================================================
# LAPLACIAN SMOOTH MODIFIER
# ============================================================================
def add_laplacian_smooth_modifier(
ctx: Context,
blender_connection,
factor: float = 1.0,
repeat: int = 2,
preserve_volume: bool = True
) -> str:
"""
Add a Laplacian Smooth modifier to reduce surface noise.
Applies Laplacian smoothing to reduce noise and high-frequency detail
while optionally preserving overall volume.
Parameters:
- factor: Smoothing factor 0-100 (default: 1.0)
- repeat: Number of iterations (default: 2)
- preserve_volume: Maintain mesh volume (default: true)
Returns status message with modifier details.
"""
try:
if not 0.0 <= factor <= 100.0:
return f"Error: Factor must be between 0 and 100."
if repeat < 1:
return f"Error: Repeat must be at least 1."
result = blender_connection.send_command("add_laplacian_smooth_modifier", {
"factor": factor,
"repeat": repeat,
"preserve_volume": preserve_volume
})
if "error" in result:
return f"Error: {result['error']}"
output = "Laplacian Smooth Modifier Added!\n\n"
output += f"Factor: {factor}\n"
output += f"Iterations: {repeat}\n"
output += f"Preserve Volume: {preserve_volume}\n"
return output
except Exception as e:
logger.error(f"Error adding laplacian smooth modifier: {str(e)}")
return f"Error adding laplacian smooth modifier: {str(e)}"