# kubik-tools (remote · mcp.kubik.tools)

Freight calculators (weight, metres, vehicle fit) and authenticated team packing-library tools.

- Trust score: 58/100 (low)
- Change this week: +3
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- remote · `mcp.kubik.tools`: 58/100 (this document), [markdown](https://verifymcp.io/servers/markopolovic-kubik-tools/mcp.md), [page](https://verifymcp.io/servers/markopolovic-kubik-tools/mcp)

## Channel facts

- Endpoint: `https://mcp.kubik.tools/mcp`
- Transports: `streamable-http`
- Auth: `none`
- Version: `1.2.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, 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-08-03.

- **Endpoint Security**: 46/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation check failed: no authorisation is required to call this server, and it exposes a tool marked destructive (undo_change).
  - HTTPS not yet verified: we couldn't determine whether a plaintext access path exists.
  - HSTS check failed: the Strict-Transport-Security header is absent.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 55/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 3737 tokens (~533/item across 7 items; 7 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 95/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 84% of tool parameters carry a description.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add --transport http markopolovic-kubik-tools https://mcp.kubik.tools/mcp
```

### Codex

```toml
[mcp_servers.markopolovic-kubik-tools]
url = "https://mcp.kubik.tools/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "markopolovic-kubik-tools": {
      "type": "remote",
      "url": "https://mcp.kubik.tools/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add markopolovic-kubik-tools --url https://mcp.kubik.tools/mcp --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  markopolovic-kubik-tools:
    url: "https://mcp.kubik.tools/mcp"
```

### Other

```json
{
  "mcpServers": {
    "markopolovic-kubik-tools": {
      "type": "http",
      "url": "https://mcp.kubik.tools/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## 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-08-03 (score 58, +1)

No change was recorded against any check on this day. Stability & Change Management went from 23 to 27. That category is still filling its 30-day observation window: 7 days of observed history at the previous scan, 8 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-08-01 (score 57, +1)

No change was recorded against any check on this day. Stability & Change Management went from 17 to 20. That category is still filling its 30-day observation window: 5 days of observed history at the previous scan, 6 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-31 (score 56, −1)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 57, 0)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-29 (score 57, +1)

No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-28 (score 56, +1)

No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-27 (score 55, 0)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-26 (score 55)

First indexed and scored.

## MCP tools (7)

### `calculate_chargeable_weight` (~710 tokens)

Calculate Chargeable Weight

Calculates chargeable (billable) weight -- frachtpflichtiges Gewicht, Frachtgewicht -- for a freight shipment (Stückgut or Sammelgut) from a list of cargo pieces, for one of four transport modes. Answers questions like "wie viel wiegt die Sendung frachtpflichtig" or "was ist das Volumengewicht".

For each mode, chargeable weight is the greater of the actual (scale) weight and the volumetric weight (Volumengewicht), where volumetric weight is derived from total volume using a mode-specific default divisor (overridable via volumetric_divisor):
\- air (Luftfracht): volume_cm3 / 6000 (IATA standard, 167 kg/m3)
\- courier: volume_cm3 / 5000 (common express-carrier convention, e.g. DHL/FedEx/UPS)
\- road: volume_m3 * 333 (simple volumetric "1:3" convention; does not model Lademeter/LDM-based road pricing -- for loading-metre, Stellplätze, or vehicle-fit questions, use calculate_loading_metres and check_truck_fit instead, both on this server)
\- sea_lcl (Seefracht): volume_m3 * 1000 (W/M -- weight or measurement, 1 revenue tonne per m3)

Worked example: 2 pieces, 60x40x50cm, 45 kg each, air mode -> total actual weight 90 kg, total volume 0.24 m3, volumetric weight 40 kg (240,000 cm3 / 6000) -> chargeable weight 90 kg (actual weight governs, since it exceeds the volumetric weight).

Rounding: air and courier chargeable/volumetric weight round UP to the nearest 0.5 kg (chargeable_weight_raw_kg gives the unrounded value, chargeable_weight_kg the rounded one). Road and sea_lcl are not rounded up, just reported to 1 decimal place.

Edge cases: missing or invalid mode, more than 100 pieces, or any non-positive dimension/weight/quantity returns a clear, structured explanation rather than an error stack -- never a guessed default mode or divisor.

Returns total actual weight, total volume, volumetric weight, raw and rounded chargeable weight, which one governs, the divisor used, and a one-line human-readable summary.

Input parameters:

- `mode` (string): Transport mode (required): one of "air" (Luftfracht), "road", "sea_lcl" (Seefracht), "courier". Selects the default volumetric divisor: air=6000 cm³/kg (IATA), courier=5000 cm³/kg, road=333 kg/m³ (si…
- `pieces` (array): List of cargo pieces (up to 100 line items, required, non-empty). Use quantity to combine identical pieces rather than repeating rows.
- `volumetric_divisor` (number): Optional positive override of the mode's default divisor. For air/courier this is cm³ per kg (divided into volume); for road/sea_lcl this is kg per m³ (multiplied by volume).

### `resolve_quantities` (~462 tokens)

Resolve Article Quantities

Resolves an ordered quantity of a Library article into concrete packed units (boxes/pallets), using that article's own logged packing history -- never a generic guess.

Check resolution_status first: "resolved" means units/tier are a real answer, safe to use directly. "ambiguous" means the article has more than one viable packaging family (e.g. logged both as pallets and as crates) with meaningfully different pack counts -- units and tier are both null, and alternatives lists every viable option with no default among them. When resolution_status is "ambiguous", do not select an alternative autonomously -- present the options to the user and ask which packaging family they mean; do not guess based on which one appears first. "not_found" means the article has no packed-form data logged at all -- there is nothing to resolve, alternatives is absent, and units/tier are null. needs_confirmation (boolean) is kept only for backward compatibility with callers written before resolution_status existed -- new integrations should check resolution_status.

When resolution_status is "resolved", tier is one of: "observed" (an exact match against a real logged pack), "estimated" (interpolated between two real logged points), or "verify" (extrapolated beyond the highest -- or below the lowest -- quantity ever actually logged for this article; still returns a real number, but flagged as needing a human's eyes before it's trusted).

Does not resolve prepack-table or consolidation-group quantities -- those use the same tier engine but a different lookup key (a table/group id, not a free-text article search) and are not covered by this tool.

Requires an MCP API key (Authorization: Bearer <key>) issued for a kubik.tools team. Looks the article up by article number or name within that team's own Library -- never across teams.

Input parameters:

- `api_key` (string, required): Your team's kubik.tools MCP API key (kubik_mcp_...). Required.
- `article_query` (string, required): The article number or name to search for in the Library, e.g. 'MLB1001' or 'rim holder'.
- `quantity` (number, required): The ordered quantity to resolve, in whole units of the article. Must be a positive number.

### `create_article_profile` (~471 tokens)

Create Article Profile

Creates a new article in your team's kubik.tools Library -- team-scoped from creation, visible to the whole team immediately (not a personal draft).

Two-step by design, never a silent write: call once WITHOUT confirm to get a preview of exactly what would be created (including a check for an existing article that looks like a likely duplicate); call again with confirm=true and the preview_id from the first response to actually create it. A confirmed creation can be undone within 15 minutes via undo_change -- after that, edit or delete it directly in the app.

On the confirm call, only api_key, confirm, and preview_id are actually read -- every other field is required/optional per the schema for shape-consistency but ignored if resupplied, since the values captured during the preview call are what gets created; to change any of them, call again without confirm for a fresh preview.

Do not use this to log a real packing observation for an article that already exists -- use log_pack_observation instead; this tool only creates the article record itself, never packing data. Do not skip the unconfirmed preview call even if you are confident there is no duplicate -- the duplicate check only runs on that first call, and confirm=true without a fresh preview_id will be rejected.

Required: name, supplier. Optional: article_number, hs_code (exactly 8 digits if given), description_de, description_en.

Input parameters:

- `api_key` (string, required): Your team's kubik.tools MCP API key (kubik_mcp_...). Required.
- `article_number` (string): Supplier's own article/SKU number, if known.
- `confirm` (boolean): Set true, with preview_id, to actually create the article after reviewing the preview. Omit or false for a dry-run preview only.
- `description_de` (string)
- `description_en` (string)
- `hs_code` (string): HS/tariff code, exactly 8 digits. Format-only check -- not verified against a real tariff database.
- `name` (string, required): Article name, e.g. 'Rotor hub casting'. Required.
- `preview_id` (string): The preview_id returned by the first (unconfirmed) call. Required when confirm=true.
- `supplier` (string, required): Supplier name. Required.

### `log_pack_observation` (~521 tokens)

Log Pack Observation

Logs a real, observed consolidation pack -- "these articles, at these quantities, actually packed onto N pallets at these dims/weight" -- against an existing consolidation group in your team's Library. This is ground truth: it becomes a new data point resolve_quantities and the app's own resolve flow learn from (PRINCIPLES.md P-13).

Two-step by design: call once WITHOUT confirm to preview exactly what would be logged; call again with confirm=true and the preview_id to actually log it. A confirmed log can be undone within 15 minutes via undo_change -- after that it's permanent (append-only ground truth, by design -- see PRINCIPLES.md P-17/P-18 for why).

On the confirm call, only api_key, confirm, and preview_id are actually read -- every other field is required by the schema for shape-consistency but ignored if resupplied, since the values captured during the preview call are what gets logged; to change any of them, call again without confirm for a fresh preview.

Do not use this for a single article's own packing history outside a consolidation group -- that data comes from the app's own data entry, not this tool. Do not use this to correct a mistaken past observation after the 15-minute undo window -- log a new, correct observation instead; past ones are never edited. Requires an EXISTING consolidation_groups id -- this tool cannot create a new consolidation group.

Requires an existing consolidation_groups id (from the app's Consolidation Groups screen) and each member article's number (resolved to its profile automatically).

Input parameters:

- `api_key` (string, required): Your team's kubik.tools MCP API key (kubik_mcp_...). Required.
- `confirm` (boolean): Set true, with preview_id, to actually log the observation after reviewing the preview. Omit or false for a dry-run preview only.
- `consolidation_group_id` (string, required): The id of an existing consolidation group in your team's Library. Required.
- `height_cm` (number, required)
- `length_cm` (number, required)
- `member_quantities` (array, required): The articles and quantities actually packed together, e.g. [{article_number: 'MLB1001', qty: 3}].
- `pallet_count` (integer, required): Number of pallets this pack used.
- `preview_id` (string): The preview_id returned by the first (unconfirmed) call. Required when confirm=true.
- `weight_kg` (number, required): Total gross weight, in kg.
- `width_cm` (number, required)

### `undo_change` (~221 tokens)

Undo Recent Change

Undoes a create_article_profile or log_pack_observation call, but only within 15 minutes of when it was confirmed, and only if nothing else now depends on it.

For article_profiles: refuses if any packed_forms, consolidation_group_members, or edit-history rows now reference the article (edit it or delete it manually in the app instead of undoing).

For consolidation_pack_observations: append-only ground truth past the 15-minute window, by design (PRINCIPLES.md P-17/P-18) -- undo only exists for a mistake caught immediately after logging it, never as a general edit/delete capability.

Input parameters:

- `api_key` (string, required): Your team's kubik.tools MCP API key (kubik_mcp_...). Required.
- `table` (string, required): Which kind of change to undo, matching the undo_token's origin (create_article_profile -> article_profiles, log_pack_observation -> consolidation_pack_observations).
- `undo_token` (string, required): The undo_token returned by the original confirmed create_article_profile or log_pack_observation call.

### `calculate_loading_metres` (~534 tokens)

Calculate Loading Metres

Calculates loading metres (Lademeter, LDM) -- the floor-space unit (Ladefläche) that governs European road freight -- for a list of cargo pieces, plus the equivalent number of pallet places (Palettenstellplätze, Stellplätze). Answers questions like "wie viele Lademeter" or "wieviel Platz brauche ich im Lkw".

Units: length_cm and width_cm (Länge/Breite in cm) per piece. weight_kg_per_piece (Gewicht in kg) is optional. Formula: LDM = sum(length_cm x width_cm x quantity) / reference_deck_width_cm / 100. Height is irrelevant here -- LDM is a floor-footprint metric, not a volume one (for volumetric/chargeable weight, use calculate_chargeable_weight instead).

Reference width: defaults to the industry-standard 240cm (2.4m) deck width used for a standard semi-trailer (Sattelzug, Auflieger) unless vehicle_id names one of the loadable vehicle profiles (e.g. "semi_136" = Sattelzug 13,6 m, "rigid_75" = 7,5-Tonner), in which case that vehicle's real deck width is used instead.

Worked example: 8 Europaletten/EUR-Paletten (120cm x 80cm) at the standard 240cm width = (120*80*8)/240/100 = 3.2 LDM, equivalent to 8 Palettenstellplätze (one Europalette occupies 0.4 LDM at this width). An Industriepalette (120x100cm) occupies more floor space per unit: 0.5 LDM at the same width.

Edge cases: an unknown vehicle_id returns the list of available vehicles instead of guessing -- it never silently picks one. If any piece omits weight_kg_per_piece, total_weight_kg is returned as null rather than an incomplete partial sum. Maximum 100 piece lines (use quantity to combine identical pieces).

Input parameters:

- `pieces` (array): List of cargo pieces (up to 100 line items, required, non-empty). Use quantity to combine identical pieces rather than repeating rows.
- `vehicle_id` (string): Optional vehicle profile id (e.g. "semi_136" = Sattelzug 13,6 m, "rigid_75" = 7,5-Tonner) to use that vehicle's real deck width instead of the 240cm standard. If given but not recognized, the respons…

### `check_truck_fit` (~818 tokens)

Check Truck Fit

Checks whether a list of cargo pieces fits a named vehicle by loading metres (Lademeter, LDM, Stellplätze) and, if weight is given, by payload (Zuladung, Nutzlast) too -- the two capacity limits that actually govern road freight ("passt das auf..."), not full 3D placement or Ladungssicherung (load securing).

Vehicle profiles (vehicle_id -> German name): "semi_136" = Sattelzug/Sattelauflieger 13,6 m (colloquially also "40-Tonner"), "curtain_136" = Planensattel 13,6 m, "flatbed_136" = Pritsche 13,6 m, "rigid_75" = 7,5-Tonner, "midi_12" = 12-Tonner/Koffer-Lkw, "rigid_18" = 18-Tonner, "rigid_26" = 26-Tonner (3-Achser), "drawbar_40" = Hängerzug, "van_35" = Sprinter, "cont_20"/"cont_40"/"cont_40hc" = 20-/40-/40-Fuß-HC-Container. Cargo like a Gitterbox/Rollbehälter is just another piece by footprint -- no separate cargo-type parameter needed.

Units: length_cm and width_cm per piece in centimetres (Länge/Breite in cm), weight_kg_per_piece in kilograms (Gewicht in kg, optional -- if omitted, only the floor-space/LDM check runs; the payload check is honestly skipped, not guessed).

Three modes, by what's given: (1) vehicle_id + pieces -> full fit check; if it does NOT fit, the response additionally includes recommended_vehicles -- the smallest fitting alternatives by payload, e.g. cargo that overloads a 7,5-Tonner might fit a 12-Tonner or 18-Tonner instead (suggest, never auto-pick). (2) vehicle_id alone, no pieces -> that vehicle's own payload_kg/max_ldm_m/deck_width_cm, a plain spec lookup (e.g. "wie viele Stellplätze hat ein Standard-Sattelzug" or "maximale Zuladung Sattelzug"). (3) neither given, or pieces given with no vehicle_id -> the full vehicle list, filtered to fitting ones when pieces were given. An unrecognized vehicle_id also returns the full list -- it never assumes which vehicle you mean.

Worked example: 6 Europaletten (120x80cm), 4.8 tonnes total, against vehicle_id "rigid_75" -- loading metres (2.5 LDM) are well within the 6.2m limit, but 4800kg exceeds…

Input parameters:

- `pieces` (array): List of cargo pieces (up to 100 line items), optionally omitted entirely to just look up a vehicle's specs (with vehicle_id) or list all vehicles (without). Use quantity to combine identical pieces r…
- `vehicle_id` (string): Vehicle profile id to check against or look up (e.g. "semi_136" = Sattelzug 13,6 m, "rigid_75" = 7,5-Tonner). If omitted or not recognized, the response lists every available vehicle instead of guess…

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/markopolovic-kubik-tools/mcp#diagnostics

## Score history

- 2026-08-03: 58
- 2026-08-02: 57
- 2026-08-01: 57
- 2026-07-31: 56
- 2026-07-30: 57
- 2026-07-29: 57
- 2026-07-28: 56
- 2026-07-27: 55
- 2026-07-26: 55

## Links

- Remote endpoint: https://mcp.kubik.tools/mcp
- Website: https://kubik.tools/
- Changelog RSS feed: https://verifymcp.io/servers/markopolovic-kubik-tools/mcp/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/markopolovic-kubik-tools/mcp/changelog.json
- HTML version of this page: https://verifymcp.io/servers/markopolovic-kubik-tools/mcp
