{"name":"cad.mino.mobi","version":"1","title":"Feature-tree CAD","protocolVersion":"2025-06-18","transport":"streamable-http (JSON responses)","endpoint":"https://cad.mino.mobi/mcp","skill":"https://cad.mino.mobi/SKILL.md","index":"https://cad.mino.mobi/llms.txt","changelog":"https://cad.mino.mobi/CHANGELOG.md","capabilities":{"manifold":false,"maxParts":3,"budgetMs":null,"workBudget":6000000},"tools":[{"name":"check","title":"Resolve a tree","description":"Evaluate the expressions, sketches and ops of a tree without building geometry. Returns params, sketch and op counts, or the first error with its op id. On an assembly: its params and derived at t = 0, every placement expression, and each distinct part. Cheap; run it after every edit.","inputSchema":{"type":"object","properties":{"tree":{"oneOf":[{"type":"object","description":"A feature tree (see cad.mino.mobi/README.md), or an assembly with `components`. Strings `bench:<name>` and `at://…` are accepted in place of the object."},{"type":"string","description":"`bench:<name>` or an `at://` URI"}]}},"required":["tree"]}},{"name":"build","title":"Build a part or assembly","description":"Exact build with the Truck kernel: volume, area, bbox, centroid, Euler characteristic, watertightness, and every named face with its geometry (plane or cylinder). For an assembly: the component list, every distinct part key, and the parts built in this call — a server builds at most a few parts per call (a gear can take 20 s), so pass `parts` (part keys from `partKeys`) to build the rest, and `remaining` tells you which are left. Returns a link that opens the same document in the viewer. `ok` means what `agent/build.mjs`'s exit code means: built AND watertight — a leaky solid comes back `ok: false` with `built: true` and the open-edge count, because its volume cannot be trusted and it will not print or export cleanly. The preview kernel is not available on this server.","inputSchema":{"type":"object","properties":{"tree":{"oneOf":[{"type":"object","description":"A feature tree (see cad.mino.mobi/README.md), or an assembly with `components`. Strings `bench:<name>` and `at://…` are accepted in place of the object."},{"type":"string","description":"`bench:<name>` or an `at://` URI"}]},"faces":{"type":"boolean","default":true,"description":"include the face list"},"parts":{"type":"array","items":{"type":"string"},"description":"assemblies only: the part keys to build in this call (default: the first few)"}},"required":["tree"]}},{"name":"measure","title":"Measure named faces","description":"One face: its geometry (a cylinder's diameter and axis, a plane's normal). Two faces: plane-to-plane, axis-to-axis (with both diameters and the wall between) or axis-to-plane distance, from exact geometry. Face names come from `build`. On an assembly, name faces as `component.face` and pass `t` to pose it first: the distance between two parts' faces at an instant, which tests the kinematics directly.","inputSchema":{"type":"object","properties":{"tree":{"oneOf":[{"type":"object","description":"A feature tree (see cad.mino.mobi/README.md), or an assembly with `components`. Strings `bench:<name>` and `at://…` are accepted in place of the object."},{"type":"string","description":"`bench:<name>` or an `at://` URI"}]},"a":{"type":"string","description":"a face name, e.g. plate.pivot[0][0]"},"b":{"type":"string"},"t":{"type":"number","description":"seconds through the drive, for an assembly"}},"required":["tree","a"]}},{"name":"mechanism","title":"What a mechanism does: ratios, advantage, effort, dead points","description":"What the mechanism DOES, by virtual work — the question `interference` cannot answer. The poser is differenced against each input, so every velocity ratio in the assembly falls out, and the MECHANICAL ADVANTAGE is the reciprocal of a ratio: a jaw moving 0.36 mm per mm of nut travel multiplies the thrust by 2.8. Per input it returns what moves and how fast, the advantage, the travel and turn end to end (read from the two end poses, so an impulsive motion like an escapement is not under-resolved by sampling), what stays still, and DEAD POINTS — a rate passing through zero, where the mechanism self-locks and the advantage is infinite. `loads` gives the EFFORT at the input that holds them: `{component, force: [fx,fy,fz]}` in newtons or `{component, torque}` in N·m about the part's own turn, answered in newtons for an input in mm, newton-metres for one in degrees, watts for a drive. It is LOSSLESS — friction is not modelled — so it is a floor, not the answer; and it is the whole effort, not the useful part of it (taking F·lead/2π off a screw as \"useful work\" under-sizes a brake by a quarter). `span: [a, b]` is the distance between two components and its rate, at the state asked about AND at its worst over the whole input — `invariant: true` means the rate is zero EVERYWHERE on it, and a rate reading zero at one state may only be a dead point: an invariant of the mechanism is that rate reading zero (\"the link is a link\", \"rolling does not change the grip\"), which is otherwise a hundred lines of hand-written oracle. `point` differentiates one point in a part's own coordinates, so a hand pinned at its boss reads zero at the origin and r·ω at its tip. `of` returns the advantage curve of one component through the whole input. It builds NO geometry and runs no kernel — two poses per rate — so it is cheap here and has no budget, unless the document places a component by a `@comp.face` reference, which needs that part built once. A document with neither `inputs` nor a `drive` has no degree of freedom and is refused.","inputSchema":{"type":"object","properties":{"assembly":{"oneOf":[{"type":"object","description":"A feature tree (see cad.mino.mobi/README.md), or an assembly with `components`. Strings `bench:<name>` and `at://…` are accepted in place of the object."},{"type":"string","description":"`bench:<name>` or an `at://` URI"}]},"input":{"type":"string","description":"one declared input, or `t` for the drive; default every axis the document has"},"at":{"type":"object","additionalProperties":{"type":"number"},"description":"the values of the OTHER inputs while this one is differentiated; defaults to each input's `default`"},"t":{"type":"number","default":0,"description":"seconds through the drive, when differentiating against an input rather than time"},"steps":{"type":"integer","description":"states across the input (default its own `steps`)"},"of":{"type":"string","description":"a component id: return its advantage curve through the whole input"},"span":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":2,"description":"two component ids: their distance and its rate — zero is an invariant"},"point":{"type":"object","properties":{"component":{"type":"string"},"local":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3}},"required":["component"],"description":"a point in a part's own coordinates, differentiated"},"loads":{"type":"array","items":{"type":"object","properties":{"component":{"type":"string"},"force":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3,"description":"newtons, in world axes"},"torque":{"type":"number","description":"N·m about the part's own turn"}},"required":["component"]},"description":"the effort at the input that holds these"}},"required":["assembly"]}},{"name":"interference","title":"Check an assembly for interference and clearance","description":"Pose every component of an assembly at time t (seconds through its drive) and test every pair. With the preview kernel, pairs with more than eps mm³ in common are returned with their shared volume. Everywhere (this server included), pass `clearance` in mm to get the nearest approach of every pair from the exact meshes instead — crossing, contained, touching, or the distance — and a verdict per pair: collision (depth or containment, including a mated touch past its budget), close (under the clearance), loose (wider than a designed fit), expected (a mated touch), fit (a designed clearance, from the document's `fits`), contact (touching, no depth, no clearance demanded), clear. A fixed or screw mate means bolted, not \"may be the same solid\": an expected touch may share up to 1 mm³ (or a thousandth of the smaller part) and go 0.1 mm deep, and a real press fit raises its own budget with `fits: [{a, b, contact: true, interfere: {max, depth}}]`. `ok` says nothing bad was found IN WHAT WAS SAMPLED; `done` says the sweep finished — they are separate, so a windowed run with nothing wrong in it says ok: true, done: false. Every answer carries `cost`: what one instant of this assembly costs in triangle-pairs, this server's budget, how many instants that buys, and an estimate at the other resolutions, so `res` can be chosen without probing for the cliff. With sweep N, N instants over one period of the drive (or `period` seconds) are checked and each pair's worst kept; with `grid: true` (or a number of steps), every combination of the document's `inputs` is checked instead — which is the instrument for a document with more than one input, where there is no period, and where a path through the inputs would say nothing about the corners it misses; in clearance mode the minimum is then chased between samples for the pairs near the clearance, so a graze between instants is found. Reference components are left out. A big assembly does not fit in one request here. New part meshes are built a few per call and cached, so repeating the call gets further (`incomplete: \"parts\"` says what is left); a sweep that does not fit answers `done: false` with `next` — call again with `from: next` until `done`, then take the smallest distance per pair across the windows; and an assembly whose single instant is past the server's budget is refused with its numbers (`incomplete: \"too-big\"`) rather than killed — try `res` 128 or 64, or run it locally. Big gears take ~30 s each to build; sweeping a large assembly locally with agent/check.mjs is still faster.","inputSchema":{"type":"object","properties":{"assembly":{"oneOf":[{"type":"object","description":"A feature tree (see cad.mino.mobi/README.md), or an assembly with `components`. Strings `bench:<name>` and `at://…` are accepted in place of the object."},{"type":"string","description":"`bench:<name>` or an `at://` URI"}]},"t":{"type":"number","default":0},"eps":{"type":"number","default":0.01},"clearance":{"type":"number","description":"mm: report every pair's nearest approach and flag those closer than this (0 flags only contact); this mode needs no kernel"},"sweep":{"type":"integer","description":"check this many instants over one period instead of one time t"},"grid":{"description":"check every combination of the document's `inputs` instead of a period: true for each input's own `steps`, or a number to use that many points per input. Windows against the budget like a sweep (`from`, `next`)."},"period":{"type":"number","description":"seconds per cycle for a sweep; default one turn of the driven component"},"from":{"type":"integer","default":0,"description":"clearance sweeps only: the first instant of this window. A server stops on its CPU budget and answers with `next`; pass that back as `from` to continue, and take the smallest distance per pair across the windows."},"res":{"type":"integer","enum":[64,128,256],"default":256,"description":"clearance mode: mesh resolution. 256 is the default (chord error 0.0025 mm); 64 or 128 is coarser and much cheaper, for an assembly this server refuses at 256"},"budgetMs":{"type":"integer","description":"local hosts only: stop after about this many ms (a Worker's clock does not run during synchronous work, so the server budgets by work instead)"}},"required":["assembly"]}},{"name":"drawing","title":"Draw a part or assembly","description":"An engineering drawing as SVG from the exact mesh: third-angle views (front, top, right by default; any of front, back, top, bottom, left, right, iso), hidden lines dashed, the overall width, height and depth dimensioned, and every cylindrical hole called out with its count, diameter and depth when blind. On an assembly, pass `t` to pose it; reference components are left out. Returns the SVG as an embedded resource plus the numbers on it (overall size, dimensions, holes, lines per view). Deterministic, so two drawings of the same tree diff cleanly.","inputSchema":{"type":"object","properties":{"tree":{"oneOf":[{"type":"object","description":"A feature tree (see cad.mino.mobi/README.md), or an assembly with `components`. Strings `bench:<name>` and `at://…` are accepted in place of the object."},{"type":"string","description":"`bench:<name>` or an `at://` URI"}]},"views":{"type":"array","items":{"type":"string","enum":["front","back","top","bottom","left","right","iso"]},"default":["front","top","right"]},"hidden":{"type":"boolean","default":true,"description":"draw hidden lines (dashed)"},"t":{"type":"number","default":0,"description":"seconds through the drive, for an assembly"},"width":{"type":"integer","default":900,"description":"sheet width in px; the scale is fitted to it"},"title":{"type":"string","description":"the name in the title block; defaults to the document's name or the ref it came from"}},"required":["tree"]}},{"name":"report","title":"Report on an assembly","description":"One self-contained HTML page about an assembly: the whole thing drawn in three views, an exploded isometric with a numbered balloon on every item, a parts list with quantities, volumes and sizes, a drawing of each distinct part with its holes called out, and the assembly steps. Every row links back into the viewer, so the page is a handover document, not a picture. The steps are read off the document — placements, `@comp.face` references, mates and their numbers, declared `fits` — never inferred; the order is the document's own, which is a build order because a reference must name a component declared before it. It also carries a MOTION section: per input (or the drive), what moves and how fast, the mechanical advantage, the travel and turn end to end, a rate curve with the dead points marked, and what stays still — all by virtual work from the poser, so it costs nothing and does not depend on a part building. Returns the HTML as an embedded resource plus the parts list, the steps and the motion as data. A server builds a few new parts per call and caches them, so a big assembly may take two or three calls (`incomplete: \"parts\"` says what is left).","inputSchema":{"type":"object","properties":{"assembly":{"oneOf":[{"type":"object","description":"A feature tree (see cad.mino.mobi/README.md), or an assembly with `components`. Strings `bench:<name>` and `at://…` are accepted in place of the object."},{"type":"string","description":"`bench:<name>` or an `at://` URI"}]},"t":{"type":"number","default":0,"description":"seconds through the drive: the pose the assembly is drawn in"},"explode":{"type":"number","default":0.6,"description":"how far the exploded view pushes the parts apart, as a fraction of the assembly size"},"hidden":{"type":"boolean","default":true,"description":"hidden lines on the drawings"},"maxParts":{"type":"integer","default":20,"description":"how many part sheets to draw"},"title":{"type":"string"}},"required":["assembly"]}},{"name":"step","title":"Export STEP","description":"The exact B-rep as STEP text (Truck kernel). For other CAD systems.","inputSchema":{"type":"object","properties":{"tree":{"oneOf":[{"type":"object","description":"A feature tree (see cad.mino.mobi/README.md), or an assembly with `components`. Strings `bench:<name>` and `at://…` are accepted in place of the object."},{"type":"string","description":"`bench:<name>` or an `at://` URI"}]}},"required":["tree"]}},{"name":"list_files","title":"List a repo's CAD files","description":"The file tree in anyone's public repo: path, kind, AT URI, updated. `minomobi.com` holds the published bench (parts/<name>, train, clock).","inputSchema":{"type":"object","properties":{"repo":{"type":"string","description":"a handle or DID"},"prefix":{"type":"string"}},"required":["repo"]}},{"name":"get_file","title":"Read a CAD file","description":"A file by AT URI, or by repo and path: its head entry, the current revision's tree, and the mainline history (message, date, repo). Pass the tree straight back into build.","inputSchema":{"type":"object","properties":{"uri":{"type":"string","description":"at://did/com.minomobi.cad.part/rkey"},"repo":{"type":"string"},"path":{"type":"string"}}}}]}