MCP server for Lunar, a 3D geometry processing application. Exposes tools for discovering operators, querying world state, and executing geometric operations via the Model Context Protocol.
Lunar MCP exposes 6 tools with mixed quality. The three primary tools (discover, world_state, run) have reasonable descriptions and schemas, but lack critical clarity on parameter semantics and output structure. The three geometry operators (tf.concatenateMeshes, tf.splitIntoComponents, tf.splitIntoDomains) have minimal descriptions and incomplete input schemas. Parameter descriptions are sparse or missing type information. No error handling guidance, no output schema documentation, and no tool annotations (readOnlyHint/destructiveHint). Descriptions average ~100 chars but lack actionable context for LLM selection.
List available operators grouped by category. No params → compact catalog: { _guide, category: [{ id, l, n?, p? }] }. n = how many nodeIds to pass (omit=0, N=array, 0+=optional). p = param names. Pass operatorIds for full schemas. Pass categories for all in those groups.
Execute one or more operations. Each operation has operatorId, optional nodeIds, optional params. Call discover() to see available operators. Call discover({ operatorId }) for full schema + _example. Operations execute sequentially. Returns array of results.
Merge multiple meshes into one. Applies transformations and offsets face indices.
Split a mesh into separate meshes by per-face labels.
Decompose a non-manifold surface mesh (typically the output of Mesh Arrangements) into per-domain watertight outward-oriented submeshes. Runs clean → domainLabels → splitIntoDomains.
Get the current scene. Node IDs are what you pass in run operations. No params → compact list (id, label, type, visible, center) + summary. Pass nodeIds for full detail: properties (faces, vertices, AABB, OBB with center/axes/extent in world space), transform matrix, color, opacity, children.
Three geometry operators (tf.concatenateMeshes, tf.splitIntoComponents, tf.splitIntoDomains) lack proper input schema definitions. Parameters reference custom types ('mesh', 'ndarray') without JSON Schema type declarations, making them unparseable by LLMs.
Output schemas are not documented for any tool. LLMs cannot plan downstream calls or extract required fields (e.g., what does discover() return? what fields are in world_state results?). This violates the pattern:tool requirement.
No error handling guidance. Tools return errors but do not tell LLMs what to do next (retry? ask user? call a different tool?). Missing recovery-guide pattern.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 51 | <=2025-11-25 | v2 |
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). LLMs cannot determine which tools are safe to retry or have side effects. 'run' is clearly destructive but unmarked.
Parameter descriptions are vague or missing. 'operatorIds' in discover() lacks context on what happens when passed vs omitted. 'params' in run() is undocumented, what structure? what constraints? LLMs must guess.