clm-mcp
The tool schema is well structured for MCP: read-only/idempotent annotations are consistently applied to query/list tools, the three introspection/invocation tools provide full API coverage while excluding Test/* operations, and descriptions are unusually specific about known API quirks (e.g., material-handover status 'All' matching zero records). Input schemas sensibly use $defs and anyOf for enum-like values, with clm_list_enums as a lookup helper. Output schemas for curated list tools standardize a total_count plus rows shape, which helps clients understand paging behavior. The main weaknesses are that many output schemas are permissive objects with additionalProperties:true, so clients cannot rely on strict field typing, and some operational caveats are embedded in descriptions rather than enforced by the schema. Also, because clm_invoke can perform writes, its annotations correctly omit readOnlyHint, but clients should still check the server read-only configuration before invoking arbitrary operations. Overall, the schema is practical, well-documented, and suitable for LLM-driven MCP clients, with the caveat that generic invocation tools like clm_invoke require care.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@clm-mcp Get the status of shipment 12345"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
clm-mcp
An MCP server exposing four SELISE CLM business services — shipment, construction, team, and konshub — to MCP clients: Claude Code, Claude Desktop, Cursor, or any other MCP-compatible tool.
Every one of the 364 non-
Testoperations across all four services is reachable, by default, with zero configuration — 47 read-only tools by default:2 identity/discovery tools (
clm_whoami,clm_list_enums) plus 42 curated domain tools: 18 covering shipment (shipments, incidents, site equipment, lean cards, material handovers, cockpit dashboards, weather), and 8 each for construction (materials, zones, site structure, wiki search), team (teams, members, join requests, invitations, contacts), and konshub (the warehouse/logistics dashboard: incoming/outgoing shipments, deliveries, storage, warehouse zones).A full-coverage gateway (
clm_list_operations/clm_describe_operation/clm_invoke) that reaches literally every operation in all four services — including all 181 write (*Command) operations and the 141 less-common query operations without a hand-written tool (322 operations total via the gateway) — generically, with pre-flight schema validation. This is the default way to execute a write — see below.181 auto-generated write tools exist but are opt-in, one per
*Commandoperation (create/update/delete/discard/...), individually named and annotated by risk. Registering all of them by default would add ~78,000 tokens of tool-definition context to every request — setCLM_WRITE_TOOLS=shipment(or a comma-separated list, orall) to opt specific services into named write tools.Set
CLM_ENABLE_WRITES=falseto refuse every write outright — throughclm_invokeor a named write tool — and run strictly read-only instead.
Proactive token refresh for a 7-minute access-token lifetime (shared across all four services — one login, one token), correct handling of an API that returns HTTP 200 even for business failures, and response shaping so large DTOs don't flood the model's context.
Requirements
Python ≥ 3.13.3
A SELISE CLM account (username/password, or an existing refresh token)
Related MCP server: mcp_hospirfq_processor
Install
git clone <this-repo>
cd clm-mcp
uv syncAuthenticate
Pick one of these. If both are configured, environment variables win — the
on-disk store from clm-mcp login is only consulted when neither
CLM_REFRESH_TOKEN nor CLM_USERNAME+CLM_PASSWORD is set.
Option A — clm-mcp login (recommended)
A one-time interactive login. Your password is typed at a getpass prompt (never
echoed, never sent anywhere except the identity service, and never passed as a tool
argument — see Security). The resulting refresh token is validated and
saved to ~/.config/clm-mcp/credentials.json (mode 0600):
uv run clm-mcp login
# CLM username (email): you@example.com
# CLM password:
# Credentials saved to /home/you/.config/clm-mcp/credentials.jsonAlready have a refresh token (e.g. from your browser's network tab)? Skip the prompt:
uv run clm-mcp login --refresh-token <token>Option B — environment variables
Set one of these (e.g. in your MCP client's config, or a .env file — copy
.env.example to .env to start):
CLM_REFRESH_TOKEN=<token>
# — or —
CLM_USERNAME=you@example.com
CLM_PASSWORD=<password>If none of the above is configured, every tool call fails with a clear
ToolError telling you to run clm-mcp login.
Run
uv run clm-mcp # stdio — for MCP clients that spawn a subprocess
uv run clm-mcp --http --port 8000 # streamable HTTP — for a remote/containerized deployment--http also accepts --host (default 127.0.0.1) and --path (default /mcp).
Add to Claude Code
claude mcp add clm -- uv run --project /path/to/clm-mcp clm-mcpAdd to Claude Desktop
claude_desktop_config.json:
{
"mcpServers": {
"clm": {
"command": "uv",
"args": ["run", "--project", "/path/to/clm-mcp", "clm-mcp"]
}
}
}Credentials come from clm-mcp login automatically — no env block needed unless you
prefer CLM_REFRESH_TOKEN/CLM_USERNAME+CLM_PASSWORD inline.
See USAGE.md for a complete connection guide covering Claude Code, Claude
Desktop, Cursor, Windsurf, VS Code (Copilot Chat), Cline, Zed, Continue.dev, and generic
stdio/HTTP MCP clients, plus operating guidance for coding agents using this server.
Configuration reference
All variables use the CLM_ prefix (see .env.example for the full, commented list).
Variable | Default | Purpose |
| — | Refresh token (Option B) |
| — | Password grant (Option B) |
|
| Where |
|
| API root — each service's base is |
| — | Deprecated: shipment-only base URL override, kept for pre-multi-service configs. Equivalent to |
|
| Per-service base URL overrides, as a JSON object: |
|
| Identity/token endpoint (shared by all four services) |
|
| Required |
|
| Whether a |
| (empty) | Which services get a named tool per |
|
| TCP connect timeout for business API requests |
|
| Read timeout for business API requests — some operations (e.g. |
|
| Refresh this many seconds before actual expiry |
|
| Byte cap before a list response is truncated |
|
| Logging level (always written to stderr, never stdout) |
Tool reference
Identity & discovery
Tool | Description |
| Identity, site, and roles of the authenticated user — call this first. |
| Known integer values for CLM's undocumented status/type enums. |
Shipments
Tool | Description |
| Free-text shipment search, scoped to a site. |
| Filtered, searched, ordered, paged shipment list (cockpit list view). |
| Shipment counts by status bucket (open/approved/completed/cancelled). |
| Full internal shipment record by id (up to 142 fields). |
| Smaller, external-facing shipment summary — prefer this over |
| Comments posted on a shipment. |
| Audit/event log history for a shipment or related entity. |
| Day-wise timeline for a single shipment. |
Incidents
Tool | Description |
| Non-deleted incidents/findings raised against a shipment. |
| Full detail of a single incident/finding. |
Site equipment
Tool | Description |
| Bookable/non-bookable site equipment for the grid view. |
| Equipment timeline entries (bookings), filtered and paged. |
Lean cards (working packages)
Tool | Description |
| Lean cards for a site, filtered by status. |
| Lean card counts by status (overdue/active/pending/completed). |
Material handovers
Tool | Description |
| Handover summaries for a site, filtered by a required status string (the API rejects null/empty — see Known limitations) and date range. |
| Full handover detail, including event history and equipment usage. |
Cockpit dashboard
Tool | Description |
| Weekly shipment count grid for a site's unloading zones. |
| Daily weather records for a site within a date range. |
Construction
Tool | Description |
| Paginated, searchable material list for a site. |
| A single material by its item id. |
| A material's shipment usage totals, grouped by status. |
| Zones belonging to a site or shared at the project level. |
| A zone by id, with equipment, way-points, and related areas. |
| A site's zones as locations, with direction way-points. |
| A site's structure (buildings/floors/laydowns), hierarchically. |
| Free-text search over wiki page content. |
Team
Tool | Description |
| CLM teams for a site, own teams surfaced first by default. |
| Members of (or unassigned candidates for) a team. |
| Vendor teams for a site. |
| Team join requests for a site, role-scoped to the caller. |
| Full detail of a single team join request. |
| Responsible-person contacts for a site (e.g. shipment sender/recipient pickers). |
| Extended profile combining Person/User/ClmTeamMember/temp-role data. |
| Pending and past user invitations for a site. |
KonsHub (warehouse/logistics dashboard)
Tool | Description |
| Incoming shipments in a date window, for the dashboard. |
| Outgoing shipments in a date window, for the dashboard. |
| Shipments for one tab of the Deliveries screen. |
| Deliveries-screen tab counts plus a grand total. |
| Free-text search over every Deliveries tab in one call. |
| Comments on a KonsHub shipment. |
| Storage zones matching an optional combination of filters. |
| Zones belonging to a warehouse (scoped by |
(KonsHub tool names carry a konshub_ infix where they'd otherwise collide with a
shipment tool name — the shipment service already owns the unprefixed names.)
Full-coverage gateway
The curated tools above cover the common workflows across all four services. These three reach everything else — including all 181 write operations — at the cost of the caller constructing its own request body:
Tool | Description |
| List operations, filterable by |
| Get an operation's resolved JSON Schema request/response shape. |
| Execute any listed operation — the default way to run a write. Validates |
Operation names are {tag}/{operation} (e.g. "ShipmentQuery/GetShipmentById") when
unambiguous across all four services — true for every operation today — or the fully
qualified {service}/{tag}/{operation} form always works
("konshub/KonsHubShipmentCommand/SplitKonsHubShipment").
Test/* operations (see Security) are excluded from all three, in every
service — they never appear in clm_list_operations and clm_invoke refuses them by name.
Write tools
Opt-in, empty by default — set CLM_WRITE_TOOLS=shipment (or a comma-separated list
of shipment/construction/team/konshub, or the literal all) to get a named
tool per *Command operation for that service, in addition to the always-available
clm_invoke. Registering all 181 by default would add ~78,000 tokens of
tool-definition context to every single request (measured: 59 shipment write tools
alone cost ~27,000 tokens) — clm_invoke is the default write path specifically to
avoid that, and is already schema-validated and gated by CLM_ENABLE_WRITES the same
way a named tool would be.
When enabled, each is named clm_<tag>_<operation> — e.g.
clm_shipment_command_discard_shipment, clm_konshub_shipment_command_split_konshub_shipment —
generated from that operation's resolved request schema and annotated by its verb:
Verb prefix | Annotation |
| not destructive |
| not destructive, idempotent |
| destructive |
anything else ( | destructive, non-idempotent (conservative fallback — annotations are hints, not a guarantee, so an unrecognized verb is treated as risky rather than safe) |
A deeply nested field (an array of objects, say) falls back to a permissive JSON
object rather than a fully-typed nested schema — the API itself still validates it.
Use clm_invoke instead when you want full JSON-Schema pre-validation of a nested body.
CLM_WRITE_TOOLS and CLM_ENABLE_WRITES are independent settings: the former
controls whether a named tool exists; the latter controls whether a write can
execute at all (through clm_invoke or a named tool). CLM_ENABLE_WRITES=false
always wins — there's no point in a named tool that would only ever refuse.
To see the exact generated names for a given CLM_WRITE_TOOLS value, ask a connected
client to list its tools, or run:
CLM_WRITE_TOOLS=all npx @modelcontextprotocol/inspector uv run clm-mcpArchitecture
src/clm_mcp/
├── __main__.py CLI: clm-mcp / clm-mcp login / clm-mcp --http
├── config.py pydantic-settings, CLM_ env prefix, per-service base_url_for()
├── services_catalog.py the 4 CLM services: slug, spec file, gateway segment, path prefix
├── server.py build_server(): MCPServer + typed lifespan
├── enums.py domain enums (see Known limitations)
├── auth/ token lifecycle: models, on-disk store, TokenManager (shared
│ across all 4 services — one identity issuer)
├── api/ HTTP client (retry policy, per-operation service routing) +
│ envelope unwrapping
├── spec/
│ ├── specs/ vendored OpenAPI specs, one per service
│ ├── registry.py merges all 4 specs into one operation index
│ └── shaping.py response shaping (null-stripping, projection, truncation)
├── services/ composition layer between tools and api/ — no business
│ logic in tool functions; one module per service
└── tools/ MCP tool registration: meta, curated domains (one module per
service), gateway, auto-generated write toolsAuth. The identity service issues a 7-minute access token. TokenManager
refreshes proactively (90s before expiry, configurable), coalesces concurrent
refreshes behind a single in-flight request, and forces a refresh on an unexpected
401. Refresh tokens observed on this API are not rotated, but the manager persists
whatever comes back regardless, in case that changes.
Envelopes. The business API returns HTTP 200 even when the requested operation
failed — success/failure lives in the JSON body (IsSuccess, ErrorMessages,
ExternalError, ValidationErrors.IsValid), not the status code. api/envelope.py
checks this on every response and raises a normal ToolError on failure, so the model
sees "shipment not found" the same way it sees any other tool outcome.
Response shaping. Some DTOs are large (Shipment has 142 properties, most
usually null for any given row). Every list-returning tool null-strips its result,
supports a fields parameter to project down to just what's needed, and enforces a
byte budget (CLM_MAX_RESPONSE_BYTES) — truncating rows (never a row's own fields)
with an explicit note rather than silently dropping data.
Development
uv sync --group dev
uv run pytest # full test suite
uv run ruff check . # lint
uv run ruff format . # format
uv run mypy src/clm_mcp/ # strict type check
uv run python scripts/refresh_spec.py # check all 4 vendored specs for drift
uv run python scripts/refresh_spec.py --write # ...and apply the update, all 4
uv run python scripts/refresh_spec.py --service konshub # just one servicenpx @modelcontextprotocol/inspector uv run clm-mcpopens the MCP Inspector against
this server for interactive testing (uv run mcp dev isn't usable here since the
entry point is a Typer CLI, not a module-level MCPServer instance the Inspector's
dev command can import directly).
Security
clm-mcp loginis the only place a password is collected, via a terminalgetpassprompt — never as a tool argument. Per the MCP specification, "servers MUST NOT use elicitation to request sensitive information," so this server never asks the client to collect one either. Only a refresh token is ever written to disk.Tokens are never logged. A structlog processor redacts
access_token,refresh_token,password, andAuthorizationfrom every log line, regardless of where in a nested structure they appear.Test/*operations are permanently excluded, in all four services (at the registry level — every tool,clm_list_operations, andclm_invokeall route through the same exclusion).Test/GetUserDataon the upstream staging API returns super-admin credentials in plaintext to any authenticated caller, confirmed present in shipment, construction, team, and konshub alike; this is an upstream vulnerability that should be reported and fixed independently of this client — excluding it here only stops this server from being a vector for it, it does not remediate the underlying exposure.Writes execute only when
CLM_ENABLE_WRITESis true (the default) — throughclm_invokeor a named write tool alike. Named write tools are themselves opt-in per service (CLM_WRITE_TOOLS, empty by default) and individually annotated so an MCP client can prompt for confirmation before a destructive call. SetCLM_ENABLE_WRITES=falsefor a connection that should never be able to mutate live data at all, regardless ofCLM_WRITE_TOOLS.
Known limitations
Several shipment-service domain enums have no documented names.
ShipmentStatus(13 values),LeanCardStatus,Severity,ShipmentGroupingType,AccessType, andAvailableDateGetTypeare exposed as bare integers in the OpenAPI spec with no labels.enums.pyships them as explicitUNKNOWN_nplaceholders (not a guess — see that module's docstring) andclm_list_enumssurfaces the known int ranges. Tools accept either the placeholder name or the raw int. Replace the placeholders with real names (from the CLM front-end source or a domain expert) when available. Construction, team, and konshub have similar undocumented int fields (e.g. konshub'sApprovalStatus/CommissionedStatus, team'sTeamType/RequestType, construction'sLocationType/WKTType) that are not yet stubbed — unlikeShipmentStatus, none of them have live-observed cardinality evidence yet, and guessing a range would be worse than leaving them as plain ints reachable viaclm_invoke/clm_describe_operation.Two of the four specs contain cyclic schemas (konshub's
KonsHubShipmentself-references viaPreviousKonsHubShipments; construction'sReservation/ReservationObject/ReservationObjectSpecificDateform a mutual cycle). The registry breaks a cycle with a permissive{"type": "object"}placeholder at the point it closes rather than failing to build — four operations (KonsHubShipmentCommand/SplitKonsHubShipmentand three query operations) lose static pre-validation on the recursive field specifically; the API itself still validates the real shape at call time.The vendored specs'
servers[0].urlis wrong in all four (plain HTTP, missing the gateway path prefix) — this server derives each service's base URL fromCLM_API_ROOT_URLinstead of reading it from the spec.No
securitySchemesin any of the four specs — the Bearer scheme is inferred from testing against the live API, not documented. If a gateway ever requires an additional header,api/client.pyis the one place to add it.Construction has inconsistent
SiteIdcasing across operations (SiteId,siteId,Siteid,SiteIds) — each curated construction tool uses the exact casing its own operation declares; don't assumeSiteIdblindly when usingclm_invokeagainst a construction operation not covered by a curated tool.clm_list_material_handovers'sstatusis required, despite the spec marking the underlying fieldnullable: true— the API rejects both a missing and an empty/nullStatuswith'Status' must not be empty.statusis matched as a literal value, not a wildcard:Allis accepted without a validation error but matches zero handovers (confirmed live:TotalCount=0against a site with 35 real handovers).InProgressis confirmed live to filter correctly (returned all 35 matching handovers on that site).Open,Completed,Pending,Draft, andClosedare accepted without a validation error but their filtering semantics were not confirmed against real data.One specific staging site (the account's default/JWT-scoped site,
68BC0C11-963F-46CB-AF93-267B50ABCCAF, "Scclm Team") has corrupted or incomplete data that makes several otherwise-healthy operations throw generic exceptions when scoped to it — confirmed by re-running the exact same operations against a properly-configured site (e.g. "KonsHub Test Site 1") and getting clean, correct results both times. This was initially mistaken for universal upstream bugs during an earlier pass; a broader real-data test across multiple sites corrected that. Affected on that one site only:LeanCardQuery/GetWorkingPackages/GetWorkingPackagesCount(shipment),ClmTeamQuery/GetTeamListandGetVendorTeams(team — the latter's error message,"Provided SiteId does not exists", really means "this site isn't vendor-team-scoped"),KonsHubShipmentQuery/GetDashboardIncommingShipmentList/GetDashboardOutgoingShipmentList(konshub), andZoneCommand/CreateZone(construction,"The site does not exist"— this site isn't construction-zone-scoped). If a query in one of these services fails ambiguously, try a differentsite_idbefore concluding the API itself is broken.TimelineQuery/GetShipmentTimelineByIdreturns a 500 instead of a clean 404 for a genuinely nonexistent shipment id — confirmed independent of which site is used, reproduced via rawcurl.clm_get_shipment_timelinesurfaces this faithfully as aToolError.ClmTeamQuery/GetSiteResponsiblePersons'sTotalCountdoes not track itsDataarray length at all (observed bothTotalCount: 1with 0 real rows, andTotalCount: 1with 7 real rows), confirmed live on more than one site — a genuine API defect, not a client bug. Treat this operation'stotal_countas unreliable; trustreturned/datainstead.clm_list_site_responsible_personsis affected.ConstructionManagementQuery/GetMaterialUsagesByIdalways reportsIsSuccess: false, even on a genuine successful lookup — confirmed live with two different realMaterialIds on two different sites (and independently by the user with their own payload):Datais populated and correct despite the false flag, and only a truly nonexistentMaterialIdreturnsData: null. Handled transparently:api/envelope.pyspecial-cases exactly this one operation (by its canonical name) to treat a populatedDataas success regardless of the flag, soclm_get_material_usageworks normally — a nullDatais still correctly treated as failure. This operation is also noticeably slow (observed 3–12s) — worth knowing if you're tuningCLM_API_READ_TIMEOUT_SECONDSdown from its 60s default.Team and konshub curated list tools, plus
clm_list_materials(construction), use one-based pagination (page_number=1is the first page) — unlike shipment/most other construction tools' zero-based convention. Confirmed live:GetJoinRequestList,GetTeamList,GetMaterialList, andGetDeliveriesTabShipmentListall computeskip = (PageNumber - 1) * PageSizeinternally and rejectPageNumber=0with a 500. Each curated tool's ownpage_numberdefault and description already reflect the correct convention for that operation — this only matters if you overridepage_numberexplicitly.clm_get_cockpit_weekly_countsrejects a date window wider than 92 days. The underlying API returns one entry per day with no size cap of its own — confirmed live, a 2020–2027 window returned ~530,000 bytes (over 10xCLM_MAX_RESPONSE_BYTES's default) with zero truncation, since it's an object response rather than a list one. The 92-day cap is enforced before the HTTP call, with a clearToolErrortelling the caller to narrow the range.
Troubleshooting
Symptom | Likely cause / fix |
| Run |
A |
|
| That's the real read-only gate — |
| Check the credentials themselves against the CLM login page. |
| It expired or was revoked — run |
A tool call is missing/behaves oddly after an upstream API change | Run |
Response was truncated | The |
Nothing happens over stdio / a client can't parse output | Something wrote to stdout directly — all logging in this project goes to stderr by design ( |
Available Tools
82 toolsclm_count_shipmentsARead-onlyIdempotent
Shipment counts for a site broken down by status bucket (open, approved, completed, cancelled/rejected).
Inputs: filter_schedule_end_date (required), filter_schedule_start_date (required), site_id. Returns: object
clm_count_working_packagesARead-onlyIdempotent
Count of lean cards (working packages) for a site, broken down by status (overdue, active, pending, completed).
Inputs: site_id. Returns: object
clm_describe_operationARead-onlyIdempotent
Describe one operation: its resolved JSON Schema request body
(for a POST operation) or query parameters (for a GET operation),
and its response shape — everything needed to build valid
clm_invoke params.
Inputs: operation (required). Returns: tag, name, method, summary, +4 more
clm_get_cockpit_weekly_countsBRead-onlyIdempotent
Weekly shipment count grid for a site's active unloading zones.
Inputs: filter_schedule_end_date (required), filter_schedule_start_date (required), site_id. Returns: object
clm_get_incidentARead-onlyIdempotent
Retrieve the full detail of a single incident/finding.
Inputs: item_id (required). Returns: object
clm_get_material_handoverARead-onlyIdempotent
Full details of a single material handover, including its event history and equipment usage.
Inputs: handover_id (required). Returns: object
clm_get_shipmentARead-onlyIdempotent
Retrieve the full internal shipment record by id (up to 142 possible fields, most absent for any given shipment). Prefer clm_get_shipment_summary for a smaller, external-facing view.
Inputs: shipment_id (required). Returns: object
clm_get_shipment_commentsARead-onlyIdempotent
List all comments posted on a shipment, with commenter display info.
Inputs: shipment_id (required). Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_get_shipment_event_logsARead-onlyIdempotent
Retrieve the audit/event log history for a shipment or related connected entity, ordered chronologically.
Inputs: item_id (required). Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_get_shipment_summaryARead-onlyIdempotent
Retrieve a shipment's smaller, external-facing summary (native CLM or KonsHub-linked).
Inputs: shipment_id (required). Returns: object
clm_get_shipment_timelineARead-onlyIdempotent
Retrieve the day-wise timeline for a single shipment.
Inputs: shipment_id (required). Returns: object
clm_get_weatherARead-onlyIdempotent
Daily weather records (temperature, wind speed, symbol) stored for a site within a date range.
Inputs: end_date (required), start_date (required), fields, site_id. Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_incident_command_create_incidentA
Creates a new incident/finding against a CLM, KonsHub, or equipment-booking shipment, links it to the shipment, and recalculates the shipment's incident counts. A background command is queued afterwards to generate thumbnails for the incident's attached files, and, if the shipment is already completed, to trigger PDF regeneration.
Inputs: params (required). Returns: object
clm_incident_command_delete_incidentADestructive
Soft-deletes an incident by marking it as deleted (IsMarkedToDelete) rather than physically removing it, then recalculates the owning shipment's incident counts to exclude it.
Inputs: params (required). Returns: object
clm_incident_command_update_incidentAIdempotent
Updates the remark, attached files, and finding type of an existing incident, then recalculates the owning shipment's incident counts and re-queues thumbnail generation for the updated files.
Inputs: params (required). Returns: object
clm_invokeA
Execute any operation listed by clm_list_operations.
params is validated against the operation's resolved schema
before the HTTP call. A *Command operation (a write) is refused
if the server was started with CLM_ENABLE_WRITES=false.
Inputs: operation (required), params.
clm_lean_card_command_create_lean_documentA
Registers an uploaded lean document (an Excel workbook used to bulk import/refresh lean cards) for a project/site if it does not already exist, then queues it for background processing that parses the workbook and creates or updates the corresponding lean cards.
Inputs: params (required). Returns: object
clm_lean_card_command_lean_card_createADestructive
Creates a new lean card (working package) for a project/site, assigning it to a sender and recipient team, computing its initial status, and setting the access-control roles that determine who can read or update it. Also queues background jobs to refresh site-structure and team grouping counts.
Inputs: params (required). Returns: object
clm_lean_card_command_lean_card_updateADestructive
Updates an existing lean card's location (building/floor/laydown area), comment, dates, archived flag, volume, and estimated transport unit; recalculates its status; and queues background jobs to re-sync site-structure and team grouping counts using the old and new values.
Inputs: params (required). Returns: object
clm_lean_card_command_save_working_package_file_dataAIdempotent
Finalizes the working-package import: creates the lean document record for the uploaded file if one does not already exist, then queues a background command that creates or updates the actual lean cards from the previously mapped Excel data.
Inputs: params (required). Returns: object
clm_lean_card_command_save_working_package_header_mappingAIdempotent
Saves the user-selected mapping between Excel columns and lean card fields (activity id, date format, sender/recipient team) for a previously uploaded working-package file, then queues background building of a preview of the resulting working packages by matching rows against existing teams and lean cards, notifying the uploading user of the outcome.
Inputs: params (required). Returns: object
clm_lean_card_command_send_working_package_date_change_emailADestructive
Sends an email notification, in each recipient's preferred language, to the members of a lean card's (working package's) sender team informing them that its start/end dates have changed.
Inputs: params (required). Returns: object
clm_lean_card_command_upload_working_package_fileADestructive
Queues the initial background processing of an uploaded working-package Excel file: reading the selected sheet, parsing its rows/columns into a temporary upload record, and notifying the uploading user once processing completes, in preparation for the header-mapping step.
Inputs: params (required). Returns: object
clm_list_enumsARead-onlyIdempotent
List CLM domain enums and their known integer values.
Several API fields (e.g. shipment/lean-card status, severity) are
undocumented integer enums in the spec — real member names are not
yet known (see PLAN.md). Tools accepting one of these enums take
either the int value shown here or its placeholder name (e.g.
"UNKNOWN_3") interchangeably.
Inputs: no named parameters. Returns: result
clm_list_equipmentARead-onlyIdempotent
List all site equipment, split into bookable and non-bookable groups, for the equipment management grid view.
Inputs: site_id. Returns: object
clm_list_equipment_timelineARead-onlyIdempotent
List equipment timeline entries (bookings) for the cockpit equipment list view: filtered, searched, sorted, and paged.
Inputs: filter_schedule_end_date (required), filter_schedule_start_date (required), fields, site_id, +2 more. Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_list_incidentsARead-onlyIdempotent
List all non-deleted incidents/findings raised against a shipment.
Inputs: shipment_id (required). Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_list_material_handoversARead-onlyIdempotent
List material handover summaries for a site, filtered by status and date range.
Inputs: status (required), end_date (required), start_date (required), fields, +1 more. Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_list_operationsARead-onlyIdempotent
List CLM API operations reachable via clm_invoke.
Filter by exact tag (e.g. "ShipmentCommand") and/or a
case-insensitive search substring against the operation name or
summary. Use clm_describe_operation on a result to get its full
input schema before calling clm_invoke.
Inputs: tag, limit, search. Returns: result
clm_list_shipmentsARead-onlyIdempotent
List shipments for the cockpit list view: filtered, searched, ordered, and paged, scoped to the site and the caller's team visibility.
Inputs: filter_schedule_end_date (required), filter_schedule_start_date (required), fields, status, +5 more. Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_list_working_packagesARead-onlyIdempotent
List lean cards (working packages) for a site, filtered by status.
Inputs: status (required), fields, site_id, page_size, +1 more. Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_material_handover_command_change_material_handover_statusADestructive
Toggles a handover's status between InProgress and Paused, appending a new handover event capturing the note and photos for the change, and updates the parent shipment's aggregated handover status. Pausing also queues a background job to generate thumbnails for the responsible-person photos of that event.
Inputs: params (required). Returns: object
clm_material_handover_command_complete_material_handoverADestructive
Marks a handover as Completed: appends a completion event, stores the final material/responsible-person photos and note, computes the total time spent by summing the durations between paired handover events, optionally attaches the responsible person resolved from a QR-code scan, updates the parent shipment's aggregated handover status (triggering PDF regeneration if the shipment itself is now complete), and queues a background job to generate thumbnails for the final photos.
Inputs: params (required). Returns: object
clm_material_handover_command_create_material_handoverA
Creates a new material handover for a CLM or Konshub shipment, snapshotting the shipment's bookable equipment and assigning a sequential handover number, then updates the shipment's aggregated handover status/counters and queues a background job to generate thumbnails for the uploaded material photos.
Inputs: params (required). Returns: object
clm_material_handover_command_update_planned_equipment_usage_of_handoverAIdempotent
Records the actual usage (unit count or number of time slots, depending on the equipment's price type) for a single planned/bookable equipment item on a handover, recalculates that item's actual total price, and rolls the aggregated actual usage/price back up into the shipment's equipment timeline.
Inputs: params (required). Returns: object
clm_search_shipmentsARead-onlyIdempotent
Search shipments (native CLM and KonsHub-linked) by free text, scoped to a site.
Inputs: search_key (required), fields, site_id. Returns: Structured output for every curated list-returning tool. `total_count` is the A…
clm_shipment_command_create_shipment_commentA
Adds a new comment to a shipment, attributed to the current user.
Inputs: params (required). Returns: object
clm_shipment_command_delete_draft_shipmentDDestructive
Transitions a shipment to a new status (approved, waiting/ongoing/unloading, rejected/withdrawn, cancelled at transit, or completed), updates grouping counts, and triggers background processing (e.g. notifications) for the status change.
Inputs: params (required). Returns: object
clm_shipment_command_delete_shipment_commentBDestructive
Deletes an existing shipment comment.
Inputs: params (required). Returns: object
clm_shipment_command_discard_shipmentADestructive
Discards a shipment: if the shipment is still an in-progress wizard draft it is deleted entirely; if it has already been submitted, only its pending edit draft (and smart-wizard draft) is cleared, leaving the submitted shipment intact.
Inputs: params (required). Returns: object
clm_shipment_command_generate_cockpit_daily_reportADestructive
Queues generation of the cockpit daily report PDF (scheduled shipments, equipment, and ad-hoc shipment summaries) for background processing; once generated, the requesting user is notified.
Inputs: params (required). Returns: object
clm_shipment_command_generate_shipment_pdfADestructive
Requests (and returns, if already available) the generated PDF report for a shipment in the given language; if no PDF has been generated yet, this queues background PDF generation and returns immediately without a URL.
Inputs: params (required). Returns: object
clm_shipment_command_save_shipment_wizard_booking_datesAIdempotent
Saves the booking date step of the shipment wizard: for a shipment still being created it applies the booking date, express-shipment flag, and lean card directly; for an already-submitted shipment being edited, the change is stored as a pending draft.
Inputs: params (required). Returns: object
clm_shipment_command_save_shipment_wizard_materialAIdempotent
Saves the material-selection step of the shipment wizard: for a shipment still being created this sets its materials and recipient team directly; for an already-submitted shipment being edited, the change is stored as a pending draft rather than applied immediately.
Inputs: params (required). Returns: object
clm_shipment_command_save_shipment_wizard_other_infoBIdempotent
Saves the final "other info" step of the shipment wizard (on-site responsible person, sustainability/vehicle info, etc.), finalizing the shipment: persists the additional responsible persons and remaining shipment details, then triggers a background command to complete post-save processing.
Inputs: params (required). Returns: object
clm_shipment_command_save_shipment_wizard_timeslotsAIdempotent
Saves the timeslot step of the shipment wizard: resolves the selected zone (and its waiting area, if any), then for a shipment still being created applies the schedule window and equipment reservations directly, or for an already-submitted shipment being edited, stores the change as a pending draft.
Inputs: params (required). Returns: object
clm_shipment_command_save_shipment_wizard_unloadingsAIdempotent
Saves the unloading/vehicle step of the shipment wizard: for a shipment still being created it sets the selected vehicle's name, type, ID, and key directly on the shipment; for an already-submitted shipment being edited, the change is stored as a pending draft.
Inputs: params (required). Returns: object
clm_shipment_command_send_open_shipment_mailADestructive
Queues a background job to notify the shipment's recipient that a shipment has been requested, sending the "shipment requested" email in every supported language once the shipment is found.
Inputs: params (required). Returns: object
clm_shipment_command_update_shipment_commentBIdempotent
Updates the text of an existing shipment comment.
Inputs: params (required). Returns: object
clm_shipment_command_update_shipment_statusCIdempotent
Execute ShipmentCommand/UpdateShipmentStatus (a write operation).
Inputs: params (required). Returns: object
clm_shipment_command_upsert_adhoc_shipmentAIdempotent
Creates or updates an ad-hoc (walk-in, non-wizard) shipment: if a shipment with the given ID already exists it is updated, otherwise a new one is created and a background command is queued to finish processing it (e.g. thumbnail generation, notifications).
Inputs: params (required). Returns: object
clm_shipment_command_upsert_sustainability_addressBIdempotent
Creates, updates, or removes a team's saved sustainability address: marking an address as not-favourite deletes it, otherwise the address (identified by item ID) is updated if it already exists or created new for the given team.
Inputs: params (required). Returns: object
clm_site_equipment_command_calculate_bookable_equipment_usageADestructive
Recalculates and persists a bookable site equipment's daily usage aggregate for the given date, tallying open and approved shipments/bookings that use the equipment that day against its total available time; the aggregate record is removed if total usage becomes zero.
Inputs: params (required). Returns: object
clm_site_equipment_command_create_equipment_booking_from_mobileA
Creates a new site equipment booking submitted from the mobile app in a single call, covering booking date/slots, transport info, and other info (responsible persons, photos), then queues a background command that finalizes the booking (timeline creation and approval notifications).
Inputs: params (required). Returns: object
clm_site_equipment_command_create_or_update_equipmentA
Creates a new site equipment master record (creating its calendar reservation object and, if bookable, publishing an availability-set command) or updates an existing one (recreating/updating its reservation object and queuing a background command to refresh its zone attachment).
Inputs: params (required). Returns: object
clm_site_equipment_command_delete_equipmentADestructive
Permanently deletes a site equipment record and queues background commands to remove its zone attachment and, for bookable equipment, its booking prerequisites.
Inputs: params (required). Returns: object
clm_site_equipment_command_delete_equipment_booking_commentADestructive
Soft-deletes an equipment booking comment by marking it as deleted (it is excluded from subsequent reads but not physically removed).
Inputs: params (required). Returns: object
clm_site_equipment_command_delete_unplanned_equipmentADestructive
Soft-deletes an unplanned equipment usage record (marks it as deleted), removes its associated timeline entry, and logs an event.
Inputs: params (required). Returns: object
clm_site_equipment_command_discard_equipment_bookingADestructive
Discards an in-progress site equipment booking: permanently deletes it if it is still a drafted (not yet finalized) booking, or clears its in-progress draft data if it is an existing valid booking.
Inputs: params (required). Returns: object
clm_site_equipment_command_save_equipment_booking_commentAIdempotent
Adds a new comment to a site equipment booking, or edits an existing comment's text when Commands.EquipmentBookingCommentSaveCommand.ItemId matches an existing comment.
Inputs: params (required). Returns: object
clm_site_equipment_command_save_site_equipment_booking_infoAIdempotent
Saves the booking-date step of a site equipment booking (booking date, weather info, time slots). Creates a brand-new booking with status UnApproved when none exists yet for the given id, or updates the existing booking's (or draft's) booking info otherwise.
Inputs: params (required). Returns: object
clm_site_equipment_command_save_site_equipment_other_infoAIdempotent
Saves the "other info" step of a site equipment booking (creator/on-site responsible persons, photos, documents, comment). Depending on whether the booking is still being drafted or already exists, this finalizes creation (assigning a booking number and queuing the create-background command) or updates its draft (queuing the update-background command); it also re-validates the calendar slot reservation.
Inputs: params (required). Returns: object
clm_site_equipment_command_save_site_equipment_transport_infoAIdempotent
Saves the transport-info step of a site equipment booking (building/floor location, transport unit quantity, recipient team, material comment, price per unit) onto the booking record or its draft.
Inputs: params (required). Returns: object
clm_site_equipment_command_send_open_equipment_booking_mailADestructive
Queues a background command that sends a "booking requested" reminder email (in every supported language) for a still-open (unapproved) site equipment booking; the command is placed directly on the message queue and this endpoint returns immediately without waiting for the email to be sent.
Inputs: params (required). Returns: object
clm_site_equipment_command_update_equipment_booking_from_mobileAIdempotent
Updates an existing site equipment booking's booking/transport/other info from the mobile app, re-validating and re-creating the calendar slot reservation, then queues a background command that updates the timeline and sends the relevant status-change notifications.
Inputs: params (required). Returns: object
clm_site_equipment_command_update_equipment_statusAIdempotent
Activates or deactivates an existing site equipment record by toggling its Active flag.
Inputs: params (required). Returns: object
clm_site_equipment_command_update_site_equipment_booking_statusAIdempotent
Transitions a site equipment booking to a new status (e.g. approve, reject, withdraw, cancel, complete), updates its timeline entry, and queues a background command that either completes the linked equipment timeline (calculating actual usage/price and freeing up slots, when completing) or performs the corresponding status-change side effects such as sending notification emails.
Inputs: params (required). Returns: object
clm_site_equipment_command_upsert_unplanned_equipmentAIdempotent
Creates a new unplanned equipment usage record attached to a material handover, or updates an existing one's usage/price/slot data. On create it also (re)builds the equipment's timeline entry, assigns a booking number, and logs an event; the same happens for updates.
Inputs: params (required). Returns: object
clm_smart_shipment_command_save_shipment_wizard_booking_datesAIdempotent
Saves step 1 of the Smart Shipment wizard: the booking date, lean card and weather/timezone context. If no shipment exists yet for the given ShipmentId, creates a new draft shipment (status UnApproved) linked to the lean card's site; otherwise updates the booking-date fields on the existing shipment (or on its smart-draft, if the shipment is already a valid, non-draft shipment).
Inputs: params (required). Returns: object
clm_smart_shipment_command_save_shipment_wizard_timeslotsAIdempotent
Saves step 2 of the Smart Shipment wizard: the selected unloading zone, delivery time slots and the bookable/non-bookable equipment associated with the shipment. Resolves the full zone (and its waiting area, if any) and applies the schedule to the shipment directly, or to its smart-draft if the shipment already exists as a valid (non-draft) shipment.
Inputs: params (required). Returns: object
clm_smart_shipment_command_save_smart_shipment_wizard_materialsAIdempotent
Saves step 4 of the Smart Shipment wizard: the delivery materials and drop-off details (building, floor, laydown area, recipient team) for the shipment. For a new (drafted) shipment this persists the material lines to the shipment and saves each ShipmentMaterial individually; for an existing shipment it stores the material info on the shipment's smart-draft instead.
Inputs: params (required). Returns: object
clm_smart_shipment_command_save_smart_shipment_wizard_other_infoAIdempotent
Saves the final step of the Smart Shipment wizard: responsible persons, shipment photos/documents, comment and sustainability info, and finalizes the shipment. Validation reserves the unloading-zone timeslot and any bookable/non-bookable equipment via the calendar service (rolling back reservations on failure). On success, promotes the draft/smart-draft into the real shipment: for an update it applies the requested status change (when HasAction is set), refreshes material handovers and updates grouping counts; for a new shipment it assigns a shipment number and updates grouping counts. In both cases a background command describing the change is recorded (as a pending ClmCommand) and sent to the processing queue to actually create/update the shipment downstream.
Inputs: params (required). Returns: object
clm_smart_shipment_command_save_smart_shipment_wizard_unloadingsAIdempotent
Saves step 3 of the Smart Shipment wizard: the unloading vehicle details for the shipment's booking date. Applies the vehicle information to the shipment directly, or to its smart-draft if the shipment already exists as a valid (non-draft) shipment.
Inputs: params (required). Returns: object
clm_timeline_command_complete_shipment_equipment_timelineADestructive
Validates and completes a site-equipment timeline entry: records the completion amount, optionally frees up any remaining reserved calendar slots for the equipment, updates the related shipment/site-equipment booking, and sends a booking-completed notification email in every supported language.
Inputs: params (required). Returns: object
clm_timeline_command_generate_equipment_timeline_excel_reportADestructive
Queues an asynchronous request to build an Excel export of the site-equipment timeline, filtered by site, status, date range, team/equipment ids and search keys, and returns immediately without waiting for the report to be generated.
Inputs: params (required). Returns: object
clm_timeline_command_generate_up_timeline_excel_reportADestructive
Queues an asynchronous request to build an Excel export of the shipment list view (UP timeline), filtered by site, status, schedule date range and sender/recipient teams, and returns immediately without waiting for the report to be generated.
Inputs: params (required). Returns: object
clm_user_setting_command_create_cockpit_equipment_filterA
Saves a new "equipment view" cockpit filter (site, recipient teams, bookable/non-bookable equipment and annotation flags) for the current user.
Inputs: params (required). Returns: object
clm_user_setting_command_create_cockpit_weekly_filterA
Saves a new "weekly view" cockpit filter (site, sender/recipient teams, moving/unloading equipment and annotation flags) for the current user.
Inputs: params (required). Returns: object
clm_user_setting_command_delete_cockpit_equipment_filterADestructive
Removes an existing "equipment view" cockpit filter belonging to the current user.
Inputs: params (required). Returns: object
clm_user_setting_command_delete_cockpit_weekly_filterADestructive
Removes an existing "weekly view" cockpit filter belonging to the current user.
Inputs: params (required). Returns: object
clm_user_setting_command_update_user_favorite_materialAIdempotent
Adds or removes a material from the current user's favorite materials list for a given site.
Inputs: params (required). Returns: object
clm_whoamiARead-onlyIdempotent
Return the identity, site, and roles of the authenticated CLM user.
Call this first: it confirms authentication is actually working
(triggering a token refresh if needed) and its site_id is the
default most other tools use for their site_id parameter.
Inputs: no named parameters. Returns: The identity, site, and roles of the currently authenticated CLM user.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 82 tools
Multiple tool boundaries are unclear: the regular and Smart Shipment wizard step tools differ only by prefix, clm_shipment_command_delete_draft_shipment is described as a status transition that collides with clm_shipment_command_update_shipment_status, and the generic clm_invoke overlaps with many concrete write tools. Agents would need to read long descriptions very carefully to reliably pick the intended tool.
The naming follows a strong clm_<domain>_command_<verb>_<object> pattern for writes and clm_list_/clm_get_/clm_count_ for reads, with consistent snake_case throughout. Minor deviations include clm_whoami, the generic clm_invoke/list/describe tools, and the misleading delete_draft_shipment name that does not match its described behavior.
With 82 tools, the surface is far beyond a well-scoped MCP server, and it includes near-duplicate wizard variants, many overlapping status/comment/update commands, and a generic invoke escape hatch. This imposes a severe context and selection burden on agents and is an extreme count for practical use.
The set provides broad lifecycle coverage for shipments, equipment, incidents, lean cards, material handovers, reports, and user filters, with no obvious dead ends for the main workflows. The main gaps are first-class reference-data lookups such as listing teams, zones, materials, and vehicles, though the generic invoke/describe tools can partly work around these.
Maintenance
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
One OAuth connector for your team's remote MCP servers, with Tool Packs, guardrails and logs.
Access Siglume API Store tools and external MCP Router servers.
Related MCP Servers
- AlicenseAqualityDmaintenanceExposes the OpenProject REST API as MCP tools for project management, including creating and managing projects, work packages, relations, attachments, users, notifications, watchers, boards, and reference data.3761 npmMIT
- AlicenseNot gradedqualityCmaintenanceExposes RFQ, travel, and hospitality operations as MCP tools backed by a GraphQL API.MIT
- FlicenseAqualityDmaintenanceMCP server that exposes tools for monitoring supply chain disruptions, including vessel positions, port weather, congestion, and news. Includes an AI agent that synthesizes these sources to assess route risks.5-
- FlicenseNot gradedqualityCmaintenanceEnables merchants to connect their PostEx account to MCP clients, exposing tools to book and cancel COD orders, track parcels, generate load sheets and airway bills, and check settlement status using their own PostEx token.2-