Tools for agents: Mesh transform and OBJ export

Transform mesh geometry with a 4×4 affine matrix and get bounds, centroid, and a ready-to-save OBJ artifact.

Connect with MCP

{
  "mcpServers": {
    "super-agent-tools": {
      "url": "https://app.getsupers.com/sites/agent-mesh-transform/mcp"
    }
  }
}
Streamable HTTP · No API key · Stateless

Use this URL in any client supporting remote Streamable HTTP MCP. Calls return structured JSON; inputs are processed without persistence.

Call transform_mesh

Row-major matrix multiplied by column vectors [x,y,z,1]. Input faces are zero-based; OBJ faces are one-based. Face winding is preserved, including under reflections. Normals and materials are not included.

Input and output schemas
{
  "name": "transform_mesh",
  "title": "Mesh transform and OBJ export",
  "description": "Apply a row-major 4x4 affine matrix to vertices and export OBJ, bounds and centroid. Face indices are zero-based. No filesystem or network access.",
  "inputSchema": {
    "$defs": {
      "Mesh": {
        "properties": {
          "vertices": {
            "items": {
              "maxItems": 3,
              "minItems": 3,
              "prefixItems": [
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                }
              ],
              "type": "array"
            },
            "minItems": 1,
            "title": "Vertices",
            "type": "array"
          },
          "faces": {
            "items": {
              "items": {
                "type": "integer"
              },
              "type": "array"
            },
            "title": "Faces",
            "type": "array"
          }
        },
        "required": [
          "vertices"
        ],
        "title": "Mesh",
        "type": "object"
      }
    },
    "properties": {
      "mesh": {
        "$ref": "#/$defs/Mesh"
      },
      "matrix": {
        "items": {
          "items": {
            "type": "number"
          },
          "type": "array"
        },
        "title": "Matrix",
        "type": "array"
      }
    },
    "required": [
      "mesh",
      "matrix"
    ],
    "title": "transform_meshArguments",
    "type": "object"
  },
  "outputSchema": {
    "additionalProperties": true,
    "title": "transform_meshDictOutput",
    "type": "object"
  },
  "icons": null,
  "annotations": {
    "title": null,
    "readOnlyHint": true,
    "destructiveHint": false,
    "idempotentHint": true,
    "openWorldHint": false
  },
  "meta": null,
  "execution": null
}

Run the example to see the actual result.

HTTP alternative

POST https://app.getsupers.com/sites/agent-mesh-transform/call
Content-Type: application/json

{
  "mesh": {
    "vertices": [
      [
        0,
        0,
        0
      ],
      [
        1,
        0,
        0
      ],
      [
        0,
        1,
        0
      ]
    ],
    "faces": [
      [
        0,
        1,
        2
      ]
    ]
  },
  "matrix": [
    [
      2,
      0,
      0,
      10
    ],
    [
      0,
      2,
      0,
      0
    ],
    [
      0,
      0,
      2,
      0
    ],
    [
      0,
      0,
      0,
      1
    ]
  ]
}

The HTTP and MCP interfaces execute the same implementation. Validation errors are returned explicitly. See the tool notes above for its supported inputs and behavior.

Affine mesh coordinates and an OBJ design example

Read the explanation

The displayed triangle begins at zero zero zero, one zero zero, and zero one zero. The row-major affine matrix doubles each spatial coordinate and translates x by ten. The transformed vertices are ten zero zero, twelve zero zero, and ten two zero. At twenty pixels per x coordinate the first two transformed x bars span two hundred and two hundred forty. Translation uses the fourth homogeneous input coordinate one. This explains the documented example. The offline copy cannot load its absolute shared app script, and we make no HTTP or MCP request, so the actual transform response and file delivery remain unverified. Before the transform the triangle has x bounds zero through one. After scaling by two and shifting by ten, its x bounds are ten through twelve. The span doubles from one to two rather than growing to twelve. At one hundred pixels per span unit the bars grow from one hundred to two hundred. The transformed vertex-average center is x thirty two thirds, y two thirds, z zero. For this single triangle it also equals the surface centroid. For general meshes a vertex-average and an area-weighted centroid can differ; inspect the implementation contract rather than inferring its centroid definition from one example. The documented input face uses zero-based indices zero, one, and two. The matching OBJ face is written f one two three because OBJ indices are one-based. At sixty pixels per first index the input bar is zero and the OBJ bar sixty. The vertices must be written in corresponding order; changing the index convention does not create new geometry or change triangle winding. The page describes a ready-to-save OBJ artifact, but no successful local submission or downloaded OBJ is claimed in this offline draft. Argument editing and preserved layout can be checked separately from backend correctness and public publication.

Mesh Transform and OBJ Export Guide

How does transform_mesh evaluate 4×4 affine matrices, calculate mesh bounds and centroids, and format geometry into Wavefront OBJ lines?

The transform_mesh tool maps 3D coordinate arrays through a 4×4 affine transformation matrix by multiplying each vertex as a homogeneous column vector [x, y, z, 1] against the first three matrix rows. The script computes axis-aligned bounding extremes across transformed coordinates, derives an unweighted arithmetic mean of the vertices as the centroid, and emits a Wavefront OBJ string where geometric vertex lines use the 'v' tag and 0-based face indices are incremented by one to match the 1-based Wavefront OBJ specification.

The tool strictly enforces affine transforms by requiring the final row of the matrix to equal [0, 0, 0, 1]; perspective projections or projective transformations are rejected. The centroid output is an unweighted mean of unique vertex positions rather than an area-weighted surface centroid or volumetric center of mass. In addition, the transformation copies polygon face vertex indices directly without inverting winding when the transformation matrix determinant is negative, and it does not transform vertex normals or texture coordinates.

Try a worked example

In the JSON arguments textarea, the preset defines a triangle at (0,0,0), (1,0,0), and (0,1,0) subjected to a 2× uniform scale and a 10-unit translation along the x-axis. Clicking 'Run tool' submits this payload to the endpoint, which updates the live status line above the structured result area to 'Running…'. Under live evaluation, the transformed vertices evaluate to (10,0,0), (12,0,0), and (10,2,0) with bounds min [10,0,0], max [12,2,0], centroid [10.666666666666666, 0.6666666666666666, 0.0], and the 0-based face [0, 1, 2] formatted as 'f 1 2 3' in the OBJ text.

Wavefront OBJ 1-Based Indexing

The Wavefront OBJ geometry format defines polygon face elements with the 'f' keyword followed by 1-based indices corresponding to the order of geometric 'v' vertex records in the file. Library of Congress: Wavefront OBJ File Format

Because Python data structures and standard graphics pipelines commonly store vertex arrays with 0-based indices, the backend transform function increments every integer in mesh.faces by 1 when generating the ASCII OBJ string.

Affine Geometry and Transformation Logic

The implementation computes transformed vertex coordinates using row-major dot products: for each row i from 0 to 2, new_x_i is the sum of matrix[i][j] multiplied by [x, y, z, 1][j]. The fourth row is validated to be exactly [0, 0, 0, 1], guaranteeing that the transformation remains strictly affine without non-linear perspective divisions.

The exported bounds represent the coordinate-wise minima and maxima along each cartesian axis. The centroid is calculated by summing the vertex positions along each axis and dividing by the total vertex count, which reflects the point cloud arithmetic average rather than a surface or mass distribution centroid.

Sources and further reading