cmms-mcp-server
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., "@cmms-mcp-serverShow me the plant overview and any critical unacknowledged alarms"
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.
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 belowAdd 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 |
| read | counts of assets/alarms/work orders, overdue work, class-A assets with unacknowledged alarms |
| read | filter by status, type, location, criticality, free text; paged |
| read | one asset + its uncleared alarms, active work orders, last completed work order |
| read | filter by state, severity, asset, time; most severe first |
| read | filter by status, priority, asset, assignee, overdue; highest priority first |
| read | one work order with its full event history |
| write, idempotent | take ownership of an alarm; repeating it changes nothing |
| write | optionally linked to an alarm; one active work order per alarm |
| write | supervisors only |
| 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)
`--------`--------------------------`-> cancelledrole | 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, cancelledDesign decisions
Errors are written for a model. A domain error becomes a tool error
code: reasonthat 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_alarmandassign_work_orderare idempotent; nothing is destructive (records are never deleted).--read-onlyremoves 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_ordertwice; 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) andnext_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.
actoris 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. Thestreamable-httpoption 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.mdis guidance I wrote and have not measured.Written for
mcp2.x (MCPServer,from mcp.client.client import Client); version 1.x usedFastMCPand different client entry points, hence themcp>=2.2,<3pin.
Development
uv sync
uv run pytest
uv run ruff checkLicense
MIT, see LICENSE.
Available Tools
10 toolsacknowledge_alarmAIdempotent
Take ownership of an active alarm. Safe to repeat: an already acknowledged alarm is returned unchanged with already_acknowledged=true.
| Name | Required | Description | Default |
|---|---|---|---|
| actor | Yes | Username performing the action, e.g. 'tech.a'. Never guess one. | |
| alarm_id | Yes | Alarm id such as ALM-0001. |
Output Schema
| Name | Required | Description |
|---|---|---|
| alarm | Yes | |
| already_acknowledged | Yes |
TDQS
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.
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.
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.
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.
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.
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_orderAIdempotent
Assign (or reassign) an open or assigned work order. Supervisors only.
| Name | Required | Description | Default |
|---|---|---|---|
| actor | Yes | Username performing the action, e.g. 'tech.a'. Never guess one. | |
| assignee | Yes | Username of a technician or supervisor. | |
| work_order_id | Yes | Work-order id such as WO-2026-0001. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | Yes | |
| work_order | Yes |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| actor | Yes | Username performing the action, e.g. 'tech.a'. Never guess one. | |
| title | Yes | 5-120 characters. | |
| wo_type | No | Kind of work. | corrective |
| asset_id | Yes | Asset id such as AST-0001. | |
| due_date | No | YYYY-MM-DD, today or later. | |
| priority | No | Work-order priority. | medium |
| description | No | What is wrong / what to do, up to 2000 characters. | |
| source_alarm_id | No | Alarm 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
| Name | Required | Description |
|---|---|---|
| events | Yes | |
| work_order | Yes |
TDQS
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.
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.
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.
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.
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.
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_assetARead-onlyIdempotent
One asset with its uncleared alarms, its active work orders and its last completed work order.
| Name | Required | Description | Default |
|---|---|---|---|
| asset_id | Yes | Asset id such as AST-0001. |
Output Schema
| Name | Required | Description |
|---|---|---|
| asset | Yes | |
| active_alarms | Yes | |
| open_work_orders | Yes | |
| last_completed_work_order | No |
TDQS
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.
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.
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.
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.
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.
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_overviewARead-onlyIdempotent
Counts of assets, active alarms and work orders, overdue work, and critical (A) assets with unacknowledged alarms. Call this first.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| as_of | Yes | |
| assets_by_status | Yes | |
| overdue_work_orders | Yes | |
| work_orders_by_status | Yes | |
| active_alarms_by_severity | Yes | |
| critical_assets_with_active_alarms | Yes |
TDQS
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.
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.
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.
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.
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.
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_orderBRead-onlyIdempotent
One work order with its full history of events (who did what, when, and why).
| Name | Required | Description | Default |
|---|---|---|---|
| work_order_id | Yes | Work-order id such as WO-2026-0001. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | Yes | |
| work_order | Yes |
TDQS
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.
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.
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.
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.
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.
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_alarmsBRead-onlyIdempotent
List alarms, most severe and most recent first.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Page size (1-100). | |
| since | No | Only alarms raised at or after this ISO-8601 time (UTC if no zone). | |
| state | No | 'active' means nobody has acknowledged it yet. | |
| offset | No | Items to skip; use next_offset from the previous page. | |
| asset_id | No | Only alarms of this asset, e.g. AST-0001. | |
| severity | No | Filter by severity. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| next_offset | No |
TDQS
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.
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.
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.
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.
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.
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_assetsARead-onlyIdempotent
List assets, most critical first. All filters are optional and combine with AND.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Exact asset type, e.g. 'pump' or 'compressor'. | |
| limit | No | Page size (1-100). | |
| query | No | Text search over id, name, type, location, maker, model, serial. | |
| offset | No | Items to skip; use next_offset from the previous page. | |
| status | No | Filter by status. | |
| location | No | Exact location name, e.g. 'Utilities'. | |
| criticality | No | A is most critical. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| next_offset | No |
TDQS
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.
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.
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.
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.
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.
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_ordersBRead-onlyIdempotent
List work orders, highest priority first, then earliest due date.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Page size (1-100). | |
| offset | No | Items to skip; use next_offset from the previous page. | |
| status | No | Filter by status. | |
| asset_id | No | Only work orders of this asset, e.g. AST-0001. | |
| assignee | No | Username the work is assigned to. | |
| priority | No | Filter by priority. | |
| overdue_only | No | Only active work orders past their due date. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| next_offset | No |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Reason or result. Required (5+ characters) for on_hold, completed, cancelled, open (unassign) and reopening. | |
| actor | Yes | Username performing the action, e.g. 'tech.a'. Never guess one. | |
| to_status | Yes | Work-order status. | |
| work_order_id | Yes | Work-order id such as WO-2026-0001. |
Output Schema
| Name | Required | Description |
|---|---|---|
| events | Yes | |
| work_order | Yes |
TDQS
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.
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.
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.
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.
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.
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.
10 tool updates
v0.1.0- First observed
acknowledge_alarm - First observed
assign_work_order - First observed
create_work_order - First observed
get_asset - First observed
get_plant_overview - First observed
get_work_order - First observed
list_alarms - First observed
list_assets - First observed
list_work_orders - First observed
transition_work_order
TDQS
Scored across 10 tools
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.
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.
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.
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
Related MCP Connectors
Build and run grounded business agents over MCP: agents, knowledge bases, skills, Storylines.
Guarded MCP server for agent-readable business truth, provenance, readiness, and discovery.
Public MCP digital twin with synthetic systems and an agent firewall. No customer data.
Hosted MCP memory and agent control plane for durable conversations, jobs, and operations.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceConfig-driven MCP server that gives AI scoped, auditable database access without exposing the entire database.5 npm6MIT
- AlicenseCqualityAmaintenanceReference 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 legacy34188MIT
- AlicenseNot gradedqualityBmaintenanceProvides 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 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables 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.-