Skip to main content
Glama
mcp-server-snipe-it

mcp-server-snipe-it

by borgels

mcp-server-snipe-it

MCP server for the Snipe-IT asset management REST API (v1, tested against Snipe-IT v8.6.x).

Tools

Read (always on): snipeit_list_assets (search, meta-status, model/category/location filters, audit/checkin due-lists), snipeit_get_asset (by id/tag/serial + licenses/history/assigned), snipeit_list_entities + snipeit_get_entity (licenses incl. seats, accessories incl. checkedout rows, consumables, components, users incl. their assets, locations, status labels, categories, manufacturers, models, companies, departments, suppliers, custom fields, fieldsets, kits, maintenances, depreciations, groups), snipeit_get_activity_report, snipeit_search_capabilities.

Write (opt-in via SNIPEIT_ENABLE_WRITES=true): snipeit_create_asset, snipeit_update_asset, snipeit_create_entity, snipeit_update_entity (all PATCH semantics — PUT is never used because it nulls omitted fields), snipeit_checkout, snipeit_checkin, snipeit_audit_asset.

Per-user auth (opt-in via SNIPEIT_PER_USER_AUTH=true): snipeit_connect, snipeit_status, snipeit_disconnect — see Authentication.

Deliberately absent: delete tools (no API restore for most entities), settings/backup endpoints, LDAP sync, import processing.

Related MCP server: snipeit-mcp

Filtering

snipeit_list_entities takes a filters object that goes straight to the index endpoint, so narrowing happens server-side instead of by paging everything:

{ "entity": "licenses",     "filters": { "expires": true } }
{ "entity": "licenses",     "filters": { "company_id": 3, "maintained": true } }
{ "entity": "users",        "filters": { "department_id": 2, "activated": true } }
{ "entity": "maintenances", "filters": { "asset_id": 17, "completed": false } }

The allowed keys per entity are transcribed from the $request->filled('…') guards in each Snipe-IT controller's index(), so they are what the API really honours. An unknown key is an error, not a no-op — Snipe-IT ignores parameters it does not recognise, which would otherwise hand back an unfiltered list with a 200 and look like a filtered answer. The error names the valid keys. search, sort, order, limit and offset have their own arguments and are refused inside filters.

Custom fields

Custom-field values live on the asset, keyed by db_column_name (e.g. _snipeit_mac_address_1) — never by display name, which silently does nothing. Discover the keys first:

snipeit_get_entity  entity=fieldsets  id=<id>  include=fields

Each field comes back with db_column_name, format (the server-side validation regex), type, required, field_encrypted, and field_values_array (the allowed values for a dropdown). Put that key in the payload of snipeit_create_asset or the patch of snipeit_update_asset.

Kits

Kits can be listed and inspected, but the API has no kit-checkout endpoint — only the web UI hands out a whole kit in one action. Through the API: read the kit's contents (entity=kits include=models|licenses|accessories|consumables), pick an available asset per model, then call snipeit_checkout per item. There is no atomicity, so check each result rather than assuming the whole kit went out.

Gotchas encoded in the server

  • Snipe-IT returns HTTP 200 for business failures — the client throws on the status:"error" envelope instead of trusting the status code.

  • Snipe-IT also ignores query parameters it does not recognise, so a mistyped filter is indistinguishable from no filter in the response. Hence the per-entity allowlist.

  • Accessory and component checkin uses pivot-row ids, not entity ids (fetch them via snipeit_get_entity with include=checkedout / include=assets).

  • Consumable checkout is irreversible; license-seat checkin on a non-reassignable license burns the seat. Tool descriptions warn about both.

  • Lists are {total, rows} with limit/offset (server caps limit at 500). Default API throttle is 120 req/min (HTTP 429 + Retry-After).

Authentication

Two modes. SNIPEIT_BASE_URL is required in both.

Shared token (default)

Set SNIPEIT_API_TOKEN to one personal access token. Simple, and right for stdio or a single operator — but note what it means on a shared endpoint: every caller acts as the token's owner, with that account's permissions, and Snipe-IT's own action log credits every change to them. If that token belongs to a superuser, everyone reaching the server is a superuser, and the asset history tells you nothing about who actually did what.

Per-user auth

Each user enrols their own Snipe-IT token, so Snipe-IT applies their own permissions and records their name in its history.

SNIPEIT_PER_USER_AUTH=true
SNIPEIT_TRUST_FORWARDED_USER=true
MCP_HTTP_TOKEN=<shared secret the gateway sends as Bearer>
SNIPEIT_ENCRYPTION_KEY=<min 16 chars>
SNIPEIT_STORE_PATH=/data/store.json
SNIPEIT_PUBLIC_BASE_URL=https://snipe-it.example.com
# SNIPEIT_API_TOKEN deliberately unset

Adds three tools: snipeit_connect, snipeit_status, snipeit_disconnect. The flow:

  1. The user calls snipeit_connect and gets a single-use link, valid 10 minutes, bound to their identity.

  2. They open it — the page shows "Linking for ", the gateway identity the link is bound to — tick a box confirming that identity is theirs, and paste a token they created in Snipe-IT under their own profile → Manage API Keys. The token goes from their browser straight to the server, so it never enters the conversation transcript — a Snipe-IT token is bearer-equivalent to the whole account and would otherwise sit in history forever.

  3. The server calls GET /users/me with that token before storing it, so a wrong or revoked token is rejected on the spot and the page can confirm which account was linked.

  4. Tokens are encrypted at rest with AES-256-GCM, one row per verified identity.

Requirements and sharp edges:

  • Identity comes only from the gateway. X-MCP-User is read only when SNIPEIT_TRUST_FORWARDED_USER=true, and never from anything the MCP client controls. Only enable it behind a gateway that sets the header from a validated token and strips any client-supplied copy — otherwise a caller can name any identity and read that person's data.

  • MCP_HTTP_TOKEN is required with forwarded-user trust. The HTTP server refuses to start when SNIPEIT_TRUST_FORWARDED_USER=true and MCP_HTTP_TOKEN is empty, since without a shared bearer anything that can reach the port could assert an identity. The bearer is compared in constant time.

  • No fallback. An un-enrolled user gets NOT_CONNECTED, never the shared token, even if SNIPEIT_API_TOKEN happens to be set. A fallback would hand them borrowed rights, which is the failure this mode exists to remove.

  • /snipeit/enroll must be reachable by the user's browser, bypassing the MCP gateway (it cannot carry the gateway bearer). Route /snipeit/* on SNIPEIT_PUBLIC_BASE_URL straight to the container. Its security is the single-use, user-bound state token.

  • Persist SNIPEIT_STORE_PATH on a volume, or every user re-enrols on restart. Keep SNIPEIT_ENCRYPTION_KEY stable too — change it and every stored token becomes undecryptable.

  • Per-user auth separates permissions and attribution, not companies. Unless Snipe-IT's Full Multiple Companies Support is on, every user still sees every company's items — exactly as they would in the web UI.

Configuration

See .env.example for the full list.

Run

npm install
npm run dev          # stdio
npm run dev:http     # streamable HTTP on :3000/mcp (stateless)
npm test

Docker images: ghcr.io/borgels/mcp-server-snipe-it (published on push to main).

Available Tools

13 tools
snipeit_audit_assetAudit Asset (Snipe-IT)A

Record a physical audit of an asset — append-only log entry; optionally set location and next audit date. Requires write access.

Inputs: id (required), note, locationId, nextAuditDate.

snipeit_checkinCheck In (Snipe-IT)A

Check in an asset, accessory, component, or license seat (consumables cannot be checked in). GOTCHA: for accessory/component the id is the PIVOT-ROW id from snipeit_get_entity include=checkedout / include=assets — not the entity id. License checkin needs seatId; on a non-reassignable license this permanently burns the seat. Requires write access.

Inputs: id (required), type (required), note, seatId, +3 more.

snipeit_checkoutCheck Out (Snipe-IT)A

Check out to someone/something: asset → user/asset/location; accessory → user (or asset/location); consumable → user (IRREVERSIBLE — confirm with the user first); component → asset; license → user/asset (optionally a specific seatId). Requires write access.

Inputs: id (required), type (required), targetId (required), note, +5 more.

snipeit_create_assetCreate Asset (Snipe-IT)A

Create a hardware asset. Minimum: model_id and status_id (asset_tag too unless auto-increment is enabled). Requires write access on this instance.

Inputs: payload (required).

snipeit_create_entityCreate Entity (Snipe-IT)A

Create a non-asset entity (user, license, accessory, consumable, component, location, category, model, supplier, maintenance, …). Requires write access.

Inputs: entity (required), payload (required).

snipeit_get_activity_reportGet Activity Report (Snipe-IT)B
Read-onlyIdempotent

The Snipe-IT audit trail: checkouts, checkins, creates, updates, audits — who did what, when, to which item. Filterable by item, action type, and target.

Inputs: limit, itemId, offset, itemType, +3 more.

snipeit_get_assetGet Asset (Snipe-IT)A
Read-onlyIdempotent

Fetch one asset by id, assetTag, or serial. With id, include can fetch: licenses, history, assigned-assets, assigned-accessories, assigned-components.

Inputs: id, serial, include, assetTag.

snipeit_get_entityGet Entity (Snipe-IT)A
Read-onlyIdempotent

Fetch one entity by id, or a subresource via include — e.g. licenses include=seats (seat ids for checkin), accessories include=checkedout (pivot-row ids for checkin), components include=assets, users include=assets|accessories|licenses|history.

Inputs: id (required), entity (required), include.

snipeit_list_assetsList Assets (Snipe-IT)A
Read-onlyIdempotent

Search/list hardware assets. Filters: free-text search, meta-status (RTD=ready to deploy, Deployed, Undeployable, Deleted, Archived, Requestable), status label id, model/category/manufacturer/company/location ids, assignee. due lists assets due/overdue for audit or check-in instead. Response: {total, rows} — page with limit/offset.

Inputs: due, sort, limit, order, +12 more.

snipeit_list_entitiesList Entities (Snipe-IT)A
Read-onlyIdempotent

List licenses, accessories, consumables, components, users, locations, statuslabels, categories, manufacturers, models, companies, departments, suppliers, fields, fieldsets, kits, maintenances, depreciations, or groups. Response: {total, rows}.

Inputs: entity (required), sort, limit, order, +2 more.

snipeit_search_capabilitiesSearch Snipe-IT CapabilitiesA
Read-onlyIdempotent

Search the Snipe-IT MCP server capabilities and examples. Use this first when deciding which tool to call.

Inputs: limit, query.

snipeit_update_assetUpdate Asset (Snipe-IT)A

Partially update an asset — only the fields in patch change (PATCH semantics). Requires write access.

Inputs: id (required), patch (required).

snipeit_update_entityUpdate Entity (Snipe-IT)A

Partially update a non-asset entity (PATCH semantics). Requires write access.

Inputs: id (required), patch (required), entity (required).

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 13 tools

    Disambiguation5/5

    Each tool has a distinct purpose: audit, checkin, checkout, CRUD for assets vs other entities, and reporting. No overlapping functionality.

    Naming Consistency4/5

    All tools start with 'snipeit_' followed by a verb_noun pattern (e.g., create_asset, list_entities), but 'checkin' and 'checkout' deviate slightly as single verbs, and 'search_capabilities' is less standard.

    Tool Count5/5

    13 tools cover the essential operations for an asset management system: CRUD, checkin/checkout, audit, and search. The count feels well-scoped without being excessive.

    Completeness3/5

    Covers core create, read, update, checkin/checkout, and audit, but lacks delete operations for both assets and other entities, which is a notable gap in lifecycle management.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      B
      maintenance
      MCP server for SolarWinds Service Desk (SWSD/Samanage) enabling reading and modifying tickets, comments, knowledge-base articles, and more via each user's own API token.
      52
      1,760 npm
      5
      MIT
    • A
      license
      B
      quality
      D
      maintenance
      Read-only MCP server for Snipe-IT v7 REST API, providing search and retrieval of assets, users, models, categories, and locations without modification.
      16
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      MCP server for Snipe-IT asset management, enabling users to read and manage IT assets, models, manufacturers, and related data through natural language. Designed to feed inventory into lifecycle audits.
      Apache 2.0
    • A
      license
      C
      quality
      B
      maintenance
      MCP server for GLPI integration, providing tools for ITIL management (tickets, problems, changes, knowledge base, stats, assets, and administration) via the GLPI API.
      30
      MIT