lomit's picture
Sync from forma-3d-review@b6d4687f5d0f2e5303758c97095ea7e38e740723
182efca verified
"""MCP tool definitions for CAD review."""
from __future__ import annotations
import logging
from pathlib import Path
logger = logging.getLogger(__name__)
def register_tools(mcp):
"""Register all MCP tools."""
@mcp.tool()
def get_assembly_tree(job_id: str) -> str:
"""Get the assembly tree structure for a loaded STEP file.
Args:
job_id: The job ID from uploading a STEP file.
"""
from src.api.router import get_manager
manager = get_manager()
job = manager.get_job(job_id)
if job is None:
return f"Error: Job not found: {job_id}"
if job.assembly_tree is None:
return f"Error: Assembly tree not available yet (status: {job.status})"
import json
return json.dumps(job.assembly_tree.to_dict(), indent=2)
@mcp.tool()
def get_part_info(job_id: str, part_id: str) -> str:
"""Get detailed information about a specific part.
Args:
job_id: The job ID.
part_id: The part ID from the assembly tree.
"""
from src.api.router import get_manager
manager = get_manager()
job = manager.get_job(job_id)
if job is None:
return f"Error: Job not found: {job_id}"
if job.assembly_tree is None:
return "Error: Assembly tree not available yet"
node = job.assembly_tree.find_by_id(part_id)
if node is None:
return f"Error: Part not found: {part_id}"
import json
info = node.to_dict()
mesh = job.part_meshes.get(part_id)
if mesh:
info["mesh_vertices"] = len(mesh.vertices)
info["mesh_triangles"] = len(mesh.triangles)
return json.dumps(info, indent=2)
@mcp.tool()
def measure_part_distance(job_id: str, part_a_id: str, part_b_id: str) -> str:
"""Measure the minimum distance between two parts.
Args:
job_id: The job ID.
part_a_id: ID of the first part.
part_b_id: ID of the second part.
"""
from src.api.router import get_manager
from src.geometry.measurement import measure_distance
manager = get_manager()
job = manager.get_job(job_id)
if job is None:
return f"Error: Job not found: {job_id}"
if job.assembly_tree is None:
return "Error: Assembly tree not available yet"
node_a = job.assembly_tree.find_by_id(part_a_id)
node_b = job.assembly_tree.find_by_id(part_b_id)
if node_a is None or node_a.shape is None:
return f"Error: Part not found or has no shape: {part_a_id}"
if node_b is None or node_b.shape is None:
return f"Error: Part not found or has no shape: {part_b_id}"
result = measure_distance(node_a.shape, node_b.shape)
import json
return json.dumps({
"distance_mm": result.distance_mm,
"point_a": result.point_a,
"point_b": result.point_b,
}, indent=2)
@mcp.tool()
def check_compliance_rules(job_id: str) -> str:
"""Run compliance checks on the loaded assembly.
Args:
job_id: The job ID.
"""
from src.api.router import get_manager
from src.compliance.kmvss_checker import check_compliance
from src.compliance.rule_loader import load_rules
manager = get_manager()
job = manager.get_job(job_id)
if job is None:
return f"Error: Job not found: {job_id}"
if job.assembly_tree is None:
return "Error: Assembly tree not available yet"
rules_path = Path(__file__).parent.parent.parent / "config" / "kmvss_rules.yaml"
rules = load_rules(rules_path)
results = check_compliance(rules, job.assembly_tree)
import json
return json.dumps([{
"rule": r.rule_name,
"passed": r.passed,
"message": r.message,
"severity": r.severity,
} for r in results], indent=2)
@mcp.tool()
def get_collision_report(job_id: str) -> str:
"""Get a collision/proximity report for all parts.
Args:
job_id: The job ID.
"""
from src.api.router import get_manager
from src.geometry.measurement import scan_proximity
manager = get_manager()
job = manager.get_job(job_id)
if job is None:
return f"Error: Job not found: {job_id}"
if job.assembly_tree is None:
return "Error: Assembly tree not available yet"
parts = []
for leaf in job.assembly_tree.iter_leaves():
if leaf.shape is not None and not leaf.shape.IsNull():
parts.append({"id": leaf.id, "name": leaf.name, "shape": leaf.shape})
results = scan_proximity(parts)
import json
return json.dumps([{
"part_a": r.part_a_name,
"part_b": r.part_b_name,
"distance_mm": r.min_distance_mm,
"status": r.status,
} for r in results], indent=2)