Skip to main content
Glama
parissaahmadi

cmms-mcp-server

ci

cmms-mcp-server

An MCP server that lets an AI assistant work with a maintenance management system (CMMS): look up assets, read and acknowledge alarms, and create and move work orders through a real life cycle, with role checks and an audit trail.

Everything runs on fictional data (a made-up plant with Quanta compressors, Ironwood presses, Helix lathes, Nimbus chillers and Vortex pumps; 16 assets, 12 alarms, 9 work orders, 5 users). There is no connection to any real system.

AI client  --MCP/stdio-->  tools.py (schemas, annotations, error mapping)
                              |
                          service.py (validation, roles, state machine, transactions)
                              |
                          SQLite (db.py)

The domain logic in service.py knows nothing about MCP, so it is tested directly, and the MCP layer is tested separately, in-process and over a real stdio subprocess.

Run it

uv sync
uv run cmms-mcp-server                                        # stdio, in-memory, reseeded each start
uv run cmms-mcp-server --db plant.sqlite3                     # persistent (created and seeded when missing)
uv run cmms-mcp-server --read-only                            # write tools are not registered at all
uv run cmms-mcp-server --fixed-now 2026-10-09T06:00:00Z       # freeze the clock (the seed is set on that day)
uv run python examples/demo_client.py                         # scripted client session, see below

Add it to an MCP client with .mcp.json.example (command uv run --directory ... cmms-mcp-server). SKILL.md is a companion skill that teaches an assistant the order of calls and the safety rules.

Related MCP server: Operational Ontology

Tools

tool

kind

what it does

get_plant_overview

read

counts of assets/alarms/work orders, overdue work, class-A assets with unacknowledged alarms

list_assets

read

filter by status, type, location, criticality, free text; paged

get_asset

read

one asset + its uncleared alarms, active work orders, last completed work order

list_alarms

read

filter by state, severity, asset, time; most severe first

list_work_orders

read

filter by status, priority, asset, assignee, overdue; highest priority first

get_work_order

read

one work order with its full event history

acknowledge_alarm

write, idempotent

take ownership of an alarm; repeating it changes nothing

create_work_order

write

optionally linked to an alarm; one active work order per alarm

assign_work_order

write

supervisors only

transition_work_order

write

the life cycle below, with role and note rules

Also: resource cmms://glossary and prompt shift_handover.

Work-order life cycle:

open -> assigned -> in_progress <-> on_hold -> completed -> closed
  \        \                          \          \-> in_progress   (reopen, supervisor)
   `--------`--------------------------`-> cancelled

role

may

viewer

read

technician

acknowledge, create, start / hold / complete work assigned to them

supervisor

everything: assign, unassign, close, cancel, reopen, act for anyone

A note (5+ characters) is required to hold, complete, cancel, unassign or reopen.

What a session looks like

Real output of examples/demo_client.py (long values shortened by the script):

> acknowledge_alarm as a viewer (must fail)
  ERROR Error executing tool acknowledge_alarm: forbidden: view.d is a viewer and cannot acknowledge alarms

> acknowledge_alarm as tech.a
  {"alarm": {"id": "ALM-0001", "asset_id": "AST-0001", "severity": "critical", "code": "OIL_TEMP_HIGH", ...

> create_work_order
  {"work_order": {"id": "WO-2026-0010", "asset_id": "AST-0001", "title": "Oil temperature high: inspect cooler", ...

> create_work_order again for the same alarm (must fail)
  ERROR Error executing tool create_work_order: conflict: alarm ALM-0001 already has an active work order: WO-2026-0010

> transition straight to completed (must fail)
  ERROR Error executing tool transition_work_order: invalid: cannot move a work order from 'open' to 'completed'; allowed: assigned, cancelled

Design decisions

  • Errors are written for a model. A domain error becomes a tool error code: reason that says what was wrong and what is allowed ("allowed: assigned, cancelled"). Unexpected exceptions stay generic: the SDK hides their text, and a test checks that a crash message containing a path does not reach the client.

  • Typed outputs. Tools return pydantic models, so each has an output schema and clients get structuredContent. A test fails if any tool or parameter lacks a description.

  • Annotations. Reads are marked readOnlyHint; acknowledge_alarm and assign_work_order are idempotent; nothing is destructive (records are never deleted).

  • --read-only removes the write tools instead of rejecting calls, so the model never sees them.

  • Duplicates are prevented where retries happen. A model may call create_work_order twice; the second call for the same alarm is a conflict that names the existing work order.

  • Writes are all-or-nothing (BEGIN IMMEDIATE). A test makes the event insert fail and checks that the status update is rolled back too.

  • Injection and wildcards. All SQL is parameterised; % and _ in search text are escaped.

  • Bounded output. Every list has limit (1-100) and next_offset.

  • Injectable clock (--fixed-now) so "overdue" and ids are deterministic in tests and demos.

Tests

74 test cases (uv run pytest): state machine; every read filter and ordering; every write rule and permission; rollback; tool inventory, annotations, schemas, documentation of every parameter; error mapping; read-only mode; resource and prompt; and a full triage flow plus persistence across two server processes over real stdio.

Mutation check: 20 deliberate bugs (viewer allowed to acknowledge, duplicate guard removed, ownership check dropped, no rollback, unescaped LIKE, crash text leaking, write tools registered in read-only mode, terminal state with an exit, ...) were each caught by at least one test. One mutant first survived because it was not actually leaking; it was rewritten and then caught.

Limitations

  • No authentication. actor is a claimed identity checked against a user table. That is fine for a demo and for stdio on your own machine; a real deployment must take the identity from the transport (for example OAuth on streamable HTTP) and never from a tool argument. The streamable-http option exists but is unauthenticated.

  • One process, one SQLite connection with a lock. No multi-writer support, no migrations.

  • Offset paging: rows added between pages can shift the window.

  • Not tested against a real assistant (Claude Desktop, Claude Code, ...); it is tested with the MCP SDK's own client. SKILL.md is guidance I wrote and have not measured.

  • Written for mcp 2.x (MCPServer, from mcp.client.client import Client); version 1.x used FastMCP and different client entry points, hence the mcp>=2.2,<3 pin.

Development

uv sync
uv run pytest
uv run ruff check

License

MIT, see LICENSE.

Available Tools

10 tools
acknowledge_alarmA
Idempotent

Take ownership of an active alarm. Safe to repeat: an already acknowledged alarm is returned unchanged with already_acknowledged=true.

ParametersJSON Schema
NameRequiredDescriptionDefault
actorYesUsername performing the action, e.g. 'tech.a'. Never guess one.
alarm_idYesAlarm id such as ALM-0001.

Output Schema

ParametersJSON Schema
NameRequiredDescription
alarmYes
already_acknowledgedYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true and destructiveHint=false, but the description goes further by specifying the exact repeat-call contract: an already acknowledged alarm returns unchanged with already_acknowledged=true. That is concrete behavior an agent needs for retry logic, though it says nothing about failure modes for unknown or inactive alarm IDs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, no filler. The core action is front-loaded and the idempotency contract follows immediately, which is the right ordering for an agent deciding whether to retry.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and annotations cover the safety profile. The repeat-call semantics fill the main gap; the only omissions are error behavior for invalid or already-cleared alarms, which are minor for a 2-parameter idempotent tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and both parameters are documented in the schema, including the strong 'Never guess one' warning on actor. The description adds no parameter-level meaning beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Take ownership of an active alarm'), making the mutation's intent unambiguous. No sibling tool competes for this function (the others are all reads or work-order mutations), so differentiation is trivially satisfied.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by 'active alarm' and the note that repeat calls are safe, which tells the agent it need not pre-check acknowledgement state. However, there is no explicit when-not-to-use guidance, no mention of prerequisites (e.g. permissions or alarm state requirements), and no named alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

assign_work_orderA
Idempotent

Assign (or reassign) an open or assigned work order. Supervisors only.

ParametersJSON Schema
NameRequiredDescriptionDefault
actorYesUsername performing the action, e.g. 'tech.a'. Never guess one.
assigneeYesUsername of a technician or supervisor.
work_order_idYesWork-order id such as WO-2026-0001.

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsYes
work_orderYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this as a non-read-only, idempotent, non-destructive operation, so safety is covered. The description adds value beyond them by disclosing the authorization requirement ('Supervisors only'), which the agent cannot infer from annotations or schema, though it says nothing about side effects on notifications or prior assignees.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, no filler, eligibility scope stated first and the authorization constraint second. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need no explanation, annotations cover the safety profile, and the description supplies the missing auth requirement. What remains thin is the reassignment semantics (what happens to the previous assignee) and the failure mode for ineligible work-order states.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and each parameter has a clear description (actor, assignee, work-order id format), so the schema carries the load. The description adds no parameter-level meaning beyond confirming that work_order_id must reference an open or assigned order; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (assign/reassign) and resource (work order), plus a status constraint ('open or assigned') that narrows which work orders are eligible. It does not explicitly distinguish itself from sibling transition_work_order, which is the nearest ambiguity, so it falls one step short of top marks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Supervisors only' and 'open or assigned work order' give a precondition and an eligibility scope, which is implied usage guidance. However, it never names alternatives (e.g. transition_work_order for status changes) or says what to do when the work order is closed or already assigned to the target user, so routing guidance is incomplete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_work_orderA

Create a new work order (status open). Check list_work_orders for the asset first to avoid duplicates.

ParametersJSON Schema
NameRequiredDescriptionDefault
actorYesUsername performing the action, e.g. 'tech.a'. Never guess one.
titleYes5-120 characters.
wo_typeNoKind of work.corrective
asset_idYesAsset id such as AST-0001.
due_dateNoYYYY-MM-DD, today or later.
priorityNoWork-order priority.medium
descriptionNoWhat is wrong / what to do, up to 2000 characters.
source_alarm_idNoAlarm that triggered this work. Must belong to the same asset and not be cleared. An alarm can have only one active work order.

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsYes
work_orderYes

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this is a non-read-only, non-idempotent, non-destructive, closed-world write. The description adds that the created work order starts in 'open' status, which is useful outcome context. It does not disclose what happens on a duplicate attempt (error vs. silent create), permission requirements, or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, no filler, with the primary action stated first and the duplicate-avoidance prerequisite second. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and full parameter documentation, the description only needs to cover purpose and preconditions, which it does. The main gap is the undefined duplicate-handling behavior, which matters for a non-idempotent create that warns about duplicates.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter (actor, title, asset_id, wo_type, due_date, priority, description, source_alarm_id) is already documented with constraints and enums. The description adds no parameter-level meaning beyond the schema, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a new work order') plus the resulting state ('status open'), so the agent knows exactly what entity is produced. It also names a sibling (list_work_orders) and explains its relationship, which helps separate creation from listing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit pre-step: check list_work_orders for the asset first to avoid duplicates. That is actionable context, but there is no when-not-to-use guidance or mention of alternatives for updating an existing work order (e.g. transition_work_order, assign_work_order).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_assetA
Read-onlyIdempotent

One asset with its uncleared alarms, its active work orders and its last completed work order.

ParametersJSON Schema
NameRequiredDescriptionDefault
asset_idYesAsset id such as AST-0001.

Output Schema

ParametersJSON Schema
NameRequiredDescription
assetYes
active_alarmsYes
open_work_ordersYes
last_completed_work_orderNo

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the operation read-only, idempotent, non-destructive, and closed-world. The description adds genuine scoping context beyond that: alarms are limited to 'uncleared' ones and work orders to 'active' plus the 'last completed' one, which tells the agent exactly what subset of related data to expect from a single read.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence fragment that front-loads the subject ('One asset') and then lists the included records with no filler. It is slightly clipped and verbless, but every word carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value shape need not be spelled out, and the description already defines which related records are included. For a single required-parameter read tool with full annotations, nothing essential is missing; only edge-case behavior (e.g., unknown asset_id) is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single asset_id parameter is fully documented in the schema with a concrete example format ('AST-0001'), and the description adds nothing about it. With 100% schema coverage and no new meaning contributed, this is the baseline 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific resource (a single asset) and enumerates the exact related records bundled with it, which is more informative than a bare 'get'. However, it never states the verb explicitly and does not contrast itself with siblings like list_assets or get_plant_overview, so the agent must infer single-vs-list scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance, no prerequisites, and no mention of alternatives such as list_assets (for many assets) or get_work_order (for detail on one work order). The agent gets no routing help at all.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_plant_overviewA
Read-onlyIdempotent

Counts of assets, active alarms and work orders, overdue work, and critical (A) assets with unacknowledged alarms. Call this first.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
as_ofYes
assets_by_statusYes
overdue_work_ordersYes
work_orders_by_statusYes
active_alarms_by_severityYes
critical_assets_with_active_alarmsYes

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so the safety profile is fully covered by structured data. The description's added contribution is the set of data categories returned, which largely duplicates the existing output schema; it says nothing about refresh/staleness of the counts or how 'overdue' and 'critical (A)' are defined.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler. The scannable inventory of returned metrics comes first and the imperative routing instruction ('Call this first') is placed where it will be acted on.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter dashboard tool, the definition covers everything an agent needs: safety semantics come from annotations, return shape from the output schema, and the description supplies the content scope plus the ordering cue. Nothing required to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so by convention this dimension baselines at 4. There is no parameter surface for the description to clarify, and it correctly avoids inventing pseudo-parameters such as a plant or time-range filter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a concrete aggregation resource (plant overview) and enumerates exactly what it returns: asset, active alarm and work-order counts, overdue work, and critical (A) assets with unacknowledged alarms. The 'counts' framing cleanly separates it from the list_*/get_* siblings, which return records rather than totals, so an agent can route without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Call this first' is explicit, actionable sequencing guidance that tells the agent when to reach for this tool relative to the other nine siblings. It stops short of naming a when-not-to-use condition or an alternative for deeper drill-down, so it is clear context rather than a full decision rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_work_orderB
Read-onlyIdempotent

One work order with its full history of events (who did what, when, and why).

ParametersJSON Schema
NameRequiredDescriptionDefault
work_order_idYesWork-order id such as WO-2026-0001.

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsYes
work_orderYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false and a closed-world scope, so the safety profile is fully covered. The description adds that the return embeds an event history (who did what, when, and why), which is useful content context, but says nothing about error behavior for unknown ids or pagination limits on long histories.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler; every clause (resource, history content, who/what/when/why) earns its place. It is slightly elliptical in omitting an explicit verb like 'retrieves', but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only lookup with an output schema, complete parameter documentation, and full annotation coverage, the description supplies what the agent needs to select and call it. Missing only edge-case behavior (unknown id handling, history size), which is minor given the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter already carries a format example (WO-2026-0001), so the schema does the heavy lifting. The description adds no additional parameter meaning; baseline 3 is appropriate for a fully documented single-param tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific resource (a single work order) and specifies its scope: the full event history with who/what/when/why. The singular framing implicitly distinguishes it from list_work_orders, but it never states its verb explicitly or names a sibling, so differentiation is left to inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance and no mention of alternatives such as list_work_orders for enumeration. The only routing signal is the implied singular vs. plural distinction, which the agent must infer.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_alarmsB
Read-onlyIdempotent

List alarms, most severe and most recent first.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoPage size (1-100).
sinceNoOnly alarms raised at or after this ISO-8601 time (UTC if no zone).
stateNo'active' means nobody has acknowledged it yet.
offsetNoItems to skip; use next_offset from the previous page.
asset_idNoOnly alarms of this asset, e.g. AST-0001.
severityNoFilter by severity.

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
totalYes
next_offsetNo

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and closed-world scope, so the safety profile is fully covered without description help. The description's contribution is the default sort order and implicit paging behavior, which is useful but thin; it says nothing about what a page contains or default filter behavior (e.g., whether cleared alarms are included).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with zero filler; the operation and its ordering guarantee are stated immediately with nothing redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation, and the annotations plus full schema coverage carry the safety and parameter burden. The remaining gap is minor: the description never indicates default filter behavior or that pagination is expected, though offset/limit are documented in the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% — every parameter (limit, since, state, offset, asset_id, severity) has its own schema-level documentation including enums and pagination semantics. The description adds no parameter-level meaning beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (list alarms) and adds the default ordering semantics ('most severe and most recent first'), which is genuinely informative. It does not explicitly name a sibling alternative, but no competing alarm-listing sibling exists, so ambiguity is low.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance, no mention of the filtering options (state, severity, asset_id, since) an agent would need to decide between, and no reference to alternatives such as acknowledge_alarm. Usage is only inferred from the tool name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_assetsA
Read-onlyIdempotent

List assets, most critical first. All filters are optional and combine with AND.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoExact asset type, e.g. 'pump' or 'compressor'.
limitNoPage size (1-100).
queryNoText search over id, name, type, location, maker, model, serial.
offsetNoItems to skip; use next_offset from the previous page.
statusNoFilter by status.
locationNoExact location name, e.g. 'Utilities'.
criticalityNoA is most critical.

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
totalYes
next_offsetNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and closed-world scope, so safety is covered. The description adds two behavioral facts not present in any structured field: the result ordering (most critical first) and that filters are AND-combined. It omits pagination behavior, though the offset parameter description covers that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero filler, and the essential scope (what is listed, ordering) is front-loaded before the filter-combination note.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema, full annotation coverage, and 100% parameter descriptions, the description only needs to supply purpose, ordering, and filter semantics – all of which it does. The one gap is routing guidance versus get_asset, which is minor given how much the structured data carries.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3 and the schema carries the per-parameter detail (type, limit, query, offset, status, location, criticality). The description goes beyond the schema by specifying the cross-parameter interaction rule (AND) and that all are optional, which the schema cannot express.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List assets') plus the result ordering ('most critical first'), so an agent knows exactly what the call returns. It does not explicitly contrast itself with the singular sibling get_asset, so sibling differentiation is only implied by name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'All filters are optional and combine with AND' tells the agent how the filters behave and that the call works with no arguments at all, which is useful context. It gives no when-to-use or when-not-to-use guidance against get_asset or the other list_* siblings, so the usage signal is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_work_ordersB
Read-onlyIdempotent

List work orders, highest priority first, then earliest due date.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoPage size (1-100).
offsetNoItems to skip; use next_offset from the previous page.
statusNoFilter by status.
asset_idNoOnly work orders of this asset, e.g. AST-0001.
assigneeNoUsername the work is assigned to.
priorityNoFilter by priority.
overdue_onlyNoOnly active work orders past their due date.

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
totalYes
next_offsetNo

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent and non-destructive, covering the safety profile. The description adds the one behavioral trait they don't: the deterministic sort order. It says nothing about pagination behavior or result caps, though the schema's offset hint partially covers that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single tight sentence with the ordering constraint front-loaded after the verb; nothing is wasted. It is arguably too terse for a 7-parameter list tool, which keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and full parameter descriptions, the description need not explain return values or field semantics. The annotations cover safety, and the sort order is disclosed; only the pagination contract and the absence of filter guidance remain mild gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all seven parameters are already documented in the schema (including the next_offset pagination hint). The description adds no parameter-level meaning beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('List work orders') plus a meaningful default ordering (priority, then due date). It implicitly distinguishes itself from the singular get_work_order sibling, but never explicitly names alternatives, so it stops just short of full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use or when-not-to-use guidance and never points to get_work_order for a single record or create/assign/transition siblings for mutations. An agent must infer from the name alone that this is the browse/enumerate entry point.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transition_work_orderA

Move a work order along its life cycle. The assignee or a supervisor can start, hold and complete; only a supervisor can close, cancel, unassign or reopen. Use assign_work_order for open -> assigned.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNoReason or result. Required (5+ characters) for on_hold, completed, cancelled, open (unassign) and reopening.
actorYesUsername performing the action, e.g. 'tech.a'. Never guess one.
to_statusYesWork-order status.
work_order_idYesWork-order id such as WO-2026-0001.

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsYes
work_orderYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (non-read-only, non-destructive, non-idempotent), so the bar is lower; the description adds genuinely useful behavioral context by disclosing the role-based authorization rules for each transition group. It does not elaborate on irreversibility or side effects of cancel/reopen, which would have pushed it to a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, zero filler, with the core action and authorization constraint front-loaded before the sibling redirect. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full output schema, complete annotations, and 100% schema coverage, the description only needed to carry the routing and permission context, which it does. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents work_order_id, actor, to_status, and the note requirement. The description adds no syntax or format detail beyond what is in the schema, making the baseline 3 correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Move a work order along its life cycle') and immediately scopes the set of transitions. It explicitly separates itself from sibling assign_work_order, so an agent can tell them apart without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the alternative route for open -> assigned ('Use assign_work_order for open -> assigned') and gives the permission conditions that select between transition paths (assignee/supervisor can start, hold, complete; only supervisor can close, cancel, unassign, reopen). When-to-use and when-not are both explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 10 tool updatesv0.1.0
    • First observedacknowledge_alarm
    • First observedassign_work_order
    • First observedcreate_work_order
    • First observedget_asset
    • First observedget_plant_overview
    • First observedget_work_order
    • First observedlist_alarms
    • First observedlist_assets
    • First observedlist_work_orders
    • First observedtransition_work_order

TDQS

A3.8/5.0

Scored across 10 tools

Disambiguation4/5

Most tools target a clearly distinct resource+action (overview vs list vs get vs mutate). The only real overlap is assign_work_order vs transition_work_order, but descriptions explicitly carve out the boundary ('Use assign_work_order for open -> assigned'), which mostly resolves it.

Naming Consistency5/5

Every tool follows a clean verb_noun snake_case pattern (get_plant_overview, list_assets, get_asset, acknowledge_alarm, create_work_order, assign_work_order, transition_work_order). No casing or verb-style deviations.

Tool Count5/5

10 tools is well within the ideal 3-15 range and each one maps to a distinct CMMS capability (dashboard, asset/alarm/WO reads, and key WO/alarm mutations). Nothing feels padded or missing on count grounds.

Completeness3/5

Work order lifecycle is well covered (create, assign, transition, history), but there are notable gaps: get_asset references 'uncleared' alarms yet no tool clears/resolves an alarm, and there is no way to update a work order or append notes/log entries. Asset creation/editing is also absent, leaving some dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Config-driven MCP server that gives AI scoped, auditable database access without exposing the entire database.
    5 npm
    6
    MIT
  • A
    license
    C
    quality
    A
    maintenance
    Reference implementation of the Operational Ontology pattern: MCP tools are generated from a typed business domain model (objects, links, actions) — one tool per query shape and per action, deliberately no raw SQL tool. Writes pass business-rule preconditions, are audited, and write back to the systems of record; refusals are machine-readable. Ships with a demo orders ontology spanning two legacy
    34
    188
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides a local synthetic MCP stdio service for querying maintenance evidence and preparing human-review-gated advisory packets, with deterministic governance, evidence boundary tracing, and Agent K integrity scoring to separate retrieved evidence from model inference while preserving human review authority.
    4 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to generate audit reports and query financial ledger data via MCP. This demo version contains intentional security vulnerabilities for security testing and should not be used in production.
    -