Skip to main content
Glama
zinin

sketchup-mcp2

by zinin

create_finger_joint

Join two boards by creating a finger joint (box joint) with precise dimensions in millimeters.

Instructions

Create a finger joint (box joint) between two components. Dimensions in mm.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
board1_idYes
board2_idYes
widthNo
heightNo
depthNo
num_fingersNo
offset_xNo
offset_yNo
offset_zNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The `create_finger_joint` tool handler: a FastMCP tool annotated with @mcp.tool() that accepts board1_id, board2_id, width, height, depth, num_fingers, and offset_x/y/z, then delegates to the Ruby backend via _call(ctx, 'create_finger_joint', ...). This is the Python-side entry point that registers the tool and defines its schema via Pydantic/Annotated type hints.
    @mcp.tool()
    async def create_finger_joint(
        ctx: Context,
        board1_id: Annotated[str, Field(min_length=1)],
        board2_id: Annotated[str, Field(min_length=1)],
        width: Annotated[float, Field(gt=0)] = 50.0,
        height: Annotated[float, Field(gt=0)] = 25.0,
        depth: Annotated[float, Field(gt=0)] = 10.0,
        num_fingers: Annotated[int, Field(gt=0)] = 5,
        offset_x: float = 0.0,
        offset_y: float = 0.0,
        offset_z: float = 0.0,
    ) -> str:
        """Create a finger joint (box joint) between two components. Dimensions in mm."""
        return await _call(
            ctx,
            "create_finger_joint",
            board1_id=board1_id,
            board2_id=board2_id,
            width=width,
            height=height,
            depth=depth,
            num_fingers=num_fingers,
            offset_x=offset_x,
            offset_y=offset_y,
            offset_z=offset_z,
        )
  • Input schema for create_finger_joint: board1_id and board2_id (required strings with min_length=1), width (default 50.0, gt=0), height (default 25.0, gt=0), depth (default 10.0, gt=0), num_fingers (default 5, gt=0 int), and offset_x/y/z (default 0.0 floats). These Pydantic Field annotations define the JSON-serializable input contract exposed to the MCP client.
    async def create_finger_joint(
        ctx: Context,
        board1_id: Annotated[str, Field(min_length=1)],
        board2_id: Annotated[str, Field(min_length=1)],
        width: Annotated[float, Field(gt=0)] = 50.0,
        height: Annotated[float, Field(gt=0)] = 25.0,
        depth: Annotated[float, Field(gt=0)] = 10.0,
        num_fingers: Annotated[int, Field(gt=0)] = 5,
        offset_x: float = 0.0,
        offset_y: float = 0.0,
        offset_z: float = 0.0,
    ) -> str:
  • Registration via the @mcp.tool() decorator on line 190. The `mcp` FastMCP instance is created in app.py (line 41) and imported at line 14 of tools.py. The side-effect import in app.py line 51 (import sketchup_mcp.tools) ensures tools are registered when the MCP server starts.
    @mcp.tool()
  • The _call helper function that all tool handlers delegate to. It acquires a SketchUp connection via get_connection(), sends the command with its name and kwargs via send_command(name, kwargs), handles ConnectionError and SketchUpError, and unwraps the MCP-shaped response. This is the dispatch layer between Python handlers and the Ruby SketchUp extension.
    async def _call(ctx: Context, name: str, **kwargs) -> str:
        """Dispatch a tool call to SketchUp and shape the response for Claude.
    
        - Connection errors → human-readable string, server keeps running.
        - SketchUpError → ``format_error`` string.
        - Successful MCP-shaped result ({content: [{text: "..."}]}) → just the text.
        - Any other dict result → ``json.dumps``.
        """
        try:
            sketchup = await get_connection()
        except ConnectionError as e:
            return f"SketchUp not running or extension not started: {e}"
        try:
            result = await sketchup.send_command(name, kwargs)
        except ConnectionError as e:
            # Cached connection was stale and reconnect inside send_command failed:
            # `_connect_or_raise` re-raises OSError as ConnectionError before the
            # send/recv try-block, so it escapes past the SketchUpError handler.
            return f"SketchUp not running or extension not started: {e}"
        except SketchUpError as e:
            return format_error(e, debug=config.LOG_LEVEL == "DEBUG")
        content = result.get("content") if isinstance(result, dict) else None
        if (
            isinstance(content, list)
            and content
            and isinstance(content[0], dict)
            and "text" in content[0]
        ):
            return content[0]["text"]
        return json.dumps(result)
  • Test data for create_finger_joint: verifies that calling the Python wrapper with only board1_id='1' and board2_id='2' produces the correct Ruby call with default values (width=50.0, height=25.0, depth=10.0, num_fingers=5, offset_x/y/z=0.0). Ensures the mapping between Python wrapper and Ruby tool name is correct.
    ("create_finger_joint", {"board1_id": "1", "board2_id": "2"},
     "create_finger_joint", {"board1_id": "1", "board2_id": "2",
                              "width": 50.0, "height": 25.0, "depth": 10.0,
                              "num_fingers": 5,
                              "offset_x": 0.0, "offset_y": 0.0, "offset_z": 0.0}),
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It only states the operation and that dimensions are in mm, but does not disclose whether the operation is destructive, reversible, or what side effects occur (e.g., modifies components). The agent cannot infer behavioral traits beyond the basic action.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences that are front-loaded and free of fluff. However, the extreme brevity sacrifices necessary detail. Still, it earns a 4 for efficiency.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (9 parameters, 2 required) and no annotation support, the description is too sparse. It does not mention what the tool returns (though an output schema exists), prerequisites, or typical use cases. The agent lacks enough context to use the tool correctly without additional documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description adds no meaning to the 9 parameters. It only states 'Dimensions in mm' without linking to specific parameters like width, height, depth, or offsets. The agent must infer parameter roles from names alone, which is insufficient for correct invocation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the tool creates a finger joint (box joint) between two components, clearly identifying the verb and resource. The mention of 'finger joint (box joint)' distinguishes it from sibling tools like create_dovetail and create_mortise_tenon.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool vs alternatives (e.g., dovetail or mortise-tenon). It does not mention prerequisites such as that board1_id and board2_id must refer to existing components, or any best practices for dimension inputs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zinin/sketchup-mcp2'

If you have feedback or need assistance with the MCP directory API, please join our Discord server