Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion INSTRUCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Six FastMCP servers cover IoT data, time-series ML, work orders, vibration diagn

| Server | Tools | Categories | Backing service |
| ----------- | ----- | ------------------------ | -------------------------------------- |
| `iot` | 4 | read | CouchDB |
| `iot` | 7 | read | CouchDB (telemetry + asset registry) |
| `utilities` | 3 | read | none |
| `fmsr` | 2 | read, LLM-use | LiteLLM + `failure_modes.yaml` |
| `wo` | 14 | read, write | CouchDB |
Expand Down
26 changes: 19 additions & 7 deletions docs/mcp-servers.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,17 @@ Six FastMCP servers expose the AssetOpsBench domain logic. Each is a standalone

## iot — IoT Sensor Data

The IoT server reads from **two** databases: telemetry readings (`IOT_DBNAME`, default `iot`) and an
asset **registry** (`ASSET_DBNAME`, default `asset`, loaded from `asset_profile_sample.json`). The
two answer different questions: `assets()`/`sensors()` reflect TELEMETRY — what actually streams (the
**measured** set); `get_asset()`/`asset_sensors()`/`registry_assets()` reflect the REGISTRY — the
asset nameplate and the **installed** sensor inventory (by name). Comparing `asset_sensors()` against
`sensors()` surfaces sensors that are installed but not streaming. The registry also reconciles ids
across systems (Maximo `assetnum`, telemetry `iot_asset_id`, work-order `wo_assetnum`), so an asset
can be looked up by any of its ids.

**Path:** `src/servers/iot/main.py`
**Requires:** CouchDB (`COUCHDB_URL`, `COUCHDB_USERNAME`, `COUCHDB_PASSWORD`, `IOT_DBNAME`)
**Requires:** CouchDB (`COUCHDB_URL`, `COUCHDB_USERNAME`, `COUCHDB_PASSWORD`, `IOT_DBNAME`, `ASSET_DBNAME`)

**Sample assets shipped in the `iot` database** (loaded by `src/couchdb/couchdb_setup.sh`):

Expand All @@ -26,12 +35,15 @@ Six FastMCP servers expose the AssetOpsBench domain logic. Each is a standalone

Synthetic motor vibration data (`asset_id: Motor_01`, from `motor_01.json`) ships in a separate `vibration` database for the vibration MCP server.

| Tool | Category | Arguments | Description |
| --------- | -------- | ------------------------------------------ | ----------------------------------------------------------------------- |
| `sites` | read | — | List all available sites |
| `assets` | read | `site_name` | List all asset IDs for a site |
| `sensors` | read | `site_name`, `asset_id` | List sensor names for an asset |
| `history` | read | `site_name`, `asset_id`, `start`, `final?` | Fetch historical sensor readings for a time range (ISO 8601 timestamps) |
| Tool | Arguments | Description |
| ----------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| `sites` | — | List all sites, discovered dynamically from the asset registry (`siteid`) |
| `assets` | `site_name` | List asset ids registered at a site (telemetry id where present, else `assetnum`) |
| `sensors` | `site_name`, `asset_id` | List **measured** sensor names for an asset (union of keys across its telemetry docs) |
| `history` | `site_name`, `asset_id`, `start`, `final?` | Fetch historical sensor readings for a time range (ISO 8601 timestamps) |
| `get_asset` | `site_name`, `asset_id` | Registry/nameplate detail for one asset (description, assettype, status, location, vintage, installed count) |
| `asset_sensors` | `site_name`, `asset_id` | List the **installed** sensors for an asset, by name (registry inventory) |
| `registry_assets` | `site_name`, `assettype?` | List registry assets with metadata (assettype, vintage, sensor count), optionally filtered by assettype |

## utilities — Utilities

Expand Down
1 change: 1 addition & 0 deletions src/couchdb/.allowed_datafiles
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ src/couchdb/scenarios_data/shared/iot/hydraulic_pump_1.json
src/couchdb/scenarios_data/shared/iot/metro_pump_1.json
src/couchdb/scenarios_data/shared/iot/motor_01.json
src/couchdb/scenarios_data/shared/work_order/workorders.csv
src/couchdb/scenarios_data/shared/iot/asset_profile_sample.json
26 changes: 26 additions & 0 deletions src/couchdb/collections.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,32 @@
]
]
},
"asset": {
"format": "json",
"primary_key": [
"assetnum"
],
"id_prefix": "asset",
"doctype": "asset",
"indexes": [
[
"doctype",
"assetnum"
],
[
"doctype",
"assettype"
],
[
"doctype",
"siteid"
],
[
"doctype",
"iot_asset_id"
]
]
},
"vibration": {
"format": "json",
"primary_key": [
Expand Down
3 changes: 2 additions & 1 deletion src/couchdb/scenarios_data/default/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"shared/iot/metro_pump_1.json",
"shared/iot/hydraulic_pump_1.json"
],
"asset": "shared/iot/asset_profile_sample.json",
"vibration": "shared/iot/motor_01.json",
"failurecode": "shared/failure_code/failure_code_sample.csv"
}
}
184 changes: 184 additions & 0 deletions src/couchdb/scenarios_data/shared/iot/asset_profile_sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
[
{
"_id": "asset:CHILLER6",
"doctype": "asset",
"assetnum": "CHILLER6",
"iot_asset_id": "Chiller 6",
"wo_assetnum": "CHILLER6",
"description": "Chiller 6 (chilled-water plant)",
"siteid": "MAIN",
"orgid": "RIVPLANT",
"status": "OPERATING",
"assettype": "CHILLER",
"serialnum": null,
"manufacturer": null,
"vendor": null,
"priority": null,
"installdate": null,
"changedate": null,
"location": "MAIN-MECH-CH6",
"parent": null,
"vintage": null,
"sensors": [
"Chiller 6 Condenser Water Return To Tower Temperature",
"Chiller 6 Chiller Efficiency",
"Chiller 6 Tonnage",
"Chiller 6 Supply Temperature",
"Chiller 6 Return Temperature",
"Chiller 6 Condenser Water Flow",
"Chiller 6 Schedule",
"Chiller 6 Power Input",
"Chiller 6 Chiller % Loaded",
"Chiller 6 Liquid Refrigerant Evaporator Temperature",
"Chiller 6 Setpoint Temperature",
"Chiller 6 Oil Pressure"
]
},
{
"_id": "asset:mp_1",
"doctype": "asset",
"assetnum": "mp_1",
"iot_asset_id": "mp_1",
"wo_assetnum": null,
"description": "Compressor / pneumatic system",
"siteid": "MAIN",
"orgid": "RIVPLANT",
"status": "OPERATING",
"assettype": "COMPRESSOR",
"serialnum": null,
"manufacturer": null,
"vendor": null,
"priority": null,
"installdate": "2023-10-05",
"changedate": "2008-12-09",
"location": null,
"parent": null,
"vintage": "mid",
"sensors": [
"Compressor_Pressure_bar",
"Pneumatic_Panel_Pressure_bar",
"Cyclone_Filter_Drop_Pressure_bar",
"Tower_Discharge_Pressure_Drop_bar",
"Reservoir_Pressure_bar",
"Oil_Temperature_C",
"Motor_Current_A",
"Air_Intake_Valve_Status",
"Compressor_Outlet_Valve_Status",
"Active_Tower_ID",
"Load_Start_Signal",
"Low_Pressure_Switch_Status",
"Tower_Discharge_Switch_Status",
"Low_Oil_Level_Alarm",
"Airflow_Pulse_Counter"
]
},
{
"_id": "asset:hyd_1",
"doctype": "asset",
"assetnum": "hyd_1",
"iot_asset_id": "hyd_1",
"wo_assetnum": null,
"description": "Hydraulic pump condition-monitoring rig",
"siteid": "MAIN",
"orgid": "RIVPLANT",
"status": "OPERATING",
"assettype": "HYDRAULIC_PUMP",
"serialnum": null,
"manufacturer": null,
"vendor": null,
"priority": null,
"installdate": null,
"changedate": null,
"location": null,
"parent": null,
"vintage": null,
"sensors": [
"PS1_Pressure_bar_100Hz",
"PS2_Pressure_bar_100Hz",
"PS3_Pressure_bar_100Hz",
"PS4_Pressure_bar_100Hz",
"PS5_Pressure_bar_100Hz",
"PS6_Pressure_bar_100Hz",
"FS1_VolumeFlow_l_per_min_10Hz",
"FS2_VolumeFlow_l_per_min_10Hz",
"TS1_Temperature_C_1Hz",
"TS2_Temperature_C_1Hz",
"TS3_Temperature_C_1Hz",
"TS4_Temperature_C_1Hz",
"P1_MotorPower_W_100Hz",
"VS1_Vibration_mm_per_s_1Hz",
"CE_CoolingEfficiency_percent_1Hz",
"CP_CoolingPower_kW_1Hz",
"SE_EfficiencyFactor_percent_1Hz",
"cycle"
]
},
{
"_id": "asset:Motor_01",
"doctype": "asset",
"assetnum": "Motor_01",
"iot_asset_id": "Motor_01",
"wo_assetnum": null,
"description": "Induction motor (vibration-monitored)",
"siteid": "MAIN",
"orgid": "RIVPLANT",
"status": "OPERATING",
"assettype": "MOTOR",
"serialnum": null,
"manufacturer": null,
"vendor": null,
"priority": null,
"installdate": null,
"changedate": null,
"location": null,
"parent": null,
"vintage": null,
"sensors": [
"Vibration_X"
]
},
{
"_id": "asset:PUMP3",
"doctype": "asset",
"assetnum": "PUMP3",
"iot_asset_id": null,
"wo_assetnum": "PUMP3",
"description": "Pump 3",
"siteid": "MAIN",
"orgid": "RIVPLANT",
"status": "OPERATING",
"assettype": "PUMP",
"serialnum": null,
"manufacturer": null,
"vendor": null,
"priority": null,
"installdate": null,
"changedate": null,
"location": "MAIN-PUMPHOUSE",
"parent": null,
"vintage": null,
"sensors": []
},
{
"_id": "asset:AHU2",
"doctype": "asset",
"assetnum": "AHU2",
"iot_asset_id": null,
"wo_assetnum": "AHU2",
"description": "Air handling unit 2",
"siteid": "NORTH",
"orgid": "RIVPLANT",
"status": "OPERATING",
"assettype": "AHU",
"serialnum": null,
"manufacturer": null,
"vendor": null,
"priority": null,
"installdate": null,
"changedate": null,
"location": "NORTH-ROOF",
"parent": null,
"vintage": null,
"sensors": []
}
]
Loading