# measure-mcp (pypi · measure-mcp)

AI tape measure: cookware capacity, recipe scaling, room fit, Amazon FBA size tiers, moving volume.

- Trust score: 60/100 (medium)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-17

## Components

- pypi · `measure-mcp`: 60/100 (this document), [markdown](https://verifymcp.io/servers/purahmanian-measure-mcp/measure-mcp.md), [page](https://verifymcp.io/servers/purahmanian-measure-mcp/measure-mcp)

## Channel facts

- Registry: `pypi`
- Package: `measure-mcp`
- Version: `0.1.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-17.

- **Supply Chain Security**: 50/100
  - Malware scan not yet available for this package.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised build step with no custom scripting around it.
  - 1 of 34 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 97/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to purahmanian/measure-mcp).
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 0 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 50/100
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 11929 tokens (~350/item across 34 items; 34 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 3/100
  - Stability observed for 1 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 71/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 34 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 35 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the measure-mcp server?

measure-mcp runs locally as a PyPI package, launched with uvx measure-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add purahmanian-measure-mcp -- uvx measure-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "purahmanian-measure-mcp": {
      "command": "uvx",
      "args": [
        "measure-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "purahmanian-measure-mcp": {
      "command": "uvx",
      "args": [
        "measure-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add purahmanian-measure-mcp -- uvx measure-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "purahmanian-measure-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "measure-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add purahmanian-measure-mcp --command uvx --arg measure-mcp
```

### Hermes

```yaml
mcp_servers:
  purahmanian-measure-mcp:
    command: "uvx"
    args: ["measure-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "purahmanian-measure-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "measure-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add purahmanian-measure-mcp -t stdio -c uvx -a measure-mcp
```

### Other

```json
{
  "mcpServers": {
    "purahmanian-measure-mcp": {
      "command": "uvx",
      "args": [
        "measure-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-17 (score 60, +1)

- [functional regression] Security disclosure: unverified → fail

### 2026-10-16 (score 59)

First indexed and scored.

## MCP tools (34)

### `measure_depth_info` (~168 tokens)

Check what a photo or depth file contains BEFORE measuring from it.

path: HEIC/HEIF, TIFF, 16-bit PNG, NPZ, JPEG, or a capture-app bundle (folder or .zip). Returns summary
(quote it), info {kind, has_depth, depth_size [w, h], accuracy absolute|relative, source, intrinsics_origin,
valid_fraction, warnings}, advice and capabilities {monocular_depth, heic, usd}. accuracy "relative" needs a
reference object; intrinsics_origin "assumed" means the camera field of view is a guess (every size is then
capped at low confidence with a wide +/-). A file with no depth is a plain photo: see advice for the options.

Input parameters:

- `path` (string, required)

### `measure_object` (~550 tokens)

Size (length, width, height) of one object standing on a flat surface, from a depth capture or 3D scan.

path: LiDAR/Portrait HEIC, capture bundle (folder or .zip), a metric depth file (TIFF, 16-bit PNG in mm,
NPZ), or a 3D scan: a Scaniverse, Polycam or 3D Scanner App OBJ or PLY export (a .zip holding the .obj plus
its .mtl and texture is fine). A scan must show the object standing on a table; the object is the one
nearest the middle, as a gravity-aligned box, and rgb_path, bbox, point and reference do not apply to it. The
file's units and up axis are detected and reported in the result's `scan` block; if they are wrong or
ambiguous pass scan_units (m|cm|mm|in: what the FILE is written in, `units="cm"` works as an alias) and
up_axis (x|y|z, signs ok). rgb_path: optional original photo (its EXIF gives the focal length; its pixels
are the coordinates for bbox and point). bbox [x0, y0, x1, y1] or point [x, y]: PHOTO pixels (depth-map
pixels when there is no photo) to pick the object. reference {"type": "credit_card", "corners": [[x,y] x4]} (see
measure_list_reference_objects) rescales relative depth and fixes a guessed field of view. units:
metric|imperial|both.
Returns summary (quote it), confidence (worst of the edges, the same rule fba_measure_package uses),
measurements longest/middle/shortest_edge (+/- about 95%) and bounding_box_volume (the enclosing box, NOT a
vessel's capacity: use kitchen_measure_vessel for that), quality, warnings. Never "high" for relative or
monocular depth or for a file without camera intrinsics (those are "low"), nor for a scan whose units had to
be guessed (check `scan.units_source`). Under 1.5 cm is unreliable.
Plain photo with no depth: pass bbox around a FLAT object plus a rectangular reference lying flush beside it
and you get its footprint (length x width, no heights, no install needed).

Input parameters:

- `bbox`
- `path` (string, required)
- `point`
- `reference`
- `rgb_path`
- `scan_units` (string)
- `units` (string)
- `up_axis` (string)

### `measure_distance_between_points` (~237 tokens)

Straight-line distance between two pixels of a depth capture (a doorway width, a shelf gap).

path: LiDAR/Portrait HEIC, capture bundle or metric depth file (TIFF, 16-bit PNG in mm, NPZ). point_a and
point_b: [x, y] in PHOTO pixels (depth-map pixels when there is no photo). rgb_path: optional original photo
(EXIF gives the focal length). reference: see measure_list_reference_objects; with a plain photo the two
points must lie on the reference's surface. units: metric|imperial|both.
Returns summary (quote it), confidence, measurements [distance] (+/- about 95%), warnings. A depth file
without camera intrinsics is capped at low with a wide +/-. Glass, mirrors and black surfaces have no depth
(NO_DEPTH_AT_POINT): pick a nearby matte point. Points under 3 cm apart are within the noise.

Input parameters:

- `path` (string, required)
- `point_a` (required)
- `point_b` (required)
- `reference`
- `rgb_path`
- `units` (string)

### `measure_list_reference_objects` (~128 tokens)

List everyday objects of known size (credit_card, us_quarter, us_letter, a4, half_sheet_pan, dollar_bill)
that give a photo a metric scale, and how to pass one as `reference`.

Lay it flat on the same surface as the thing measured, fully visible, then pass reference={"type": key,
"corners": [[x,y] x4 in photo pixels, clockwise from top-left]} (discs: "bbox"). Needed for relative depth;
it also fixes a guessed field of view, and measures a flat object's footprint in a plain photo.

### `measure_open_capture` (~104 tokens)

Describe a capture bundle from the measure-mcp iOS app (a folder or .zip): depth.tiff, confidence, colour
image and a capture.json sidecar with intrinsics, pose and device.

Returns summary (quote it), depth_size, source (lidar), accuracy, valid_fraction, depth_range_m, intrinsics.
Pass the same path to kitchen_measure_vessel, measure_object, measure_distance_between_points to measure.

Input parameters:

- `path` (string, required)

### `measure_find_files` (~212 tokens)

List recent measurable files on this computer, newest first, with what each contains.

When the user says "this photo" or "the scan I just took" in chat you have NO file path: ask them to save it
to ~/measure-mcp-inbox (or AirDrop it to Downloads), then call this tool and use the path it returns.
folder: look only there (direct children, no recursion); default: $MEASURE_MCP_INBOX, ~/Downloads,
\~/Desktop, ~/measure-mcp-inbox. limit: 1-100 (default 20).
Finds HEIC/HEIF, JPEG, depth TIFF/PNG/NPZ, capture .zip or folders, PLY/OBJ/USDZ and RoomPlan/scan JSON.
Each file: path, size_bytes, modified, age, kind, has_depth (+ depth_size, accuracy, source, intrinsics),
can_measure_with. Returns summary, files, searched.

Input parameters:

- `folder`
- `limit`

### `kitchen_measure_vessel` (~715 tokens)

Capacity of a bowl, baking dish, cake pan, sheet pan or pot from one depth capture or 3D scan (to scale a
recipe).

Camera looking down into the upright vessel on a flat surface (45 degrees above the table or steeper), whole
rim in frame. path: LiDAR/Portrait HEIC, capture bundle (folder or .zip), metric depth file (16-bit PNG in mm,
TIFF or NPZ in meters), a plain photo, or a 3D scan: a Scaniverse, Polycam or 3D Scanner App OBJ or PLY
(a .zip with the .obj, .mtl and texture is fine). A scan needs the vessel upright on a table with some table in
view; it is the object nearest the middle, clutter is ignored, and rgb_path, bbox, point and reference do not
apply. Units and up axis are detected and reported in `scan` and warnings; if wrong, pass scan_units
(m|cm|mm|in: the FILE's units; Scaniverse writes meters; `units="cm"` also works) and up_axis (x|y|z, signs
ok). rgb_path: optional original photo (EXIF gives the focal length).
bbox [x0, y0, x1, y1] or point [x, y] pick the vessel among several: PHOTO pixels (depth-map pixels when
there is no photo). vessel_type: bowl|pot|round_pan|rect_pan|sheet_pan|casserole hint, or auto. material
(metal|glass|ceramic|silicone) and wall_thickness_mm set the wall allowance (depth is measured to the outer
rim). reference {"type": "credit_card", "corners": [[x,y] x4]}: needed for relative depth, useful when a
depth file has no camera intrinsics; see measure_list_reference_objects. units: metric|imperial|both.

A plain photo has no depth. With the base install it returns NO_DEPTH whose hint lists the options in
order: LiDAR capture; a credit card in frame plus pip install "measure-mcp[depth]"; typed dimensions
(kitchen_vessel_from_dimensions, which always works). measure_depth_info shows what is installed.

Returns summary (quote it), vessel (pass it as source_vessel/target_vessel to kitchen_scale_recipe),
measurements (rim size, inner depth, brimful capacity, each +/- about 95% with a confidence), capacity (L, mL,
cups, quarts), fil…

Input parameters:

- `bbox`
- `depth_source` (string)
- `material` (string)
- `path` (string, required)
- `point`
- `reference`
- `rgb_path`
- `scan_units` (string)
- `units` (string)
- `up_axis` (string)
- `vessel_type` (string)
- `wall_thickness_mm`

### `kitchen_vessel_from_dimensions` (~464 tokens)

Build a vessel and its capacity from a standard pan name or typed dimensions; no photo, always works.

Pass EITHER preset OR dimensions (both is an error). preset takes natural names: "9x13", "9 x 13 inch pan",
"8 inch round", "8-inch cake pan", "half sheet", "loaf pan", "bundt", "2 qt saucepan", "10 inch skillet",
"23x33 cm"... Presets include square/round/springform pans, 9x13, loaf pans, quarter/half/full sheets, pie
plate, skillets, bundt and tube pans, one muffin cup, casseroles and pots by quart. The result says which
preset it resolved to (preset.resolved_to, preset.match exact|alias|parsed|default|fuzzy): tell the user.
An unknown name returns candidates.
dims: "9 x 13 x 2 in" (length x width x depth), "9 x 2 in" (round: diameter x depth), a list or a dict; or the
named fields diameter, or length and width, plus depth. dims_unit: in (inches, default), cm, mm, m.
Measurements are INSIDE, rim to inside floor. For slanted walls add bottom_diameter (or bottom_length and
bottom_width, never wider than the rim); profile cylinder|frustum|cap is inferred (bowl: "cap").
Bundt/tube: tube_diameter (approximate). Outside sizes need wall_thickness. corner_radius is optional.
Returns summary (quote it), vessel (pass to kitchen_scale_recipe), capacity (L, mL, cups, quarts, brimful),
fill_guidance, preset {source, verified, how resolved} and warnings.

Input parameters:

- `bottom_diameter`
- `bottom_length`
- `bottom_width`
- `corner_radius`
- `depth`
- `diameter`
- `dims`
- `dims_unit` (string)
- `length`
- `preset`
- `profile`
- `shape`
- `tube_diameter`
- `wall_thickness`
- `width`

### `kitchen_scale_recipe` (~555 tokens)

Scale a recipe written for one pan to another vessel, with kitchen-friendly amounts.

ingredients: ONE text block, an ingredient per line (paste the list as is), or a list of strings ("2 1/4 cups
flour", "3 eggs", "1/2 cup (115 g) butter, melted") or {"amount", "unit", "name"} objects. A line with no
number stays unscaled and is listed in warnings. source_vessel: the pan the recipe was written for;
target_vessel: the pan to use now. Each is a `vessel` object from kitchen_measure_vessel or
kitchen_vessel_from_dimensions, or just a name ("9x13", "8 inch round", "half sheet"); vessels_resolved says
which preset each name became: check it with the user.
recipe_kind: batter_heavy (cakes, quick breads; fill <= 2/3), sponge (<= 1/2), bars_brownies, bread_loaf,
casserole, soup_stew, sauce (these two scale by volume); words like brownies, cake, soup work. Omitted: it is
inferred from the recipe text when obvious, else batter_heavy; recipe_kind.used / source / why say which.
mode auto|area|volume: auto uses the AREA ratio (same batter thickness) unless the target is clearly
shallower or it is a soup (then VOLUME). original_bake_minutes, original_temp_f: optional, for the bake note.
fill_fraction: how full the original fills the source pan (0.05-1.0), else a typical value is assumed.
rounding: kitchen (1/8 cup, 1/4 tsp steps) | exact.
detail: summary (default, lean lines) | full (adds original and exact amounts per ingredient).
Returns summary (quote it), scale_factor (+/-), basis and why, ingredients_scaled (original, scaled, display),
fill (height, limit, ok), bake notes, recipe_kind, vessels_resolved, warnings. Eggs scale to whole, half or
measured beaten egg. Fill height and bake notes are guidance, not measurements: go by doneness. Factors
outside 0.5-2.0 and Bundt/angel-food/cheesecake pans carry warnings.

Input parameters:

- `detail` (string)
- `fill_fraction`
- `ingredients` (required)
- `mode` (string)
- `original_bake_minutes`
- `original_temp_f`
- `recipe_kind`
- `rounding` (string)
- `source_vessel` (required)
- `target_vessel` (required)

### `room_load_scan` (~400 tokens)

Read a room scan and report what was found (walls, doors, windows, objects, size, detected units and up axis).

\``path`` is the scan file. Supported: RoomPlan CapturedRoom JSON (several encodings) and measure-room JSON;
USD/USDZ (RoomPlan export or any labeled scene; needs ``pip install measure-mcp[usd]``); PLY and OBJ point clouds or
meshes, whose floor, ceiling, walls, door/window gaps and furniture are recovered geometrically. Units
(m, cm, mm, in, ft) and the up axis are detected from the geometry, never trusted from file metadata; pass
\``scan_units`` / ``up_axis`` only to override. ``known_dimension`` calibrates the scale from one tape value:
\``{"target": "ceiling_height" | "wall:wall_1", "length": 2.44, "unit": "m"}``. ``north_deg`` says which way north points in
the room plan (degrees counter-clockwise from the plan +x axis, the frame of ``start``/``end`` in room_list_walls) and
enables "north wall" style references; scans that carry no compass cannot resolve them.
STATELESS: no option is remembered. The reply's ``load_options`` holds the non-default options used; pass that object as
\``load_options`` to the other room_* tools (they load ``path`` again, cached) when it is not empty.
Raw scans are less precise than RoomPlan; every result carries a +/- and a confidence. Corrupt or empty files give an
error with a code and hint.

Input parameters:

- `format` (string)
- `known_dimension`
- `north_deg`
- `path` (string, required)
- `scan_units` (string)
- `units` (string)
- `up_axis` (string)

### `room_summary` (~187 tokens)

Overall size of the room: footprint shape and vertices, floor area, ceiling height, volume, wall lengths, openings and objects.

\``path`` is the scan file. Each measurement has a value, a +/- (about 95%), a confidence and a display string
in the requested ``units``. The ``summary`` field is a sentence that can be quoted as is. Every wall has a ``label`` such as
"wall_3: 4.20 m, has door_1 (door), with sofa obj_1". ``detail="full"`` adds measurement names and sources and lifts the
list caps. ``load_options``: the object returned by room_load_scan, only if it was non-empty (nothing is remembered).

Input parameters:

- `detail` (string)
- `load_options`
- `path` (string, required)
- `units` (string)

### `room_list_walls` (~219 tokens)

List the walls with a plain-language ``label`` (id, length, what is on it), length, height, direction, free segments between doors/openings, and what stands along them.

\``free_segments`` leave out door and opening spans (plus a 5 cm jamb margin); windows do not cut a wall
because they only limit height. ``min_free_length_m`` hides walls whose longest free run is shorter (meters).
Use this to find a wall for a bed, sofa or bookcase and to map "the wall behind the sofa" to an id. ``u0``/``u1`` are
distances in meters along the wall from its start; ``inward_normal`` points into the room. Long listings are capped
(``detail="full"`` for all). ``load_options`` as in room_summary.

Input parameters:

- `detail` (string)
- `load_options`
- `min_free_length_m` (number)
- `path` (string, required)
- `units` (string)

### `room_list_openings` (~184 tokens)

List doors, windows and open passages with width, height, sill and head height, wall, position and swing side.

Filter by ``kind`` (door, window, opening, gap_unknown) or ``wall_id``, which takes a wall id or words:
"longest wall", "wall with the door", "wall behind the sofa" (see room_check_fit). Door sizes from RoomPlan may be the leaf
size rather than the clear opening, so measure a tight door with a tape. Only ``door``, ``opening`` and ``gap_unknown``
entries can be used with room_check_doorway. ``load_options`` as in room_summary.

Input parameters:

- `detail` (string)
- `kind`
- `load_options`
- `path` (string, required)
- `units` (string)
- `wall_id`

### `room_list_objects` (~131 tokens)

List furniture and appliances found in the scan with category, size (width x depth x height), footprint, height off the floor and nearest wall.

RoomPlan scans carry Apple categories (sofa, table, bed, storage, refrigerator, ...); raw point clouds give ``unknown``.
Filter by ``category`` (case-insensitive). Long listings are capped (``detail="full"`` for all). ``load_options`` as in room_summary.

Input parameters:

- `category`
- `detail` (string)
- `load_options`
- `path` (string, required)
- `units` (string)

### `room_check_fit` (~696 tokens)

Will this item fit? Checks an item's footprint against a wall's free run or the whole room and returns a verdict with margin.

\``dims`` is the item size, width x depth x height (width = longest front-facing side, depth = front to back): a string such as
"84 x 37 x 34 in", "60x30 in" (height unknown), "2.1 x 0.95 x 0.9 m"; a list such as [84, 37, 34] with ``dims_unit`` (default
inches, and the reply says so); or an object like {"name": "sofa", "width": 84, "depth": 37, "height": 34, "unit": "in"}
({"length", "width", "height"} is read as width = length, depth = width). ``item_name`` labels it.
\``target``: a wall, "room" (default; finds spots), or {"type": "region", "x": 0, "y": 0, "width": 2, "depth": 1} in room meters.
A wall is an id ("wall_1", or {"type": "wall", "id": "wall_1"}) or words: "longest wall", "shortest wall", "wall with the door",
"wall with the window", "wall behind the sofa" / "sofa wall" (the wall nearest that object category or id), and
"north/south/east/west wall" ONLY when the scan defines an orientation (see room_load_scan ``north_deg``). An unclear
reference returns an error whose hint lists every wall with its id, length and what is on it (room_list_walls shows the same
\``label``s). ``clearance``: "none", "walkway" (76 cm / 30 in in front), "comfortable" (91 cm / 36 in), or
{"front_m": 0.76, "side_m": 0, "back_gap_m": 0.02}.
It respects doors, door swings, windows (``windows`` warn/block/ignore) and existing furniture; list furniture the user will remove
(or the scan's own copy of the item, e.g. the sofa being replaced) in ``ignore_objects`` (ids or a comma list): when the thing
blocking a wall looks like the item itself, the reply says so. ``verdict`` is fits / tight / probably_not / does_not_fit from margin
divided by the scan's uncertainty; a 1 cm margin on a drifty scan is "tight", never "fits". Returns placements with footprints (pass
one to room_floor_plan_svg). ``max_results`` is 1-10. ``detail`` summary|full. ``load_options`` as in r…

Input parameters:

- `clearance`
- `detail` (string)
- `dims` (required)
- `dims_unit`
- `ignore_objects`
- `item_name`
- `load_options`
- `max_results` (integer)
- `path` (string, required)
- `respect_door_swing` (boolean)
- `rotations_deg`
- `target`
- `units` (string)
- `windows` (string)

### `room_check_doorway` (~452 tokens)

Can this item go through that door or open passage? Tests a rigid box through the clear opening, turning it any way it can go.

\``dims`` as in room_check_fit but all three sizes are needed: "84 x 37 x 34 in", [84, 37, 34] with ``dims_unit``, or
{"name": "sofa", "width": 84, "depth": 37, "height": 34, "unit": "in", "diagonal_depth": 31, "leg_height": 6}. Real sofas are not
boxes: give ``diagonal_depth`` (top-back corner to bottom-front corner of the frame, the figure movers use) when known, and
\``leg_height`` if the legs unscrew. ``opening_id`` is a door or open passage from room_list_openings; WINDOWS ARE REFUSED
(error NOT_A_DOORWAY, which lists the valid door/opening ids). Open passages (no door leaf) get no leaf allowance, and
unidentified gaps (gap_unknown) are tested with lowered confidence and a note. ``door_state``: "as_is"/"leaf_open_90" (leaf swung
back; it still takes ``door_intrusion_m``, default 4 cm) or "removed" (off the hinges). ``allow_roll`` lets the item tilt about
its travel axis; ``allow_legs_removed`` removes the legs first. Returns the verdict, margin, best way through, alternatives, and
what would help (remove the door, remove legs). The approach path and turns are not evaluated; near zero margin the answer is
"tight": measure the door. ``load_options`` as in room_summary.

Input parameters:

- `allow_legs_removed` (boolean)
- `allow_roll` (boolean)
- `detail` (string)
- `dims` (required)
- `dims_unit`
- `door_intrusion_m`
- `door_state` (string)
- `item_name`
- `load_options`
- `opening_id` (string, required)
- `path` (string, required)
- `units` (string)

### `room_floor_plan_svg` (~276 tokens)

Draw the room as a floor plan SVG: walls with dimension lines, doors with swing arcs, windows, furniture, and optionally a proposed item.

Pass ``placement`` (one entry of ``placements`` from room_check_fit, with an optional "verdict" key to color it) to draw the item;
\``dims`` / ``item_name`` only supply its label. Dimensions are written in the requested ``units``. The SVG is ALWAYS saved into
the server's output folder (MEASURE_MCP_OUTPUT_DIR, default ~/measure-mcp-output) as ``output_name`` (a plain file name; folders in
it are dropped and ``.svg`` is enforced, default "floor_plan") and the reply gives ``path``. The ``svg`` text is also returned
inline when it is under about 30 KB, otherwise only the path and a note. All labels are sanitized and escaped.
\``load_options`` as in room_summary.

Input parameters:

- `dims`
- `dims_unit`
- `item_name`
- `load_options`
- `output_name`
- `path` (string, required)
- `placement`
- `px_per_m` (integer)
- `show_dimensions` (boolean)
- `show_labels` (boolean)
- `units` (string)

### `fba_analyze` (~602 tokens)

START HERE for "what FBA tier and fee is this product?": one call returns the size tier, dimensional
and shipping weight, the estimated fulfillment fee (this period, and the peak or non-peak alternative),
the nearest limit that would change the tier or fee with its margin in YOUR units, a risk class
(safe / risky / critical) that reflects that nearest edge, and the single best shrink or weight cut to
save money. Quote `summary`; it is one self-contained paragraph.

Inputs: dims = the 3 edges of the PACKED unit as "12 x 9 x 3 in", [12, 9, 3] (with dims_unit) or
{"length":12,"width":9,"height":3}; weight = 1.4 or "1.4 lb" / "22 oz" / "640 g" (a bare number is POUNDS
unless weight_unit says otherwise, and the summary says how it was read); price = listing price in USD
(29.99 or "$29.99"; selects the fee price band). dims_unit is in (default), cm or mm; weight_unit is lb
(default), oz, g or kg. dims_sigma = 1-sigma measuring error per edge in dims_unit (omit for tape values;
use sigma_in from fba_measure_package, or 0.2 in for a LiDAR scan); weight_sigma_oz = scale error in
ounces. ship_date (ISO, default today) picks peak or non-peak fees. margin_in (0.5 in) and margin_pct (3 %)
are the safety margins behind the risk class; a weight-band edge counts as risky when a measuring error of
margin_in could cross it. max_shrink_pct and min_dims bound the shrink search.

detail="summary" (default) returns a short `caveats` list (as-of date, "Amazon's own measurement governs",
data gaps that matter for THIS result); detail="full" adds all thresholds, every suggestion and the full
assumptions list. Use fba_tier_headroom / fba_size_tier / fba_fee_estimate only when you need that detail.
Only product_class "standard" is modelled in v0.1.

Estimate from third-party-compiled rules (see fba_data_status); Amazon's own measurement governs.

Input parameters:

- `detail` (string)
- `dims` (required)
- `dims_sigma`
- `dims_unit`
- `include_fuel_surcharge` (boolean)
- `margin_in` (number)
- `margin_pct` (number)
- `max_shrink_pct` (number)
- `min_dims`
- `price` (required)
- `ship_date`
- `units_per_month`
- `weight` (required)
- `weight_sigma_oz`
- `weight_unit`

### `fba_measure_package` (~721 tokens)

Measure the PACKAGED unit (the box or bag as it ships) from 1 to 5 scans of the same package.

Inputs: path = one scan file, or paths = a list of 2 to 5 scans of the same pack (combined by median per
sorted edge). A scan is a 3D scan export (a Scaniverse, Polycam or 3D Scanner App OBJ or PLY mesh or point
cloud; a .zip holding the .obj plus its .mtl and texture is fine) of the package on a table, a metric depth
file (HEIC, TIFF, 16-bit PNG, NPZ) or an iOS capture bundle (folder or .zip); rgb_path is an optional
companion photo for a single depth file. For OBJ/PLY the file's units (m, cm, mm or inches) and up axis are
detected from the table and plausible sizes, and notes say what was assumed; if that is wrong or ambiguous,
pass scan_units (m|cm|mm|in: what the FILE is written in; Scaniverse writes METERS, and `units="cm"` works as
an alias) and up_axis (x|y|z, signs ok). The package is the object nearest the middle of the scan.
weight is the user's own scale reading of the packed unit (a scan cannot weigh): a number
(POUNDS unless weight_unit says otherwise) or "22 oz" / "640 g"; weight_sigma_oz is the scale's 1-sigma
error in ounces. bbox [x0, y0, x1, y1] or point [x, y] pick the package out of the scene; they are in PHOTO
pixels when the scan carries a photo (HEIC or a capture bundle with its colour image), otherwise in
depth-image pixels (the result's pixel_space says which). reference is only used when the depth is
relative rather than metric: {"type": "credit_card", "corners": [[x,y] x4]} or {"type", "bbox"} in the same
pixel space (see measure_list_reference_objects).

Returns dims_in {longest, median, shortest} in INCHES with 1-sigma sigma_in per edge (LiDAR is never
reported better than 0.2 in), dims_cm, length_plus_girth_in, volume_cubic_in, unit_weight (user-supplied),
confidence (high/medium/low), quality_flags (thin_item_unreliable, low_coverage, soft_or_irregular_surface,
scan_disagreement, monocular_only, relative_depth_not_metric, assumed_intrinsics)…

Input parameters:

- `bbox`
- `detail` (string)
- `path`
- `paths`
- `point`
- `reference`
- `rgb_path`
- `scan_units` (string)
- `units` (string)
- `up_axis` (string)
- `weight`
- `weight_sigma_oz`
- `weight_unit`

### `fba_size_tier` (~481 tokens)

Classify a packaged unit into its US Amazon FBA size tier (small standard, large standard, small
bulky, large bulky, extra-large bands) and show how close it is to each limit. (fba_analyze answers the
usual question, tier plus fee plus nearest limit, in one call.)

Inputs: dims = the 3 edges of the PACKED unit, any order: "12 x 9 x 3 in", [12, 9, 3] with dims_unit
(in default, cm or mm) or {"length":12,"width":9,"height":3}; weight = unit weight of the packed unit:
1.4, "1.4 lb", "22 oz" or "640 g" (a bare number is POUNDS unless weight_unit is oz, lb, g or kg; the
summary states how it was read). dims_sigma = 1-sigma measurement error per edge in dims_unit (a single
number, or 3 numbers in the same order as dims; omit for exact tape/caliper values); weight_sigma_oz =
scale error in ounces. as_of (ISO date) picks the dataset effective on that date, default today. Only
product_class "standard" is modelled in v0.1.

Returns tier, sorted dims in inches, length_plus_girth_in, unit and dimensional weight in lb (divisor 139,
2 in floor on the two shorter sides for bulky tiers), the shipping weight Amazon bands on (greater of unit
and dimensional, unit-only for small standard), each binding limit with margin, z-score and risk class
(safe/risky/critical), rejected tiers with the failing limits, the next tier up and tier_probabilities when
dims_sigma is given. detail="summary" (default) adds a short `caveats` list; detail="full" adds the
assumptions list and disclaimer.

Estimate from third-party-compiled rules (see fba_data_status); Amazon's own measurement governs.

Input parameters:

- `as_of`
- `detail` (string)
- `dims` (required)
- `dims_sigma`
- `dims_unit`
- `product_class` (string)
- `weight` (required)
- `weight_sigma_oz`
- `weight_unit`

### `fba_fee_estimate` (~501 tokens)

Estimate the US Amazon FBA per-unit fulfillment fee in USD for a packaged unit.

Inputs: dims = 3 edges of the PACKED unit, any order ("12 x 9 x 3 in", [12, 9, 3] with dims_unit in/cm/mm,
or a dict); weight = 1.4 / "1.4 lb" / "22 oz" / "640 g" (a bare number is POUNDS unless weight_unit says
otherwise; the summary states how it was read); price = the listing price in USD (24.99 or "$24.99"; selects
the fee price band: under 10, 10 to 50, over 50). ship_date (ISO date, default today) selects the peak table
(2026-10-15 to 2027-01-14) or non-peak, and whether the 3.5% fuel and logistics surcharge (from 2026-04-17)
applies; set include_fuel_surcharge=false to see the fee without it. dims_sigma / weight_sigma_oz add a +-2
sigma fee interval. units_per_month adds a monthly total. Only product_class "standard" is supported;
others return an error.

Returns tier, shipping weight, price_band, period (peak/nonpeak), itemised components with the rule used,
total_usd, interval_usd, monthly_usd, the alternate period's total, what is NOT included (bulky packaging
fee, inbound placement, storage, returns) and data_verification. If a fee row is missing in the dataset the
tier is still returned and fee_available is false. detail="summary" (default) adds a short `caveats` list;
detail="full" adds the assumptions list and disclaimer.

Rates come from third-party summaries and are not yet verified against Seller Central; compare with the Fee
Preview report. Amazon's own measurement and fee schedule govern.

Input parameters:

- `detail` (string)
- `dims` (required)
- `dims_sigma`
- `dims_unit`
- `include_fuel_surcharge` (boolean)
- `price` (required)
- `product_class` (string)
- `ship_date`
- `sipp_enrolled`
- `units_per_month`
- `weight` (required)
- `weight_sigma_oz`
- `weight_unit`

### `fba_tier_headroom` (~569 tokens)

Show how close a packaged unit is to every FBA tier, weight and fee-band threshold, and what to
shrink to pay less. (fba_analyze is the one-call version with the single best suggestion.)

Inputs: dims = 3 edges of the PACKED unit, any order ("12 x 9 x 3 in", [12, 9, 3] with dims_unit in/cm/mm,
or a dict); weight = 1.4 / "1.4 lb" / "22 oz" (a bare number is POUNDS unless weight_unit says otherwise);
price = listing price in USD. dims_sigma = 1-sigma error per edge in dims_unit (use sigma_in from
fba_measure_package; 0.2 in for a LiDAR scan); weight_sigma_oz = scale error in ounces. margin_in is the
safety margin in INCHES (default 0.5) and margin_pct the weight margin in percent (default 3); a threshold
is "risky" inside either margin or within 2 sigma and "critical" within 1 sigma. When dimensional weight
sets the shipping weight, a weight-band edge is also risky if a margin_in measuring error could cross it.
max_shrink_pct caps how much any one edge may shrink (default 15%); min_dims (same form and unit as dims)
is the smallest each edge can be because of the contents. ship_date (ISO, default today) picks peak or
non-peak fees; units_per_month adds monthly savings.

Returns current tier and fee, thresholds sorted by risk, overall_risk, ranked suggestions (single- and
two-edge shrinks, each with apply_dims_in, new_total_usd, saving_per_unit_usd and per inch, confidence),
tier_drop_suggestions (shrinks that reach a cheaper tier with the safety margin), and weight_suggestions
(unit-weight cuts). Targets include the safety margin. Savings come from the same fee engine as
fba_fee_estimate. detail="summary" (default) adds a short `caveats` list; "full" adds the assumptions list.

Estimate only; Amazon measures the packed unit itself and its measurement governs.

Input parameters:

- `detail` (string)
- `dims` (required)
- `dims_sigma`
- `dims_unit`
- `include_weight_options` (boolean)
- `margin_in` (number)
- `margin_pct` (number)
- `max_shrink_pct` (number)
- `min_dims`
- `price` (required)
- `ship_date`
- `units_per_month`
- `weight` (required)
- `weight_sigma_oz`
- `weight_unit`

### `fba_audit_listing` (~666 tokens)

Compare what Amazon has on file / charged against your own measurement and say whether a
remeasurement request looks worthwhile. A design-time and audit aid, NOT dispute evidence.

Naming: `dims`, `weight` (and dims_unit, weight_unit, dims_sigma) are YOUR measurement of the packed unit,
as in the other fba tools; every `amazon_*` parameter is what Seller Central shows or charged.
dims = your 3 edges ("12 x 9 x 3 in", a list or a dict; dims_unit in/cm/mm, default in); dims_sigma = their
1-sigma error in dims_unit (default 0.2 in); weight = your scale reading (1.4, "1.4 lb", "22 oz"; a bare
number is POUNDS) and is optional only when amazon_weight is given. Give at least one of: amazon_dims
(+ amazon_weight; amazon_dims_unit and amazon_weight_unit default in and lb) as shown in Seller Central,
amazon_tier (e.g. "small_bulky"), or amazon_fee = the per-unit fulfillment fee charged (Fee Preview or
order fee, without referral fee; 6.10 or "$6.10"). price = listing price in USD. charge_date = date the fee
was charged (ISO; starts the 90-day reimbursement window), ship_date defaults to it.
fee_includes_fuel_surcharge: leave unset to test both. units_sold_since_charge scales the exposure;
units_per_month adds a monthly amount.
When the fee differs under your dims and Amazon's and edges differ significantly, the verdict is at least
amazon_possibly_over / amazon_possibly_under (uncertainty softens "likely" to "possibly", never to "no money
at stake"); "consistent" is only returned when the central fees match or no edge differs.

Returns verdict (consistent, amazon_likely_over, amazon_likely_under, inconclusive,
fee_not_explained_by_dims), confidence (never high), per-edge deltas with significance, tier comparison
with probabilities, fee comparison with overcharge per unit (central and conservative), a reverse lookup
of which tier/weight-band/period/price-band rows produce the charged fee (works without Amazon's dims),
reimbursement_deadline and days_left, likely causes and ne…

Input parameters:

- `amazon_dims`
- `amazon_dims_unit`
- `amazon_fee`
- `amazon_tier`
- `amazon_weight`
- `amazon_weight_unit`
- `charge_date`
- `detail` (string)
- `dims` (required)
- `dims_sigma`
- `dims_unit`
- `fee_includes_fuel_surcharge`
- `price` (required)
- `ship_date`
- `units_per_month`
- `units_sold_since_charge`
- `weight`
- `weight_sigma_oz`
- `weight_unit`

### `fba_draft_remeasure_request` (~324 tokens)

Draft (never send) a Seller Support remeasurement request. Pass the dict returned by
fba_audit_listing as audit, plus asin / sku / fnsku and seller_name.

The text states measurements as seller-provided hand measurements, asks for a multi-unit Cubiscan
remeasurement, asks Amazon to confirm fees and reimburse overcharges since the charge date within
policy, and offers sample units. It does not claim a scan proves anything. Bracketed [ADD: ...]
placeholders mark facts only the seller knows (number of units measured, name); replace them before use.
amazon_dims_text / measured_dims_text override the dimensions taken from the audit, for example
"18.5 x 12 x 3 in". measurement_method describes how the seller measured. tone is "concise" or "detailed".

Returns subject, body, checklist (measure 3+ units as shipped, 90-day window from the charge date,
reported re-request limits), warnings (audit verdict not 'likely over', low confidence, window passed,
missing fields), the channel to use and the deadline. submitted is always false.

Amazon's own measurement governs; photos and estimates from this server are not proof.

Input parameters:

- `amazon_dims_text`
- `asin`
- `audit`
- `fnsku`
- `measured_dims_text`
- `measurement_method` (string)
- `request_reimbursement` (boolean)
- `seller_name`
- `sku`
- `tone` (string)

### `fba_data_status` (~191 tokens)

Report which FBA rules dataset is in force and how much to trust it. Call this before quoting a fee,
or when another fba tool's `caveats` point here.

date (ISO, default today) is the day to check. Returns dataset_id, as_of date of the data, effective
range, the peak window and whether peak or non-peak fees apply on that day, active surcharges, a
per-section verification table (official / secondary_cross_checked / secondary / unverified), the list
of rows that are verified versus not, unverified_fields, staleness warnings (data older than 90 days or
past its review date), source URLs and the 90-day reimbursement window. Fee and tier rows are currently
compiled from third-party sources, so treat them as estimates; Amazon's own measurement and fee
schedule govern.

Input parameters:

- `date`

### `moving_cube_sheet_lookup` (~159 tokens)

Look up how many cubic feet (and pounds) the movers' cube sheet assigns to an item, with sources.

Use this to answer "why 50 cu ft for my sofa?" or to find the right catalog name before building an
inventory. Accepts names, aliases, plurals, small typos and size hints ("55 inch tv", "18 cu ft fridge").
Each match lists the value, the range across published sheets, alternative values, the weight at the
movers' 7 lb per cu ft rule, and whether the row was re-verified against its source. Never includes prices.

Input parameters:

- `limit` (integer)
- `query` (string, required)
- `room`
- `units` (string)

### `moving_estimate_from_inventory` (~181 tokens)

Estimate the volume (cu ft / m3) and weight of a move from a list of belongings.

Give ``inventory_text`` (one block or a list of lines) such as "queen bed, 3-seat sofa, 20 medium boxes",
and/or structured ``items``. Text understands quantities ("3x", "two", "a dozen"), plurals, small typos,
"Bedroom:" headers and notes in parentheses. Items it cannot match are returned in ``unresolved`` and are NOT
in the total; assumed sizes are listed in ``needs_review``: ask the user about them rather than hiding them.

Input parameters:

- `default_room` (string)
- `detail` (string)
- `include_recommendations` (boolean)
- `inventory_text`
- `items`
- `units` (string)

### `moving_estimate_from_scan` (~288 tokens)

Estimate a move from a RoomPlan room scan (JSON export, USDZ, or a PLY/OBJ the room tools can load).

Pass ``path`` (one merged scan) or ``paths`` (one file per room). Scanned furniture (sofa, bed, table,
storage, appliances...) is mapped to cube-sheet sizes; built-in fixtures (sink, toilet, bathtub, built-in
cabinets) are excluded unless fixture_policy="include_all". IMPORTANT: a scan only sees large furniture, so
boxes, clothes, books and kitchenware are missing: read ``coverage_warning``, ask the user about boxes, and pass
them as ``extra_items`` (same item format as moving_estimate_from_inventory) or use contents_allowance. Ambiguous
objects appear in ``needs_review``. A raw point cloud or mesh has no furniture labels: the result then says
\``no_furniture_recognised`` and asks for a RoomPlan export or an inventory list instead of a number.

Input parameters:

- `contents_allowance` (string)
- `detail` (string)
- `extra_items`
- `fixture_policy` (string)
- `include_recommendations` (boolean)
- `path`
- `paths`
- `room_names`
- `size_method` (string)
- `units` (string)

### `moving_estimate_object` (~345 tokens)

Volume of one oddly shaped object from measured size, ready to add to an inventory.

Give ``dims`` ("36 x 72 x 12 in", [36, 72, 12] with dims_unit, or {length,width,height}; any order, default
unit inches, no edge over 10 m) or ``path`` to a depth capture of the object on a surface, or a 3D scan export
of it (a Scaniverse, Polycam or 3D Scanner App OBJ or PLY; a .zip holding the .obj, .mtl and texture is fine;
the object is the one nearest the middle of the scan). For a scan the file's units and up axis are detected
and reported in the notes; if that is wrong, pass scan_units (m|cm|mm|in: what the FILE is written in;
Scaniverse writes meters) and up_axis (x|y|z, signs ok). The moving volume
is the bounding box times a 0.75 fill factor, with a plus/minus; this is a loose envelope, so confidence is
usually low-to-medium. Returns ``inventory_item`` to pass in moving_estimate_from_inventory(items=[...]) or
moving_estimate_from_scan(extra_items=[...]), plus a comparison with the cube-sheet value when the name matches.

Input parameters:

- `dims`
- `dims_unit` (string)
- `name` (string, required)
- `path`
- `reference`
- `room`
- `scan_units` (string)
- `units` (string)
- `up_axis` (string)

### `moving_recommend_truck` (~273 tokens)

Pick the smallest rental truck or van (U-Haul, Penske, Budget) for a load, by volume AND payload.

Pass ``estimate_id`` (or the dict) from moving_estimate_*, or bare volume_cuft / weight / box_fraction (not
both an estimate and volume_cuft). Loads never fill a truck completely, so the required capacity is volume
divided by a packing efficiency of 0.70-0.85 (more boxes pack tighter; override with ``efficiency``).
\``size_range`` shows whether the answer holds across the estimate's error. Capacities are provider-published
approximations. U-Haul does not publish payloads here: for those vehicles the summary says "payload not
published; weight not checked", the load is only compared with similar-sized trucks, and a vehicle with a
published payload is offered as ``known_payload_alternative``. (``weight_lb`` is a deprecated alias of ``weight``.)
No prices.

Input parameters:

- `box_fraction`
- `efficiency`
- `estimate`
- `estimate_id`
- `providers`
- `units` (string)
- `volume_cuft`
- `weight`
- `weight_lb`
- `weight_unit` (string)

### `moving_recommend_container` (~195 tokens)

Pick portable moving containers (PODS 8/12/16 ft, U-Haul U-Box) for a load, by volume AND weight limit.

Containers have hard weight limits that dense loads (books, tools) can hit before the volume is full;
\``weight_binding`` says when weight, not volume, decides the count. Returns a plan such as
[{"container_id": "pods.16ft", "count": 1}] per family. PODS capacities come from third-party sources
(marked unverified): confirm with the provider. Input as in moving_recommend_truck. No prices.

Input parameters:

- `box_fraction`
- `efficiency`
- `estimate`
- `estimate_id`
- `families`
- `units` (string)
- `volume_cuft`
- `weight`
- `weight_lb`
- `weight_unit` (string)

### `moving_recommend_storage` (~160 tokens)

Pick a self-storage unit size (5x5 up to 10x30) for a load, leaving an access aisle.

Unit volume is floor area times ceiling height (8 ft is typical; pass ceiling_ft if the facility differs).
Usable space is 0.65-0.80 of that (packing efficiency minus 0.05 for an aisle). Also reports the next
smaller unit and how much would not fit, and two-unit combinations. Input as in moving_recommend_truck. No prices.

Input parameters:

- `box_fraction`
- `ceiling_ft` (number)
- `efficiency`
- `estimate`
- `estimate_id`
- `units` (string)
- `volume_cuft`

### `moving_export_inventory` (~220 tokens)

Turn an estimate into a printable or shareable inventory list for movers, insurance or storage.

Pass ``estimate_id`` from moving_estimate_* (or the full dict from detail='full'). ``html`` has print CSS
(open in a browser, Save as PDF); ``markdown``, ``csv`` and ``json`` come back inline in ``content`` when
small. Files are only written into the server's output folder (MEASURE_MCP_OUTPUT_DIR, default
\~/measure-mcp-output): ``output_name`` is a plain file name (no folders; the extension follows ``format``),
an existing file is never overwritten, and the result's ``path`` says where it went. The output lists
unmatched and excluded items under "Not counted" and carries a not-a-quote disclaimer.

Input parameters:

- `estimate`
- `estimate_id`
- `format` (string)
- `group_by` (string)
- `include_weights` (boolean)
- `output_name`
- `title` (string)

### `moving_data_info` (~46 tokens)

Report the versions, as-of dates, source URLs, verified/unverified row counts and staleness warnings of the moving data files (cube sheet, trucks, containers, storage units).

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/purahmanian-measure-mcp/measure-mcp#diagnostics

## Score history

- 2026-10-17: 60
- 2026-10-16: 59

## Common questions

### What is the measure-mcp server?

measure-mcp is listed in the public MCP registry as io.github.purahmanian/measure-mcp. AI tape measure: cookware capacity, recipe scaling, room fit, Amazon FBA size tiers, moving volume. This page covers its PyPI package (measure-mcp).

### Is the measure-mcp server safe to use?

measure-mcp scores 60 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 17 October 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the measure-mcp server expose?

measure-mcp exposes 34 tools: measure_depth_info, measure_object, measure_distance_between_points, measure_list_reference_objects, measure_open_capture, and 29 more. Their descriptions and schemas cost roughly 11,600 tokens of context every time the server is loaded.

### Is the measure-mcp server still maintained?

measure-mcp is still listed as active in the MCP registry. We last reached this channel on 17 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the measure-mcp server under?

measure-mcp declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/measure-mcp/
- Socket report: https://socket.dev/pypi/package/measure-mcp
- Repository: https://github.com/purahmanian/measure-mcp
- Changelog RSS feed: https://verifymcp.io/servers/purahmanian-measure-mcp/measure-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/purahmanian-measure-mcp/measure-mcp.json
- HTML version of this page: https://verifymcp.io/servers/purahmanian-measure-mcp/measure-mcp
