Skip to main content
Glama
homebox-mcp

homebox-mcp

by dgahagan

homebox-mcp

PyPI version License: MIT CI

An MCP server over the Homebox REST API, so an MCP client like Claude can work with your home inventory in plain language: "where is my impact driver", "what's in Tote B-3", "which warranties expire this year", "add this drill — here's a photo of the receipt and the model number". It answers questions, performs intake (create an item, attach the manual/receipt, tag and file it), manages attachments, and prints QR labels for totes and shelves — no hand-rolled curl.

Quickstart

You need a running Homebox instance (0.26+, see Requirements) and an API key from Profile → API Keys in the Homebox web UI.

Claude Code

claude mcp add homebox --scope user \
  -e HOMEBOX_URL=https://homebox.example.com \
  -e HOMEBOX_TOKEN=hb_xxxxxxxxxxxxxxxxxxxxxxxx \
  -- uvx homebox-mcp
claude mcp get homebox      # should show: Status ✔ Connected

--scope user makes it available from any project. uvx fetches and runs the published package in an ephemeral environment — nothing to install first.

Claude Desktop / generic MCP clients

Add to your client's MCP config (e.g. claude_desktop_config.json):

{
  "mcpServers": {
    "homebox": {
      "command": "uvx",
      "args": ["homebox-mcp"],
      "env": {
        "HOMEBOX_URL": "https://homebox.example.com",
        "HOMEBOX_TOKEN": "hb_xxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

From a clone (no PyPI)

The module carries PEP 723 inline dependencies, so it also runs standalone with uv run --script — uv resolves mcp, httpx, pillow, and pillow-heif into an ephemeral venv on first run. Instead of env vars, drop credentials in a .env file next to the module:

git clone https://github.com/dgahagan/homebox-mcp
cd homebox-mcp
cp .env.example .env        # .env is gitignored
chmod 600 .env
# edit .env: HOMEBOX_URL + HOMEBOX_TOKEN

Then register the absolute path to the module (or to server.py, a compatibility shim kept for older registrations):

claude mcp add homebox --scope user -- \
  uv run --script /path/to/homebox-mcp/homebox_mcp.py

The server reads config from the environment, falling back to the sibling .env (resolved relative to the script, so the absolute-path invocation still finds it). The credential never enters the MCP config — it stays in the gitignored .env.

Related MCP server: homekit-cli

Requirements

  • Homebox 0.26 or newer — the actively maintained sysadminsmedia fork at homebox.software. This server speaks the unified entities API introduced in 0.26. Older instances use a different API (/items, /locations, /labels) and are rejected on the first tool call with a clear error rather than failing cryptically.

  • An API key — Homebox Profile → API Keys (the token starts with hb_).

  • uv, or any Python ≥ 3.11 environment where you install homebox-mcp yourself.

  • MCP SDK 2.x (mcp>=2,<3), pulled in automatically. uvx/pipx build an isolated environment, so this needs no action. If you are installing into an environment already pinned to mcp<2, stay on homebox-mcp==1.0.1.

Configuration

All configuration is via environment variables (or the sibling .env for the clone workflow):

Variable

Required

Purpose

HOMEBOX_URL

yes

Base URL of your Homebox instance (no trailing slash).

HOMEBOX_TOKEN

yes

Homebox API key (hb_…).

HOMEBOX_ALIAS_FIELD

no

Name of one custom field to treat as a stable item identifier — items can be resolved by it, summaries surface it, and field_index defaults to it. Unset = resolve by assetId/name only. See Conventions.

HOMEBOX_LABEL_DIR

no

Where generate_label / qrcode save output. Default: current working directory.

Tools

~39 tools. Reads accept a fuzzy identifier (assetId, alias field, exact name, then first keyword match). Write tools require an exact identifier (assetId, alias field, or exact name) — a typo or an ambiguous match is refused rather than mutating the wrong item. An assetId must be in the full 000-012 form: a bare 12 is matched as a name or alias, never as asset 000-012. Locations are referenced by name or /-separated path (e.g. Garage/Shelf 1) to disambiguate duplicate names.

Read / Q&A

Tool

Purpose

search_items(query?, tags?, limit=20)

Search items by keyword and/or tag names (AND of both); returns each with assetId, location, and the alias field.

get_item(identifier)

Full detail for one item: location path, identity, purchase, warranty, custom fields, tags, attachments.

list_locations()

The full location tree as an indented outline.

location_contents(location, recursive=False)

Items directly in a location plus its sub-location names; recursive=True walks the whole subtree and returns every nested item with its full location path.

list_tags(detail=False)

All tag (label) names; detail=True returns full objects (description, color, icon, parent tag).

warranties_expiring(before?, after?, lifetime=False)

Items whose warranty expires in after…before (after defaults to today, excluding already-expired); lifetime=True lists lifetime-warranty items.

Create & intake

Tool

Purpose

create_item(name, location?, quantity=1, manufacturer?, model?, serial?, purchase_price?, purchase_date?, purchase_from?, warranty_expires?, notes?, fields?, tags?)

Create and enrich an item in one call. fields is a dict typed by JSON value (string→text, number→number [integer-coerced], bool→boolean); tags must already exist. location resolves as in move_item: a location name or path, or a container item (name, path or assetId). Returns the new assetId.

import_csv(csv_text)

Bulk-create items and locations from a Homebox CSV in one multipart request. HB.location auto-creates the path hierarchy; recognizes HB.name, HB.tags, HB.quantity, HB.serial_number, HB.model_number, HB.manufacturer, HB.notes, HB.purchase_*, HB.warranty_expires, HB.field.<name>.

create_location(name, parent?, description?)

Create a location (tote/bin/shelf) to bootstrap a new storage spot; description doubles as a contents manifest.

barcode_lookup(code)

UPC/EAN → name/manufacturer/model (optional, for boxed goods).

duplicate_item(identifier, copy_attachments=False, copy_custom_fields=True, copy_maintenance=False, prefix="Copy of ")

Duplicate an item ("I bought a second one"). Copied custom fields include the alias field verbatim — give the copy its own value after.

Edit

All write tools resolve by exact identifier and preserve everything you don't touch (a full-body PUT that echoes the rest of the item back — see gotchas).

Tool

Purpose

set_item(identifier, new_name?, description?, notes?, quantity?, purchase_price?, purchase_date?, purchase_from?, insured?, archived?, fields?)

General item editor: rename, notes, quantity, purchase info, insured/archived flags, custom fields. Quantity-only edits use a partial PATCH.

move_item(identifier, location)

Move an item into a location or into another item (e.g. a lens into Camera Bag). The destination is a location name or path, as before; only if no location matches is it looked up as an item by exact name or path (e.g. Office/Camera Bag), or give the item's assetId. A name matching more than one is refused, and so is a location as the item to move — use set_location (partial PATCH — nothing else changes).

set_warranty(identifier, expires?, lifetime?, details?)

Set warranty end date, lifetime flag, and terms summary.

set_identity(identifier, manufacturer?, model_number?, serial_number?)

Set manufacturer / model / serial (e.g. after a nameplate photo reveals them).

set_fields(identifier, fields)

Create or overwrite custom fields (upsert; typed by JSON value type).

set_tags(identifier, tags, mode="add")

Add / remove / replace tags on an item; unknown tag names are auto-created (partial PATCH).

set_tag(name, new_name?, description?, color?, icon?, parent?, clear_parent=False)

Edit a tag's own metadata (rename, color, icon, parent tag for grouping) — not what's tagged on an item. Creates the tag if new.

set_location(location, new_name?, parent?, clear_parent?, description?, notes?, tags?, tags_mode?, entity_type?, asset_id?, fields?)

General location editor: rename, move (or clear_parent to root), tags, notes, entity type, assetId, custom fields.

mark_sold(identifier, sold_price?, sold_to?, sold_date?, sold_notes?, clear=False)

Record a sale (price/buyer/date/notes) or clear=True to un-sell; pair with set_item(archived=True) to retire the item.

Maintenance log

Tool

Purpose

log_maintenance(identifier, name, description?, completed_date?, scheduled_date?, cost?)

Add an entry — "changed the mower oil today" (completed) or "sharpen blades in spring" (scheduled).

list_maintenance(identifier?, status="both")

Entries for one item, or across the whole inventory ("what maintenance is due?"); status = scheduled / completed / both.

set_maintenance(entry_id, ...)

Edit an entry — e.g. mark a scheduled one completed by setting completed_date.

delete_maintenance(entry_id, confirm)

Delete one entry (confirm = its exact name).

Reporting

Tool

Purpose

inventory_stats(by="totals", start?, end?)

Totals (counts, total value, warranty count), value by location or tag, or purchase-price over time — the cheap way to answer "what's my inventory worth?".

export_csv(save_to?)

Export the whole inventory as a Homebox CSV (complement of import_csv; quick backup).

list_custom_fields(field?)

Discover the custom-field schema in use: all field names, or every distinct value of one field.

Attachments

Tool

Purpose

attach_document(identifier, source, title, doc_type="manual", primary=False)

Attach a file (local path or http(s) URL) to an item, or to a location by name as a fallback. doc_type e.g. manual/receipt/warranty/photo; primary=True makes a photo the entity's primary image (e.g. a location's "this is the spot" wayfinding shot).

list_attachments(identifier)

List an item's or location's attachments with their ids (the handle the other attachment tools need).

get_attachment(identifier, attachment_id, save_to)

Download one attachment to a local path so its content (e.g. a manual) can be read.

rename_attachment(identifier, attachment_id, title?, doc_type?, primary?)

Update an attachment's title, type, or primary flag.

Uploads auto-convert HEIC/HEIF (iPhone photos) to JPEG so Homebox always stores a browser-renderable image, and sanitize / in titles (Homebox treats a title as a path and would otherwise truncate it).

Deletes (confirm-gated)

Every delete requires confirm to equal the target's exact name and carries the MCP destructiveHint annotation, so clients prompt before running them.

Tool

Purpose

delete_item(identifier, confirm)

Permanently delete an item and its attachments. No undo.

delete_location(location, confirm, confirm_nonempty=False)

Delete a location. A non-empty one is refused unless confirm_nonempty=True: sub-locations cascade (are deleted); items are orphaned to the top level (not deleted).

delete_tag(name, confirm)

Delete a tag itself (removed from every tagged item; the items survive).

delete_attachment(identifier, attachment_id, confirm)

Delete one attachment (confirm = its exact title).

Labels & finalize

Tool

Purpose

generate_label(identifier, kind="location", out_dir?)

Save a printable label PNG (QR + readable name) for a location, item, or asset. Saves to $HOMEBOX_LABEL_DIR (else CWD).

qrcode(data, out_dir?)

Save a raw QR JPEG for arbitrary data (prefer generate_label for totes — it adds the name).

finalize_photos()

Finalize after a bulk photo attach: set missing primary images, then generate missing thumbnails.

field_index(field_name?)

{field_value: assetId} index over a custom field (default $HOMEBOX_ALIAS_FIELD) — a one-pass dedupe index before a bulk import, since q doesn't index custom fields.

How it works (and Homebox 0.26 gotchas)

The value of this server is as much in what it works around as in what it exposes. These are hard-won behaviors of the 0.26 entities API:

  • Items and locations are unified "entities" (/v1/entities); a location is an entity whose entity-type has isLocation=true. A new item with no entityTypeId lazily gets a default Item type.

  • GET /entities returns non-location entities only. Location children never appear in /entities results, even with parentIds — sub-locations come from the entity tree (/entities/tree). location_contents merges both sources, and delete_location's emptiness check counts items and sub-locations.

  • Deleting a non-empty location cascades sub-locations but orphans items. Force-deleting a location (confirm_nonempty=True) deletes its sub-locations with it, but its items survive, re-parented to the top level. Move items out first if you don't want them loose.

  • List/search responses are lightweight summaries — they omit fields and have an empty assetId. The server fetches full detail (GET /entities/{id}) before returning assetId/alias, so search_items/get_item are accurate.

  • q does not index custom fields. Resolving by an alias-field value uses a scan fallback (one detail fetch per item). Resolving by assetId (via /v1/assets/{id}) or name is cheaper — prefer assetId when you have it (e.g. the value create_item returns).

  • PUT clears omitted fields, including assetId. Every write tool rebuilds a full body from a fresh GET (_preserve_item_body) and overrides only the targeted keys. create_item assigns the asset ID after enrichment so it survives.

  • Attachment titles are basenamed on /. Homebox treats a title as path-like, so "front 3/4 view" silently stores as "4 view". The server sanitizes /→- in attach titles.

  • Number custom fields are integer-typed. A float numberValue (e.g. 17000.0, which the MCP SDK produces from a float-typed arg) makes the API 500 "Unknown Error". The server coerces number values to int; pass whole numbers.

  • Custom-field values are type-keyed (textValue / numberValue / booleanValue). The server rebuilds each field by its declared type — coercing everything to textValue (an earlier bug) silently wiped numeric/boolean fields on any PUT.

  • Pagination. Entity listings over one page (200) were silently truncated; the server pages through to the reported total, so search, dedupe, and warranty sweeps stay correct on large inventories.

Conventions (optional)

Homebox's built-in assetId is a stable numeric handle, but it isn't something you'd type from memory. If you want a human-meaningful stable identifier — useful for cross-referencing items with receipts, spreadsheets, or another system — add a custom field (say item_id) holding a slug like makita-xdt131 and point HOMEBOX_ALIAS_FIELD at it. Then:

  • items resolve by that slug in every read and write tool,

  • search_items/get_item summaries surface it, and

  • field_index() defaults to it, giving you a one-call dedupe map before a bulk import.

This is entirely optional — leave HOMEBOX_ALIAS_FIELD unset and items resolve by assetId or name only. Nothing about the field name is special; any single custom field works.

Companion scripts

Two standalone helper scripts ship in the repo (not MCP tools):

  • annotate_location_photos.py turns one wide photo of a shelf bank into one boxed/labeled image per shelf (--rows N), and can upload each straight to its Homebox location with --upload. See its --help.

  • heic2jpg.py converts HEIC/HEIF (iPhone photos) to JPEG for ad-hoc use (./heic2jpg.py FILE...). Note the attach tools already auto-convert HEIC on upload, so this is only needed to feed HEIC frames to a vision step before upload.

Both rely on pillow-heif, which bundles libheif — there's no system package to install.

Security

  • API key handling. In the clone workflow the key lives in .env, which is gitignored and should be mode 600 (chmod 600 .env). Never commit it. In the uvx workflow it's passed through your MCP client's config — treat that file as a secret too.

  • Key rotation. Rotating the Homebox HBOX_AUTH_API_KEY_PEPPER invalidates every issued key — mint a new one and update your config.

  • Confirm-gated deletes. All four delete tools require confirm to equal the target's exact name and carry the MCP destructiveHint annotation, so a well-behaved client prompts before any destructive call.

  • Use HTTPS for any remote Homebox instance — the API key is sent on every request in the Authorization header.

Development

git clone https://github.com/dgahagan/homebox-mcp
cd homebox-mcp

# Run the test suite (httpx mocked with respx — no live instance needed)
uv run --with pytest --with respx --with . pytest

# Lint
uv run --with ruff ruff check .

The server is a single module (homebox_mcp.py) with PEP 723 inline dependencies. See CONTRIBUTING.md for setup and PR expectations, and CHANGELOG.md for release notes.

License

MIT © Dan Gahagan

Available Tools

39 tools
attach_documentA

Attach a document to an item OR a location. source is a local file path or an http(s) URL (downloaded then uploaded). doc_type is e.g. manual, attachment, warranty, receipt, photo. identifier is assetId/alias/name for an item, or a location name/path (tried as a fallback if no item matches). Set primary=True to make a photo the entity's primary image — e.g. a "this is the spot" wayfinding photo on a shelf/tote location (doc_type="photo").

Inputs: title (required), source (required), identifier (required), primary, +1 more.

barcode_lookupA
Read-only

Look up a UPC/EAN barcode → name/manufacturer/model (optional path for boxed goods). Thin wrapper over GET /products/search-from-barcode.

Inputs: code (required).

create_itemA

Create an inventory item and enrich it in one call.

location is where the item goes, resolved as in move_item: a location name or /-separated path (must exist; use list_locations), or a container item, e.g. 'Camera Bag', 'Office/Camera Bag' or its assetId ('000-012'). A location wins over an item with the same name. tags are tag names (must already exist; use list_tags). fields maps custom-field name -> value; each value's JSON type picks the field type (string -> text, number -> number [integer-coerced], true/false -> boolean). Returns the new assetId and id.

Inputs: name (required), tags, model, notes, +9 more.

create_locationA

Create a LOCATION entity (e.g. a new tote/bin/shelf) to bootstrap a new storage spot. parent is an existing location name or /-separated path (optional); description is optional free text, e.g. a contents summary (≤1000 chars). Returns the new location id. For deep paths, prefer import_csv's HB.location auto-create.

Inputs: name (required), parent, description.

delete_attachmentA
Destructive

PERMANENTLY delete one attachment from an item or location (see list_attachments for ids). confirm must equal the attachment's exact title.

Inputs: confirm (required), identifier (required), attachment_id (required).

delete_itemA
Destructive

PERMANENTLY delete an item (assetId / alias field / exact name), including its attachments. confirm must equal the item's exact name. There is no undo.

Inputs: confirm (required), identifier (required).

delete_locationA
Destructive

PERMANENTLY delete a location (name or /-separated path). confirm must equal the location's exact name. A location that still contains items or sub-locations is refused unless confirm_nonempty=True — sub-locations are deleted with it, and its items are ORPHANED to the top level (not deleted). There is no undo.

Inputs: confirm (required), location (required), confirm_nonempty.

delete_maintenanceA
Destructive

PERMANENTLY delete one maintenance entry (see list_maintenance for ids). confirm must equal the entry's exact name.

Inputs: confirm (required), entry_id (required).

delete_tagA
Destructive

PERMANENTLY delete a tag itself (it is removed from every tagged item; the items survive). confirm must equal the tag's exact name.

Inputs: name (required), confirm (required).

duplicate_itemA

Duplicate an existing item (assetId / alias field / exact name), e.g. "I bought a second one". prefix is prepended to the new item's name. Copies custom fields by default; attachments and maintenance log only on request. NOTE: copied custom fields include the alias field verbatim — if you use one, give the copy its own value via set_fields right after. Returns the new item's id and assetId.

Inputs: identifier (required), prefix, copy_attachments, copy_maintenance, +1 more.

export_csvA

Export the whole inventory as a Homebox CSV (the complement of import_csv; also a quick backup). Saves to save_to (file path or directory; default: homebox-export.csv in the current directory) and returns the path and row count.

Inputs: save_to.

field_indexA
Read-only

Return {field_value: assetId} for every entity that has the named custom field — a one-pass index for DEDUPE before a bulk import (q does not index custom fields, so this scans every entity). field_name defaults to $HOMEBOX_ALIAS_FIELD. assetId may be empty for un-asset'd rows. Deliberately uncapped: a truncated dedupe index causes duplicates, so expect a large result on a large inventory.

Inputs: field_name.

finalize_photosA
Idempotent

Finalize after a bulk photo attach: ensure every entity with photos has a primary image, then generate any missing thumbnails. (Wraps the set-primary-photos and create-missing-thumbnails actions, which are always run as a pair.)

Inputs: no named parameters.

generate_labelA

Save a printable Homebox label PNG (QR + readable name) for a location or item, e.g. to stick on a tote/bin. kind is "location", "item", or "asset". For location/item, identifier is a name or slug (resolved to an id); for asset it's the assetId (e.g. 000-028). Saves to out_dir (default: $HOMEBOX_LABEL_DIR, else the current directory). Returns the saved file path.

Inputs: identifier (required), kind, out_dir.

get_attachmentA

Download one attachment (see list_attachments for ids) to a local path, so its content — e.g. an attached manual or receipt — can be read. save_to is a directory (keeps a name based on the title) or a full file path.

Inputs: save_to (required), identifier (required), attachment_id (required).

get_itemA
Read-only

Get full detail for one item by assetId (e.g. 000-028), alias custom field, or name (fuzzy fallback: first keyword match). Includes location path, serial, model, purchase, warranty, custom fields, tags, and attachments.

Inputs: identifier (required).

import_csvA

Bulk-create items and locations from a Homebox CSV (multipart import).

This is the bulk creator for the photo-intake pipeline — one request imports everything, avoiding ~4 API calls per item. Recognized columns: HB.name, HB.location (path e.g. "Garage/Loft" — AUTO-CREATES the hierarchy), HB.tags (must already exist; see list_tags), HB.quantity, HB.serial_number, HB.model_number, HB.manufacturer, HB.notes, HB.purchase_price, HB.purchase_from, HB.purchase_time, HB.warranty_expires, HB.field. (custom fields). A location-only row (HB.location set, contents described elsewhere) creates just the location. After import, call finalize_photos if you attached photos. Returns the count of data rows submitted.

Inputs: csv_text (required).

inventory_statsA
Read-only

Inventory statistics — the cheap way to answer "what's my inventory worth?" without scanning items. by is: totals — counts (items/locations/tags/users), total purchase price, items with warranty; locations — total value per location; tags — total value per tag; purchase-price — value over time (optional YYYY-MM-DD start/end).

Inputs: by, end, start.

list_attachmentsA
Read-only

List an item's (or location's) attachments with their ids — the handle needed by get_attachment / rename_attachment / delete_attachment. identifier is assetId / alias field / name, or a location name/path.

Inputs: identifier (required). Returns: result

list_custom_fieldsA
Read-only

Discover the custom-field schema actually in use: with no arg, all custom-field NAMES across the inventory; with field, the distinct VALUES of that field ({"total", "values"}, capped at limit). Useful before set_fields/field_index on an unfamiliar instance.

Inputs: field, limit.

list_locationsA
Read-only

Return the full location tree as an indented outline.

Inputs: no named parameters. Returns: result

list_maintenanceA
Read-only

List maintenance entries — for one item (assetId / alias field / name) or, with no identifier, across the whole inventory ("what maintenance is due?"). status is "scheduled" (upcoming), "completed", or "both".

Inputs: status, identifier. Returns: result

list_tagsA
Read-only

List all tag (label) names. Set detail=True to instead return full tag objects (name, description, color, icon, parent tag name) for auditing tag setup — pair with set_tag to edit any of these.

Inputs: detail.

location_contentsA
Read-only

List what is in a location (e.g. a tote or shelf), by location name.

Returns the items directly in that location plus any sub-locations (their names only — not their contents). Set recursive=True to instead walk the whole subtree and return every item nested under it, each tagged with its full location path; use this when a location (e.g. Garage, Basement) has sub-locations you also want the contents of, to avoid querying each one by hand. location is a name or /-separated path (for duplicate names).

Inputs: location (required), max_items, recursive.

log_maintenanceA

Add a maintenance-log entry to an item (assetId / alias field / exact name) — e.g. "changed the mower oil today" (completed_date) or "sharpen blades in spring" (scheduled_date). Dates are YYYY-MM-DD; cost is a number. Returns the new entry's id.

Inputs: name (required), identifier (required), cost, description, +2 more.

mark_soldA
Idempotent

Record that an item was sold (assetId / alias field / exact name): price, buyer, YYYY-MM-DD date, notes — only the args you pass are set. clear=True instead erases all four sold fields (un-sells the item). Other fields are preserved. Pair with set_item(archived=True) if the item should also leave active inventory.

Inputs: identifier (required), clear, sold_to, sold_date, +2 more.

move_itemA
Idempotent

Move an item into a location or into another item (assetId / alias field / exact name).

location is the destination's name or /-separated path — a location (see list_locations) or a container item, e.g. a lens into 'Camera Bag' or 'Office/Camera Bag' — or a container item's assetId ('000-012'). A location wins over an item with the same name; reach the item with a longer path or its assetId. A name that matches more than one location, or more than one item, is refused. Uses a partial PATCH, so nothing else on the item changes.

Inputs: location (required), identifier (required).

qrcodeA

Save a raw QR-code JPEG encoding arbitrary data (e.g. a deep link). For tote labels prefer generate_label (adds the readable name). Saves to out_dir (default: $HOMEBOX_LABEL_DIR, else the current directory). Returns the saved file path.

Inputs: data (required), out_dir.

rename_attachmentA
Idempotent

Update an attachment's title, type (manual/attachment/warranty/receipt/ photo), or primary flag (see list_attachments for ids). Only the args you pass change; the rest is re-sent as-is.

Inputs: identifier (required), attachment_id (required), title, primary, +1 more.

search_itemsA
Read-only

Search inventory items by name/keyword and/or by tag names (AND of both when both given — e.g. everything tagged "power-tool").

Returns items (not locations) with their immediate location, assetId, and the alias custom field (if $HOMEBOX_ALIAS_FIELD is configured). Use get_item for full detail on one result.

Inputs: tags, limit, query. Returns: result

set_fieldsA
Idempotent

Create or update custom fields on an existing item (assetId / alias field / exact name).

fields maps custom-field name -> value; each value's JSON type picks the field type (string -> text, number -> number [integer-coerced — the API 500s on float number values], true/false -> boolean). Upsert semantics: named fields are created or overwritten; other fields are preserved.

Inputs: fields (required), identifier (required).

set_identityA
Idempotent

Set manufacturer/model/serial on an existing item (assetId / alias field / exact name).

Only the args you pass change; other fields are preserved. Use when a nameplate/label photo reveals a serial number or a model-number correction after the item was created.

Inputs: identifier (required), manufacturer, model_number, serial_number.

set_itemA
Idempotent

General item editor (assetId / alias field / exact name): rename, edit description/notes/quantity, purchase info, insured/archived flags, and custom fields in one call.

Only the args you pass are changed. Quantity-only changes go via a partial PATCH; anything else uses a full-body PUT that preserves the rest of the item (the 0.26 PUT-clears gotcha). fields maps custom-field name -> value, typed by JSON type (see set_fields). To move an item use move_item; for warranty/identity/tags see set_warranty/set_identity/set_tags.

Inputs: identifier (required), notes, fields, insured, +7 more.

set_locationA
Idempotent

Edit a LOCATION's metadata (find it by current name or /-path): rename, description (e.g. a contents manifest), notes, tags, custom fields (values typed by JSON type). Only the args you pass change; other fields are preserved. parent moves it under another location; clear_parent=True moves it to the root. entity_type (e.g. "Item") converts a mis-created entity — rare. asset_id overrides the auto-assigned assetId.

Inputs: location (required), tags, notes, fields, +7 more.

set_maintenanceA
Idempotent

Edit a maintenance entry (see list_maintenance for ids) — e.g. mark a scheduled entry completed by setting completed_date. Only the args you pass change; the rest of the entry is re-sent as-is (the update is a full PUT).

Inputs: entry_id (required), cost, name, description, +2 more.

set_tagA
Idempotent

Create or edit a tag's own metadata — NOT what's tagged on an item (see set_tags for that). Matches name case-insensitively against list_tags; creates the tag if it doesn't exist yet. Only the args you pass are changed. parent nests this tag under another (existing) tag name, for grouping related tags in the Homebox UI (e.g. several condition-* tags under a "condition" parent); pass clear_parent=True to un-nest it. Use list_tags(detail=True) to see current tag metadata first.

Inputs: name (required), icon, color, parent, +3 more.

set_tagsA
Idempotent

Add, remove, or replace tags on an existing item (assetId / alias field / exact name).

mode is "add" (default — merges with the item's existing tags), "remove" (drops just the named tags, keeps the rest), or "replace" (item ends up with exactly these tags, nothing else). Tag names are matched case-insensitively against list_tags and auto-created if they don't exist yet. Everything else on the item is untouched (partial PATCH).

Inputs: tags (required), identifier (required), mode.

set_warrantyA
Idempotent

Set warranty info on an existing item (assetId / alias field / exact name).

expires is a YYYY-MM-DD date (warranty end), lifetime flags a lifetime warranty, details is a short terms summary (e.g. "limited lifetime, test/measurement instruments excluded"). Only the args you pass change; other fields are preserved.

Inputs: identifier (required), details, expires, lifetime.

warranties_expiringA
Read-only

List items whose warranty expires in a date window, or items with a lifetime warranty.

before/after are ISO dates (YYYY-MM-DD): returns items with after <= warrantyExpires <= before. after defaults to TODAY, so already-expired warranties are excluded unless you pass an earlier after. Set lifetime=True to instead list items flagged as lifetime warranty (before/after ignored). Useful for "which warranties expire this year".

Inputs: after, before, lifetime. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 39 tools

    Disambiguation3/5

    The item-editing family overlaps substantially: set_item explicitly handles custom fields too, duplicating set_fields, and set_identity/set_warranty/set_tags/move_item/mark_sold all edit the same item with subtle boundaries. set_tag vs set_tags is also easily confused despite the explicit cross-reference. Descriptions steer an agent toward the right tool, but the boundaries are not crisp.

    Naming Consistency4/5

    The dominant convention is verb_noun (set_location, delete_attachment, import_csv, list_maintenance), used consistently across most entities. A handful of noun-first outliers (field_index, barcode_lookup, warranties_expiring, qrcode, inventory_stats, location_contents) and singular/plural wobble (set_tag vs set_tags, get_attachment vs list_attachments) are minor deviations that don't hurt readability.

    Tool Count2/5

    39 tools is heavy for an inventory server, well beyond the 15-tool sweet spot. The broad domain (items, locations, tags, attachments, maintenance, labels, CSV, stats) justifies many tools, but several granular item setters (set_fields, set_identity, set_warranty) could be folded into set_item, and utility tools like qrcode/finalize_photos inflate the surface.

    Completeness4/5

    Near-complete CRUD/lifecycle coverage exists for items (create/get/set/delete/duplicate/move/sold), locations, tags, attachments, and maintenance, plus CSV import/export, label generation, stats, and custom-field discovery. Minor gaps remain: no way to delete a custom-field definition, no plain list_items (only search_items), and no user management.

    Maintenance

    ActivityMaintained
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for managing Homebox inventory via AI assistants, enabling item management, location organization, and label categorization.
      4
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      An MCP server that provides tools for inspecting and controlling Apple HomeKit accessories, scenes, automations, and more via the HomeClaw app, enabling natural language interaction with your smart home.
      3 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      An MCP server that gives AI assistants real-time access to your homelab infrastructure. It enables querying node status, managing Docker containers, controlling Proxmox VMs, and inspecting OPNsense firewall state through natural conversation.
      2
      MIT
    • F
      license
      C
      quality
      D
      maintenance
      An MCP server that exposes Homebox inventory management as tools for AI agents, enabling search, add, update, delete products, locations, tags, and maintenance entries.
      17
      2
      -