rhinomcp 0.1.1.3__py3-none-any.whl → 0.1.2.0__py3-none-any.whl

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.
rhinomcp/__init__.py CHANGED
@@ -5,8 +5,7 @@ __version__ = "0.1.0"
5
5
  # Expose key classes and functions for easier imports
6
6
  from .server import RhinoConnection, get_rhino_connection, mcp, logger
7
7
 
8
- from .prompts.assert_creation_strategy import asset_creation_strategy
9
- from .prompts.assert_query_strategy import assert_query_strategy
8
+ from .prompts.assert_general_strategy import asset_general_strategy
10
9
 
11
10
  from .tools.create_object import create_object
12
11
  from .tools.create_objects import create_objects
@@ -15,5 +14,8 @@ from .tools.get_document_info import get_document_info
15
14
  from .tools.get_object_info import get_object_info
16
15
  from .tools.get_selected_objects_info import get_selected_objects_info
17
16
  from .tools.modify_object import modify_object
17
+ from .tools.modify_objects import modify_objects
18
18
  from .tools.execute_rhinoscript_python_code import execute_rhinoscript_python_code
19
+ from .tools.select_objects import select_objects
19
20
 
21
+ from .resources.rhinoscriptsyntax_resource import get_rhinoscriptsyntax_resource
@@ -2,20 +2,24 @@ from rhinomcp.server import mcp
2
2
 
3
3
 
4
4
  @mcp.prompt()
5
- def asset_creation_strategy() -> str:
5
+ def asset_general_strategy() -> str:
6
6
  """Defines the preferred strategy for creating assets in Rhino"""
7
- return """When creating 3D content in Rhino, always start by checking if integrations are available:
7
+ return """
8
+
9
+ QUERY STRATEGY:
10
+ - if the id of the object is known, use the id to query the object.
11
+ - if the id is not known, use the name of the object to query the object.
8
12
 
9
- 0. Before anything, always check the document from get_document_info()
10
- 1. Please ALWAYS try to create the objects using the tool execute_rhinoscript_python_code() first.
13
+
14
+ CREATION STRATEGY:
15
+
16
+ 0. Before anything, always check the document from get_document_info().
17
+ 1. If the execute_rhinoscript_python_code() function is not able to create the objects, use the create_objects() function.
11
18
  2. If there are multiple objects, use the method create_objects() to create multiple objects at once. Do not attempt to create them one by one if they are more than 10.
12
19
  3. When including an object into document, ALWAYS make sure that the name of the object is meanful.
13
- 4. Try to include as many objects as possible accurately and efficiently. If the command is not able to include
14
- so many data, try to create the objects in batches.
20
+ 4. Try to include as many objects as possible accurately and efficiently. If the command is not able to include so many data, try to create the objects in batches.
15
21
 
16
22
  When creating rhinoscript python code:
17
23
  - do not hallucinate, only use the syntax that is supported by rhinoscriptsyntax or Rhino,Geometry.
18
- - document the code that you are writing.
19
- - when creating objects, ALWAYS make sure that the name of the object is meanful.
20
24
  - double check the code if any of the code is not correct, and fix it.
21
25
  """
@@ -0,0 +1,59 @@
1
+ import mcp.types as types
2
+ from rhinomcp.server import mcp
3
+ from pydantic import FileUrl
4
+
5
+
6
+ import os
7
+ from pathlib import Path
8
+
9
+ # Define path to static folder
10
+ STATIC_FOLDER = Path("./static")
11
+
12
+
13
+ @mcp.tool()
14
+ def get_rhinoscriptsyntax_resource(category: str) -> str:
15
+ """
16
+ Return the RhinoScriptsyntax for a specific category.
17
+
18
+ Parameters:
19
+ - category: The category of the RhinoScriptsyntax to get.
20
+
21
+ The following categories are available:
22
+ - application
23
+ - block
24
+ - compat
25
+ - curve
26
+ - dimension
27
+ - document
28
+ - geometry
29
+ - grips
30
+ - group
31
+ - hatch
32
+ - layer
33
+ - light
34
+ - line
35
+ - linetype
36
+ - material
37
+ - mesh
38
+ - object
39
+ - plane
40
+ - pointvector
41
+ - selection
42
+ - surface
43
+ - toolbar
44
+ - transformation
45
+ - userdata
46
+ - userinterface
47
+ - utility
48
+ - view
49
+ """
50
+
51
+ for file_path in STATIC_FOLDER.glob("*.py"):
52
+ if file_path.name == f"{category}.py":
53
+ try:
54
+ with open(file_path, "r", encoding="utf-8") as f:
55
+ return f.read()
56
+ except Exception as e:
57
+ print(f"Error reading {file_path}: {e}")
58
+
59
+
@@ -18,7 +18,7 @@ def create_object(
18
18
  Create a new object in the Rhino document.
19
19
 
20
20
  Parameters:
21
- - type: Object type ("BOX", "SPHERE")
21
+ - type: Object type ("POINT", "LINE", "POLYLINE", "CURVE", "BOX", "SPHERE")
22
22
  - name: Optional name for the object
23
23
  - color: Optional [r, g, b] color values (0-255) for the object
24
24
  - params: Type-specific parameters dictionary (see documentation for each type)
@@ -27,48 +27,60 @@ def create_object(
27
27
  - scale: Optional [x, y, z] scale factors
28
28
 
29
29
  The params dictionary is type-specific.
30
+ For POINT, the params dictionary should contain the following keys:
31
+ - x: x coordinate of the point
32
+ - y: y coordinate of the point
33
+ - z: z coordinate of the point
34
+
35
+ For LINE, the params dictionary should contain the following keys:
36
+ - start: [x, y, z] start point of the line
37
+ - end: [x, y, z] end point of the line
38
+
39
+ For POLYLINE, the params dictionary should contain the following keys:
40
+ - points: List of [x, y, z] points that define the polyline
41
+
42
+ For CURVE, the params dictionary should contain the following keys:
43
+ - points: List of [x, y, z] control points that define the curve
44
+ - degree: Degree of the curve (default is 3, if user asked for smoother curve, degree can be higher)
45
+ If the curve is closed, the first and last points should be the same.
46
+
30
47
  For BOX, the params dictionary should contain the following keys:
31
48
  - width: Width of the box along X axis of the object
32
49
  - length: Length of the box along Y axis of the object
33
50
  - height: Height of the box along Z axis of the object
51
+
52
+ For SPHERE, the params dictionary should contain the following key:
53
+ - radius: Radius of the sphere
34
54
 
35
55
  Returns:
36
56
  A message indicating the created object name.
37
57
 
38
58
  Examples of params:
59
+ - POINT: {"x": 0, "y": 0, "z": 0}
60
+ - LINE: {"start": [0, 0, 0], "end": [1, 1, 1]}
61
+ - POLYLINE: {"points": [[0, 0, 0], [1, 1, 1], [2, 2, 2]]}
62
+ - CURVE: {"points": [[0, 0, 0], [1, 1, 1], [2, 2, 2]], "degree": 3}
39
63
  - BOX: {"width": 1.0, "length": 1.0, "height": 1.0}
40
64
  - SPHERE: {"radius": 1.0}
41
65
  """
42
66
  try:
43
67
  # Get the global connection
44
68
  rhino = get_rhino_connection()
45
- # Set default values for missing parameters
46
- trans = translation or [0, 0, 0]
47
- rot = rotation or [0, 0, 0]
48
- sc = scale or [1, 1, 1]
49
-
69
+
50
70
  command_params = {
51
71
  "type": type,
52
- "translation": trans,
53
- "rotation": rot,
54
- "scale": sc
72
+ "params": params
55
73
  }
56
74
 
75
+ if translation is not None: command_params["translation"] = translation
76
+ if rotation is not None: command_params["rotation"] = rotation
77
+ if scale is not None: command_params["scale"] = scale
78
+
57
79
  if name: command_params["name"] = name
58
80
  if color: command_params["color"] = color
59
81
 
60
82
  # Create the object
61
- result = {}
62
- if (type == "BOX"):
63
- command_params["width"] = params["width"]
64
- command_params["length"] = params["length"]
65
- command_params["height"] = params["height"]
66
- result = rhino.send_command("create_object", command_params)
67
- elif (type == "SPHERE"):
68
- result = rhino.send_command("create_object", command_params)
69
- # elif (type == "CYLINDER"):
70
- # result = rhino.send_command("create_cylinder", command_params)
71
-
83
+ result = result = rhino.send_command("create_object", command_params)
72
84
 
73
85
  return f"Created {type} object: {result['name']}"
74
86
  except Exception as e:
@@ -15,11 +15,11 @@ def create_objects(
15
15
  Parameters:
16
16
  - objects: A list of dictionaries, each containing the parameters for a single object
17
17
 
18
- Each object should have the following keys:
19
- - type: Object type ("BOX")
18
+ Each object should have the following values:
19
+ - type: Object type ("POINT", "LINE", "POLYLINE", "BOX", "SPHERE", etc.)
20
20
  - name: Optional name for the object
21
21
  - color: Optional [r, g, b] color values (0-255) for the object
22
- - params: Type-specific parameters dictionary (see documentation for each type)
22
+ - params: Type-specific parameters dictionary (see documentation for each type in create_object() function)
23
23
  - translation: Optional [x, y, z] translation vector
24
24
  - rotation: Optional [x, y, z] rotation in radians
25
25
  - scale: Optional [x, y, z] scale factors
@@ -29,6 +29,26 @@ def create_objects(
29
29
 
30
30
  Examples of params:
31
31
  [
32
+ {
33
+ "type": "POINT",
34
+ "name": "Point 1",
35
+ "params": {"x": 0, "y": 0, "z": 0}
36
+ },
37
+ {
38
+ "type": "LINE",
39
+ "name": "Line 1",
40
+ "params": {"start": [0, 0, 0], "end": [1, 1, 1]}
41
+ },
42
+ {
43
+ "type": "POLYLINE",
44
+ "name": "Polyline 1",
45
+ "params": {"points": [[0, 0, 0], [1, 1, 1], [2, 2, 2]]}
46
+ },
47
+ {
48
+ "type": "CURVE",
49
+ "name": "Curve 1",
50
+ "params": {"points": [[0, 0, 0], [1, 1, 1], [2, 2, 2]], "degree": 3}
51
+ },
32
52
  {
33
53
  "type": "BOX",
34
54
  "name": "Box 1",
@@ -37,6 +57,15 @@ def create_objects(
37
57
  "translation": [0, 0, 0],
38
58
  "rotation": [0, 0, 0],
39
59
  "scale": [1, 1, 1]
60
+ },
61
+ {
62
+ "type": "SPHERE",
63
+ "name": "Sphere 1",
64
+ "color": [0, 255, 0],
65
+ "params": {"radius": 1.0},
66
+ "translation": [0, 0, 0],
67
+ "rotation": [0, 0, 0],
68
+ "scale": [1, 1, 1]
40
69
  }
41
70
  ]
42
71
  """
@@ -6,7 +6,7 @@ from typing import Any, List, Dict
6
6
 
7
7
 
8
8
  @mcp.tool()
9
- def delete_object(ctx: Context, id: str = None, name: str = None) -> str:
9
+ def delete_object(ctx: Context, id: str = None, name: str = None, all: bool = None) -> str:
10
10
  """
11
11
  Delete an object from the Rhino document.
12
12
 
@@ -17,8 +17,17 @@ def delete_object(ctx: Context, id: str = None, name: str = None) -> str:
17
17
  try:
18
18
  # Get the global connection
19
19
  rhino = get_rhino_connection()
20
+
21
+ commandParams = {}
22
+ if id is not None:
23
+ commandParams["id"] = id
24
+ if name is not None:
25
+ commandParams["name"] = name
26
+ if all:
27
+ commandParams["all"] = all
20
28
 
21
- result = rhino.send_command("delete_object", {"id": id, "name": name})
29
+ result = rhino.send_command("delete_object", commandParams)
30
+
22
31
  return f"Deleted object: {result['name']}"
23
32
  except Exception as e:
24
33
  logger.error(f"Error deleting object: {str(e)}")
@@ -0,0 +1,45 @@
1
+ from mcp.server.fastmcp import Context
2
+ import json
3
+ from rhinomcp.server import get_rhino_connection, mcp, logger
4
+ from typing import Any, List, Dict
5
+
6
+
7
+ @mcp.tool()
8
+ def modify_objects(
9
+ ctx: Context,
10
+ objects: List[Dict[str, Any]],
11
+ all: bool = None
12
+ ) -> str:
13
+ """
14
+ Create multiple objects at once in the Rhino document.
15
+
16
+ Parameters:
17
+ - objects: A List of objects, each containing the parameters for a single object modification
18
+ - all: Optional boolean to modify all objects, if true, only one object is required in the objects dictionary
19
+
20
+ Each object can have the following parameters:
21
+ - id: The id of the object to modify
22
+ - new_color: Optional [r, g, b] color values (0-255) for the object
23
+ - translation: Optional [x, y, z] translation vector
24
+ - rotation: Optional [x, y, z] rotation in radians
25
+ - scale: Optional [x, y, z] scale factors
26
+ - visible: Optional boolean to set visibility
27
+
28
+ Returns:
29
+ A message indicating the modified objects.
30
+ """
31
+ try:
32
+ # Get the global connection
33
+ rhino = get_rhino_connection()
34
+ command_params = {}
35
+ command_params["objects"] = objects
36
+ if all:
37
+ command_params["all"] = all
38
+ result = rhino.send_command("modify_objects", command_params)
39
+
40
+
41
+ return f"Modified {result['modified']} objects"
42
+ except Exception as e:
43
+ logger.error(f"Error modifying objects: {str(e)}")
44
+ return f"Error modifying objects: {str(e)}"
45
+
@@ -0,0 +1,53 @@
1
+ from mcp.server.fastmcp import Context
2
+ import json
3
+ from rhinomcp.server import get_rhino_connection, mcp, logger
4
+ from typing import Any, List, Dict
5
+
6
+
7
+ @mcp.tool()
8
+ def select_objects(
9
+ ctx: Context,
10
+ filters: Dict[str, Any] = {},
11
+ filters_type: str = "and",
12
+ ) -> str:
13
+ """
14
+ Select objects in the Rhino document.
15
+
16
+ Parameters:
17
+ - filters: A dictionary containing the filters. The filters parameter is necessary, unless it's empty, in which case all objects will be selected.
18
+ - filters_type: The type of the filters, it's "and" or "or", default is "and"
19
+
20
+ The filters dictionary can contain the following keys:
21
+ - name: The name of the object
22
+ - color: The color of the object, for example [255, 0, 0]
23
+
24
+ Additionaly, rhino allows to have user custom attributes, which can be used to filters the objects.
25
+ For example, if the object has a user custom attribute called "category", the filters dictionary can contain:
26
+ - category: custom_attribute_value
27
+
28
+ Example:
29
+ filters = {
30
+ "name": "object_name",
31
+ "category": "custom_attribute_value"
32
+ },
33
+ filters_type = "or"
34
+
35
+
36
+ Returns:
37
+ A number indicating the number of objects that have been selected.
38
+ """
39
+ try:
40
+ # Get the global connection
41
+ rhino = get_rhino_connection()
42
+ command_params = {
43
+ "filters": filters,
44
+ "filters_type": filters_type
45
+ }
46
+
47
+ result = rhino.send_command("select_objects", command_params)
48
+
49
+ return f"Selected {result['count']} objects"
50
+ except Exception as e:
51
+ logger.error(f"Error selecting objects: {str(e)}")
52
+ return f"Error selecting objects: {str(e)}"
53
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rhinomcp
3
- Version: 0.1.1.3
3
+ Version: 0.1.2.0
4
4
  Summary: Rhino integration through the Model Context Protocol
5
5
  Author-email: Jingcheng Chen <mail@jchen.ch>
6
6
  License: MIT
@@ -0,0 +1,19 @@
1
+ rhinomcp/__init__.py,sha256=FiyVi0Ee7Vc0HVEfcUyEwHeHfBVP8siY-eCC5e7xLE0,909
2
+ rhinomcp/server.py,sha256=G4ESexAfPZOCzIVYCbg51aMnJa-Zw6aOtZm1w2_6Ogc,9499
3
+ rhinomcp/prompts/assert_general_strategy.py,sha256=Aovach0WYClUw191iX_Mwyh2KlxdVp0gB2Wt4eiQDvM,1250
4
+ rhinomcp/resources/rhinoscriptsyntax_resource.py,sha256=3XtpQVlKd5jJL_YrX0tw4ZT3qUR6bO1rLdsoVZ1BXv8,1166
5
+ rhinomcp/tools/create_object.py,sha256=uO5EhuM7SO9eq9senvskdiblZsWmveHHQxce9pMW7-g,3333
6
+ rhinomcp/tools/create_objects.py,sha256=974VI3C_iLjz9nJ6ya0fwxbsI0u0rlyb_cM98W6T86U,2616
7
+ rhinomcp/tools/delete_object.py,sha256=-Vz1AZlw0-hPQZ9wNVTpa5sRDJ2qLiDnfjSYKp2wafc,987
8
+ rhinomcp/tools/execute_rhinoscript_python_code.py,sha256=7bveKWTxTJ8_9Gcelied4dEQjyd2WeNV-4iTL1i-prs,1837
9
+ rhinomcp/tools/get_document_info.py,sha256=poPyqfO0KeV5Au3jks9Q3o6tTZVDfEuCm9BZWCLfpqY,613
10
+ rhinomcp/tools/get_object_info.py,sha256=mqsnkVzYHMnv9CPA7DX1dyj5z538WEsIVWu9yI6DChM,967
11
+ rhinomcp/tools/get_selected_objects_info.py,sha256=73u2Y9l9O8rwboFwBcfGQFYuFBZBp1UkChNJkK2Rbjo,573
12
+ rhinomcp/tools/modify_object.py,sha256=OVQa75PAmuVx-YslxSC2ITdFbp6cCELVaacI77sJ7Zg,1912
13
+ rhinomcp/tools/modify_objects.py,sha256=52okeGwV5IQiuBSBH9HcyDCxWbCNF4eA7LoLuhLlgp4,1498
14
+ rhinomcp/tools/select_objects.py,sha256=7qciRHFYN5orpOMDiqETCW8bOJEG-K302vQgYjsAv60,1697
15
+ rhinomcp-0.1.2.0.dist-info/METADATA,sha256=nY0r8Lp9D3IVfhLHw7GAprAmmnCsUiO12q71DpHVSBs,920
16
+ rhinomcp-0.1.2.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
17
+ rhinomcp-0.1.2.0.dist-info/entry_points.txt,sha256=OserOidtKWCl-_h3O1c2e9La6wYmJ9rE5F_T5wRLX9w,50
18
+ rhinomcp-0.1.2.0.dist-info/top_level.txt,sha256=sw73qoWC7GQp5upujkME6pRWc8OxBydEeDwQqu-qv4U,9
19
+ rhinomcp-0.1.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.0.2)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,10 +0,0 @@
1
- from rhinomcp.server import mcp
2
-
3
-
4
- @mcp.prompt()
5
- def assert_query_strategy() -> str:
6
- """Defines the preferred strategy for querying Object or Objects in Rhino"""
7
- return """When querying Object or Objects in Rhino:
8
- - if the id of the object is known, use the id to query the object.
9
- - if the id is not known, use the name of the object to query the object.
10
- """
@@ -1,17 +0,0 @@
1
- rhinomcp/__init__.py,sha256=pMvTrNAVPMY408zklG_Cln9YsIH4_yCT52aS4JIXNy4,797
2
- rhinomcp/server.py,sha256=G4ESexAfPZOCzIVYCbg51aMnJa-Zw6aOtZm1w2_6Ogc,9499
3
- rhinomcp/prompts/assert_creation_strategy.py,sha256=KryUyOnDZAPK9Syr31hkStCFsqJIRJRI2lkToK03aeo,1255
4
- rhinomcp/prompts/assert_query_strategy.py,sha256=fFOZFv6zUE-tw6HaTBIhM5A96zeBpinN1tYKwbz0C1o,379
5
- rhinomcp/tools/create_object.py,sha256=O-jfh28UoDulp3r9PJEEVS1B-L3adJzws0Z_wYXgEHw,2616
6
- rhinomcp/tools/create_objects.py,sha256=8iPTM8559J-9IQql2VGoem7CaqMIaylXmXk-FNRLv8A,1696
7
- rhinomcp/tools/delete_object.py,sha256=Opd2FInqZKIxlD8Qi4Q-OpfI7Y9aHWdYmNNjtA99xB4,762
8
- rhinomcp/tools/execute_rhinoscript_python_code.py,sha256=7bveKWTxTJ8_9Gcelied4dEQjyd2WeNV-4iTL1i-prs,1837
9
- rhinomcp/tools/get_document_info.py,sha256=poPyqfO0KeV5Au3jks9Q3o6tTZVDfEuCm9BZWCLfpqY,613
10
- rhinomcp/tools/get_object_info.py,sha256=mqsnkVzYHMnv9CPA7DX1dyj5z538WEsIVWu9yI6DChM,967
11
- rhinomcp/tools/get_selected_objects_info.py,sha256=73u2Y9l9O8rwboFwBcfGQFYuFBZBp1UkChNJkK2Rbjo,573
12
- rhinomcp/tools/modify_object.py,sha256=OVQa75PAmuVx-YslxSC2ITdFbp6cCELVaacI77sJ7Zg,1912
13
- rhinomcp-0.1.1.3.dist-info/METADATA,sha256=aYor-cdRbb5gs9qdJn7aj9PLvtxNG1MK5iKY0BYKXSE,920
14
- rhinomcp-0.1.1.3.dist-info/WHEEL,sha256=DK49LOLCYiurdXXOXwGJm6U4DkHkg4lcxjhqwRa0CP4,91
15
- rhinomcp-0.1.1.3.dist-info/entry_points.txt,sha256=OserOidtKWCl-_h3O1c2e9La6wYmJ9rE5F_T5wRLX9w,50
16
- rhinomcp-0.1.1.3.dist-info/top_level.txt,sha256=sw73qoWC7GQp5upujkME6pRWc8OxBydEeDwQqu-qv4U,9
17
- rhinomcp-0.1.1.3.dist-info/RECORD,,