Predictive Maintenance MCP Server
An MCP server that turns any LLM into an evidence-based vibration diagnostics assistant — load a signal, get fault frequencies, ISO-cited severity, and reports, with all data staying local.
Signal management — list signals on disk or in memory, load single files or atomic batches (including raw binary decode contracts), inspect metadata, generate synthetic test signals, clear the cache.
Spectral analysis — FFT peak picking, envelope-spectrum bearing screening, Welch PSD, STFT spectrogram, time-domain statistics, and sliding-window feature extraction (17 features).
Bearing diagnostics — compute BPFO/BPFI/BSF/FTF from geometry or a verified catalog, extract bearing specs from manuals, and test each expected fault line against a signal's envelope spectrum with deviation, harmonics, and evidence strength.
Integrated diagnosis — one-call pipeline (FFT + PSD + STFT + bearing faults + ISO severity) that degrades to a structured refusal rather than guessing when the unit is undeclared.
ISO severity — 20816-3 zone A–D assessment from a stored signal or a direct mm/s velocity reading, with machine group, support type, custom thresholds, and provenance.
Machine learning — train unsupervised anomaly detectors (OneClassSVM/LOF with PCA) on healthy baselines, score new signals, and visualize PCA space or feature distributions.
Document Q&A — semantic (FAISS/TF-IDF) search across manuals and catalogs, page excerpts, spec extraction, and bearing catalog lookup with typed "not found" results.
Reports — self-contained interactive HTML (FFT, envelope, ISO, signal plots) plus PDF and Word diagnostic reports with server-authored evaluative wording and baseline deltas.
Prognostics — RUL estimation (linear/exponential/Kalman) from repeated measurements and within-recording trend/onset screening.
Maintenance advice — recommendations keyed to ISO zone and a closed canonical fault vocabulary (bearing races, misalignment, unbalance, looseness).
Allows the MCP server to be used with local LLMs (via Ollama) for predictive maintenance diagnostics, keeping data local and avoiding cloud dependency.
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., "@Predictive Maintenance MCP Server Check if bearing is healthy from vibration data"
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.
Predictive Maintenance MCP Server
Give your AI assistant evidence-based vibration diagnostics — machinery fault detection, ISO-cited severity, and diagnostic reports built to support and accelerate expert decision-making.
An open-source MCP server that turns LLMs into condition monitoring assistants for reliability engineers. Its core design rule: the server refuses to guess. No diagnosis is ever inferred from filenames or statistical parameters alone — a fault indication requires matching spectral evidence. Every severity claim cites ISO 20816-3, and the evaluative wording in reports is authored by the server, not improvised by the model. The AI orchestrates the analysis and presents the evidence — detected fault frequencies, matched fault patterns, severity zones — while the final judgment stays with the engineer. Also available as a Claude Code plugin with 9 diagnostic skills.
Choose Your Path
You are | Start here |
Reliability / maintenance engineer — diagnostics in plain language, no coding | Quick Start below · then Engineer's guide for your own data, manuals and workflows |
AI / MCP developer — run, integrate, and extend the server | |
Researcher / evaluator — how the numbers are measured | Benchmark Methodology · Benchmark below |
Related MCP server: LineSight
What Can It Do?
Point the AI at a vibration signal → get the evidence behind the fault — detected frequencies, matched fault patterns, ISO-cited severity — to support your call.
You say | The AI does |
"What does the vibration say about this bearing?" | Loads the signal, tests each characteristic fault line against the noise floor of the envelope spectrum, reports what the evidence is consistent with and what it cannot exclude, cites the ISO 20816-3 severity zone |
"Generate a full diagnostic report" | Produces an interactive HTML report with charts, fault markers, and server-authored severity wording |
"Extract specs from test_pump_manual.pdf and diagnose the signal" | Reads the equipment manual, looks up the bearing model, calculates expected fault frequencies, tests each of them in the signal's envelope spectrum |
"Train an anomaly detector on my healthy baselines, then flag anomalies" | Trains a model on your normal data, scores new signals, flags outliers for your review |
"What changed on pump P-101 since the baseline?" | Reads the asset's recorded history, compares the latest acquisitions with the declared reference, and reports each indicator's change with the criterion it applied |
The AI doesn't guess: it calls 48 specialized MCP endpoints (44 tools + 4 prompts) running locally on your machine. These counts describe the main branch; tools listed under Unreleased in the CHANGELOG are not yet in the published PyPI package. Every signal is referenced by a single signal_id handle from load to report. Your data never leaves your infrastructure.
Full endpoint reference, grouped by category: Tool Catalog.
Quick Start
One route, from a fresh clone to a first diagnosis in Claude Desktop. You need Git, uv (it fetches Python 3.11 by itself) and Claude Desktop.
1. Clone the repository. The 20 sample signals come with the clone, not with the PyPI package or with the source ZIP and tarball archives generated from this revision: real bearing measurements from the MathWorks rolling-element bearing dataset, healthy baselines plus inner and outer race faults, each with its companion metadata (data/README.md).
git clone https://github.com/LGDiMaggio/predictive-maintenance-mcp.git
cd predictive-maintenance-mcp2. Install and connect. On Windows, one script creates the environment, installs the server and writes the Claude Desktop entry (clones inside OneDrive or other synced folders are handled):
powershell -ExecutionPolicy Bypass -File setup_claude.ps1uv venv .venv --python 3.11
uv pip install --python .venv/bin/python .Add this entry to ~/Library/Application Support/Claude/claude_desktop_config.json, with the absolute path of your clone in place of /path/to/predictive-maintenance-mcp. If a predictive-maintenance entry is already there, replace it:
{
"mcpServers": {
"predictive-maintenance": {
"command": "/path/to/predictive-maintenance-mcp/.venv/bin/python",
"args": ["-m", "predictive_maintenance_mcp"],
"env": { "PDM_PROJECT_DIR": "/path/to/predictive-maintenance-mcp" }
}
}
}PDM_PROJECT_DIR tells the server where the sample signals and the reports live. Keep every path absolute: Claude Desktop launches servers with a minimal PATH.
3. Restart and check. Quit Claude Desktop completely (File, then Quit) and start it again. In a new chat ask:
"List the available vibration signals."
The 20 included signals should appear. If they do not, see INSTALL.md, Troubleshooting.
4. First diagnosis. Try:
"Load real_train/OuterRaceFault_1.csv. The shaft runs at 1500 rpm: check the bearing against the fault frequencies declared in its metadata, assess the ISO severity and generate the envelope report."
What comes back is the server's evidence, not the model's opinion: in the envelope spectrum the outer-race and inner-race lines both stand above the local noise floor, each with a further line of its own, so the evidence of this single spectrum is consistent with more than one fault type, and the check lists both with their levels without singling either out, while neither the ball nor the cage line stands above the floor; the ISO 20816-3 severity zone of the broadband velocity, with the machine group and support type the assessment assumed; and the path of an HTML report in reports/ with those frequencies marked on the envelope spectrum. The call on the machine stays with you.
The file name carries the fault label, but the server never reads names. Ask which frequencies matched and with what deviation: the answer rests on the spectrum alone.
Use your own data. Put a single-column CSV without a header row where the server can read it (a folder of yours under data/signals/, or an absolute path), add a <name>_metadata.json next to it with sampling_rate and signal_unit (for example "g"), and ask for the analysis stating the shaft speed. Details and traps: Use Your Own Data.
Other clients: Claude Code, VS Code, Cursor and any other MCP client: INSTALL.md, Manual Setup.
Benchmark
A blind, reproducible benchmark of the bearing check on the public CWRU Bearing Data Center dataset (12 kHz drive-end subset: 60 fault records + 4 normal baselines). Fault labels never reach the system under test — signals enter under opaque ids, a separate scorer is the only label reader, and blindness, checksum integrity, and determinism are enforced by CI-run guard tests, not prose. Results are stratified by the per-record diagnosability grades of the Smith & Randall (2015) reference study, so records that study found undiagnosable by any classical method are reported separately instead of inflating or deflating the headline.
On the records the reference study grades clearly diagnosable (Y1+Y2, 44 records), the line tested for the labelled fault stood above the local noise floor on 44/44, and the labelled fault was supported, with a further line of its own, on 44/44. Another fault type was supported as well on 44/44; the check listed several types, the labelled one among them, on 44/44 and singled out no fault type on 44/44. The labelled fault was the first candidate listed, by level over the noise floor, on 40/44 (9/9 on the textbook-signature Y1 stratum); that order is not a ranking of likelihood, and the check names no fault from it. Of the 4 normal baselines, 1 gave no indication and 3 listed bearing candidates, 1 of them singling out one fault type: counts on these recordings, not a specificity rate.
The numbers above are read from the committed, re-runnable artifact (results.json) and drift-guarded by CI: every value is bound to its key in the artifact, and a mismatch fails the build. Methodology, blind protocol, and honest-benchmarking notes: docs/benchmark-methodology.md. Reproduce with:
python -m benchmarks.cwru allClaude Code Plugin
The project includes a plugin for Claude Code with domain-specific skills that activate automatically during conversation.
/plugin marketplace add LGDiMaggio/predictive-maintenance-mcp
/plugin install predictive-maintenance@predictive-maintenance-marketplaceThe plugin adds 9 skills that activate automatically based on context (bearing-diagnosis, gear-diagnosis, quick-screening, report-generation, anomaly-detection, signal-management, documentation-search, prognostics, experimental shaft-order-evidence), 2 agents that run multi-step diagnostic workflows end-to-end and hand you the evidence (diagnostic-pipeline, signal-explorer), and 3 commands for quick entry points (/pm-diagnose, /pm-screen, /pm-report).
Full skill, agent, and command reference: Plugin README.
Reports
All analysis tools generate interactive HTML reports you can open in any browser — pan, zoom, hover for details. Also supports structured Word (.docx) exports.


Both examples were generated from a synthetic test signal with the generate_test_signal tool. They show what the reports contain; the Zone A result does not describe a real machine.
Report Type | What it shows |
Frequency spectrum | Peak detection, harmonic markers |
Envelope analysis | Bearing fault frequency matching |
Severity assessment | Vibration health zones (ISO 20816-3) |
Word document | Full diagnostic narrative with embedded charts |
PCA visualization | Multi-signal anomaly clustering |
Feature comparison | Side-by-side signal feature analysis |
Asset Health Ledger
A single diagnosis answers "what does this signal show". The asset health ledger answers "what changed on this machine since the reference": every measurement loaded with a declared identity (asset, measurement point, acquisition instant, operating conditions) is recorded in a local append-only ledger with its derived indicators, compared with the healthy baseline the engineer declares, and judged against the reference band with the rule it applied stated in the result. Four tools carry the workflow: declare_measurement_point, declare_healthy_baseline, get_asset_history and assess_asset_change. Contract and operations: Adapter Guide · worked flow: Examples · reference adapter: STWIN.box.
Architecture
YOU (natural language)
│
v
LLM (Claude, GPT, Ollama...)
understands intent, selects tools
│
v ── Model Context Protocol ──
┌──────────────────────────────┐
│ Predictive Maintenance │
│ MCP Server │
│ │
│ Signal Analysis Reports │
│ Fault Detection ML │
│ Severity Rating RAG Docs │
└──────────────────────────────┘
│
v
YOUR DATA (stays local)
signals · manuals · modelsThe codebase follows a modular architecture organized around the ISO 13374 Six-Block Diagnostic standard — signal acquisition, processing, diagnostics, prognostics, and decision support as separate sub-packages. Standards implemented: ISO 13374, ISO 20816-3, MIMOSA OSA-CBM. Module-level detail: Architecture guide.
Key design choices:
Privacy-first — raw vibration data never leaves your machine; only computed results flow to the LLM
LLM-agnostic — works with Claude, ChatGPT, Microsoft Copilot Studio, or any MCP-compatible client. Use Ollama for fully air-gapped deployments
Modular — use only the tools you need, extend with your own
Documentation
Guide | For |
After the first diagnosis: your own data, machine manuals, workflows | |
Understand MCP, extend the server | |
Every MCP endpoint, grouped by category | |
Bring vendor/DAQ raw data in via explicit declarations | |
Claude Code plugin installation and usage | |
Docker + HTTPS for enterprise environments | |
Use with local LLMs (fully air-gapped) | |
ISO 13374 block mapping and module design | |
How the CWRU diagnostic benchmark is measured | |
Complete diagnostic workflows | |
Detailed setup and troubleshooting | |
How to contribute (all skill levels welcome) | |
Version history |
Testing
85%+ test coverage, enforced as a CI minimum, across Windows, macOS, and Linux (Python 3.11 & 3.12) — the current measured figure is on the codecov badge above.
pytest # run all tests
pytest --cov=src --cov-report=html # with coverage report20+ test files covering signal analysis, fault detection, severity assessment, ML models, report generation, RAG search, and real bearing fault data validation.
Roadmap
48 MCP endpoints on the main branch (44 tools, 4 prompts) with modular architecture and a single
signal_idhandleClaude Code plugin (9 skills, 2 agents, 3 commands)
85%+ test coverage enforced in CI, CI/CD on 3 platforms
Docker + SSE/HTTP transport for enterprise deployment
Semantic document search (FAISS + TF-IDF)
Blind, reproducible diagnostic benchmark on the CWRU dataset (extensible to Paderborn)
Customizable severity thresholds
Remaining useful life (RUL) estimation from repeated measurements (linear, exponential, Kalman)
Trend analysis and degradation onset detection
Asset health ledger: per-asset measurement history with a declared reference and qualified comparability
Multi-signal trending and historical comparison
Real-time streaming (MQTT/Kafka)
Fleet dashboard for multi-asset monitoring
CMMS integration (SAP, Maximo, Infor)
Ideas? Open a discussion or create an issue.
Are you using this?
I'd genuinely love to know. Whether you ran it on real machinery or just tried the sample data, drop a line in Discussions — one sentence about your machine or use case is enough. Real-world feedback directly shapes what gets built next.
Related
claude-stwinbox-diagnostics — Extends this project by connecting a physical edge sensor (STEVAL-STWINBX1) to Claude via MCP, with Claude Skills for guided condition monitoring. Same analysis engine, real hardware, operator-friendly reports.
Contributing
Contributions welcome from everyone — not just programmers. Domain experts, technical writers, and testers are equally valued. See CONTRIBUTING.md for paths tailored to your background.
Quick start: browse Issues for good first issue or help wanted labels.
Citation
@software{dimaggio_predictive_maintenance_mcp_2025,
title = {Predictive Maintenance MCP Server},
author = {Di Maggio, Luigi Gianpio},
year = {2025},
version = {0.13.0},
url = {https://github.com/LGDiMaggio/predictive-maintenance-mcp},
doi = {10.5281/zenodo.17611542}
}License
MIT, see LICENSE. The sample data in data/ is licensed separately under CC BY-NC-SA 4.0 (non-commercial); its attribution and terms are in data/LICENSE. For commercial use, replace it with your own machinery data.
Acknowledgments
MCP Python SDK (descended from FastMCP) · Model Context Protocol by Anthropic · Sample data by Eric Bechhoefer, redistributed by MathWorks · Core development assisted by Claude
An open-source predictive maintenance AI agent and condition monitoring copilot — built to support reliability engineers and the developer community.
Available Tools
34 toolsanalyze_envelopeA
Envelope-spectrum analysis of a stored signal (bearing fault screening).
THE unified envelope tool: bandpass filter -> Hilbert
envelope -> mean subtraction + Hann window -> FFT -> top peaks.
The mean subtraction/window step is an intentional U9 fix: the
envelope's DC leakage used to bury the low-frequency FTF zone.
Requires the signal loaded via load_signal() first; the sampling
rate comes from the stored signal metadata.
The requested band must fit the signal: an invalid band (low <= 0,
low >= high, high > Nyquist) raises a ValueError — it is NEVER
silently clamped. The band used is echoed in the result.
By default analyzes the LEADING 1.0-second segment (deterministic:
two identical calls return identical results). Set
segment_duration=None to analyze the entire signal, or pass
random_seed to sample a seeded random segment position instead.
No reference bearing frequencies are assumed: compare the returned
peaks against frequencies computed for the actual bearing and
shaft speed (check_bearing_faults or
calculate_bearing_characteristic_frequencies).
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
signal_id: ID of the stored signal (from load_signal).
filter_low: Bandpass low edge in Hz (default: 500).
filter_high: Bandpass high edge in Hz (default: 5000). Must
not exceed the signal's Nyquist frequency.
num_peaks: Number of top peaks to return (default: 5).
segment_duration: Duration in seconds to analyze (default:
leading 1.0 s). None analyzes the full signal.
random_seed: Seed for random segment position (default: None =
deterministic leading segment).
Returns:
EnvelopeResult with the band actually used, top peaks, and
comparison guidance.
Raises:
ValueError: If the signal_id is not loaded, the stored signal
has no sampling rate, or the band is invalid vs Nyquist.
Inputs: signal_id (required), num_peaks, filter_low, filter_high, +2 more. Returns: Unified envelope-spectrum analysis result (U9 merge). Compact summary: top peak…
analyze_fftA
Perform FFT (Fast Fourier Transform) analysis on a stored signal.
FFT analysis converts the signal from time domain to frequency domain,
allowing identification of harmonic components and faults that manifest
at specific frequencies. Requires the signal loaded via load_signal()
first; the sampling rate comes from the stored signal metadata.
By default analyzes the LEADING 1.0-second segment (deterministic:
two identical calls return identical results). Set
segment_duration=None to analyze the entire signal, or pass
random_seed to sample a seeded random segment position instead.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
signal_id: ID of the stored signal (from load_signal).
max_frequency: Maximum frequency to analyze (default: Nyquist frequency)
segment_duration: Duration in seconds to analyze (default: leading
1.0 s). Set to None to analyze the full signal.
random_seed: Seed for random segment position (default: None =
deterministic leading segment).
Returns:
FFTResult with top peaks, dominant peak, and spectrum stats.
Raises:
ValueError: If the signal_id is not loaded, or the stored signal
has no sampling rate.
Inputs: signal_id (required), random_seed, max_frequency, segment_duration. Returns: FFT analysis result — compact summary (top peaks + stats, no full arrays). Full…
analyze_signal_trendA
Within-recording screening: feature trend + degradation onset.
THE unified screening tool: feature trend AND degradation
onset in one call. Segments a single recording
(seconds of data), extracts the requested feature per segment,
tests whether the per-segment values show a statistically
significant trend (slope p < 0.05), and detects the first segment
AFTER the baseline window (first half of the series) whose value
exceeds baseline mean + onset_threshold_sigma standard deviations.
Onset inside the baseline window cannot be detected (the baseline
defines "normal"). Requires the signal loaded via load_signal()
first; the sampling rate comes from the stored signal metadata.
This is a SCREENING tool, not a prognosis: a trend inside seconds
of signal says whether the recording is stationary, not how long
the machine will live. For Remaining Useful Life, collect repeated
measurements over days/weeks (one recording per session) and pass
them to estimate_rul — this tool returns the per-segment feature
series so each recording can be reduced to one measurement point.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
signal_id: ID of the stored signal (from load_signal).
feature_name: Time-domain feature to analyze (default: "rms").
segment_duration: Duration of each segment in seconds.
overlap_ratio: Overlap between segments (0-1).
onset_threshold_sigma: Baseline standard deviations above the
baseline mean that trigger onset detection (default: 3.0).
Returns:
TrendAnalysisResult with slope, direction (p-value based),
fit quality, the (truncated) per-segment feature series, and
the onset-detection outcome (onset_detected,
onset_segment_index, onset_time_s, baseline_segments).
Raises:
ValueError: If the signal_id is not loaded, or the stored
signal has no sampling rate.
Inputs: signal_id (required), feature_name, overlap_ratio, segment_duration, +1 more. Returns: Within-recording feature trend — screening only, NOT a prognosis. Segments a si…
analyze_statisticsA
Calculate statistical parameters of a stored signal for diagnostics.
Statistical parameters are key indicators for diagnostics:
- RMS: Effective value, correlated to signal energy
- Crest Factor: Indicates presence of impulses (high = possible faults)
- Kurtosis: Measures impulsiveness (excess kurtosis; >0 = non-Gaussian, >3 = strong impulses)
- Peak-to-Peak: Signal range
Requires the signal loaded via load_signal() first. Statistical
parameters are screening indicators, not definitive diagnostics —
combine with frequency-domain evidence.
**Signal units:** all values are in the signal's native unit. The unit
is reported only when DECLARED — load_signal(signal_unit=...) or the
companion _metadata.json — and never guessed from signal amplitude.
ISO 20816-3 severity tools refuse to produce a verdict until the unit
is declared.
Args:
signal_id: ID of the stored signal (from load_signal).
Returns:
StatisticalResult with all statistical parameters
Raises:
ValueError: If the signal_id is not loaded.
Inputs: signal_id (required). Returns: Statistical analysis result of the signal. Values are in the signal's native un…
assess_severityA
Assess vibration severity (ISO 20816-3 zones A-D) and alert level.
THE unified severity tool: ISO zone assessment and alert
classification in one call. Zone boundary values are those of
ISO 10816-3:2009 (ISO 20816-3:2022 merges zones A/B — provenance is
noted in the result). Scope: machines rated above 15 kW; a declared
machine_power_kw below 15 kW is refused.
Input routes (exactly ONE required):
- signal_id: a stored signal (load_signal first). Sampling rate AND
declared unit come from the stored metadata; an undeclared unit is
refused, never guessed from amplitude.
- rms_velocity_mm_s: a direct broadband RMS velocity reading in mm/s
(e.g. from a portable instrument) — no unit declaration needed.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
signal_id: ID of the stored signal (mutually exclusive with
rms_velocity_mm_s).
rms_velocity_mm_s: Direct broadband RMS velocity in mm/s
(mutually exclusive with signal_id).
machine_group: 1 (large, >300 kW) or 2 (medium, 15-300 kW).
Ignored when custom thresholds are given. Default 2.
support_type: 'rigid' or 'flexible'. Ignored when custom
thresholds are given. Default 'rigid'.
thresholds: Optional custom zone boundaries {'warning': A/B,
'alarm': B/C, 'danger': C/D} in mm/s, strictly increasing —
replaces the ISO table for this call.
machine_power_kw: Rated machine power, if known. Declared values
below 15 kW are refused (out of ISO scope); None means
unknown and is not refused.
rpm: Operating speed in RPM (signal route only: selects the 2 Hz
band lower edge below 600 RPM).
Returns:
VibrationSeverityResult (status='assessed') with zone, severity,
boundaries, derived alert_level/exceeded_threshold, and threshold
provenance.
Raises:
ValueError: On route misuse (both/neither inputs), undeclared
signal unit, missing sampling rate, Nyquist below the ISO
band, declared power below 15 kW, negative RMS, or invalid
custom thresholds.
Inputs: rpm, signal_id, thresholds, support_type, +3 more. Returns: Unified severity assessment result (U9 merge — ``assess_severity``). Zone bound…
calculate_bearing_characteristic_frequenciesA
Calculate bearing characteristic frequencies from geometry.
Standard rolling-element kinematic formulas (Randall & Antoni 2011,
"Rolling element bearing diagnostics — A tutorial", MSSP 25(2)).
Requires the EXACT geometry — from the manual, the catalog
(search_bearing_catalog), or the user; never guessed. Deep-groove
ball bearings have contact_angle_deg = 0.
Args:
num_balls: Number of rolling elements (Z)
ball_diameter_mm: Ball/roller diameter (Bd) in mm
pitch_diameter_mm: Pitch circle diameter (Pd) in mm
contact_angle_deg: Contact angle (alpha) in degrees
rpm: Shaft rotation speed in RPM
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with BPFO, BPFI, BSF, FTF in Hz.
Example:
>>> # 6205 geometry (CWRU Bearing Data Center) at 1797 RPM
>>> freqs = calculate_bearing_characteristic_frequencies(
... num_balls=9, ball_diameter_mm=7.94,
... pitch_diameter_mm=39.04, rpm=1797
... )
>>> round(freqs['BPFO'], 2)
107.36
Inputs: num_balls (required), ball_diameter_mm (required), pitch_diameter_mm (required), rpm, +1 more. Returns: object
check_bearing_faultsA
Check expected fault frequencies in a stored signal's envelope spectrum.
THE unified bearing-check tool: catalog lookup, explicit
frequencies, or explicit geometry in one call. Requires the signal
loaded via load_signal() first.
Expected-frequency routes (exactly ONE required):
- bearing_id: catalog lookup (verified entries only) — BPFO/BPFI/BSF/
FTF computed from the catalog geometry; the entry's source citation
is echoed in the result.
- frequencies: explicit {label: hz} dict — for bearings not in the
catalog or non-bearing checks such as a gearbox GMF
(e.g. {"GMF": 350.0}). Labels BPFO/BPFI/BSF/FTF map to the
canonical fault vocabulary; other labels have no canonical form.
- explicit geometry: num_balls + ball_diameter_mm + pitch_diameter_mm
(+ contact_angle_deg) — frequencies computed from user-provided
geometry (out-of-catalog path).
Each check reports fault_type_canonical (outer_race / inner_race /
ball / cage) alongside the acronym.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
signal_id: ID of the stored signal.
rpm: Shaft speed in RPM.
bearing_id: Bearing designation (e.g. '6205', 'SKF 6205-2RS').
frequencies: Explicit expected frequencies {label: hz}, all > 0.
num_balls: Number of rolling elements (explicit-geometry route).
ball_diameter_mm: Ball/roller diameter Bd in mm.
pitch_diameter_mm: Pitch circle diameter Pd in mm.
contact_angle_deg: Contact angle in degrees (default 0.0).
tolerance_pct: Frequency matching tolerance in percent (default 5).
Returns:
BearingFaultsSummary with one check per expected frequency,
overall assessment, most likely fault (+ canonical form), and the
provenance of the expected frequencies (`source`).
Raises:
ValueError: If the signal is not loaded / has no sampling rate, if
not exactly one route is given, if the geometry is incomplete,
if the bearing is not in the catalog, or if frequencies is
empty / non-positive.
Inputs: rpm (required), signal_id (required), num_balls, bearing_id, +5 more. Returns: Summary of all expected-frequency checks for one bearing/machine.
clear_signalsA
Remove one signal — or all signals — from the in-memory repository.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
signal_id: ID to remove; None (default) clears the whole cache.
Returns:
Dict with cleared_count, plus signal_id and status ('removed' or
'not_found') for single-signal calls.
Inputs: signal_id. Returns: object
compute_power_spectral_densityA
Compute Power Spectral Density (Welch method) for a stored signal.
Requires signal loaded via load_signal() first.
Args:
signal_id: ID of the stored signal.
nperseg: Samples per FFT segment (default 256).
noverlap: Overlap between segments (default 128).
window: Window function (default 'hann').
Inputs: signal_id (required), window, nperseg, noverlap. Returns: Power Spectral Density (Welch method) result.
compute_spectrogram_stftA
Compute STFT spectrogram for a stored signal.
Returns time-frequency summary (no full 2D array). Use for detecting
time-varying frequency content (transient faults, speed changes).
Args:
signal_id: ID of the stored signal.
nperseg: Samples per STFT segment (default 256).
noverlap: Overlap between segments (default 128).
window: Window function (default 'hann').
Inputs: signal_id (required), window, nperseg, noverlap. Returns: STFT Spectrogram result — summary only, no full 2D arrays.
diagnose_vibrationA
Full integrated diagnosis: FFT + PSD + STFT + bearing faults + ISO severity.
Comprehensive vibration diagnostic pipeline. Loads signal from repository,
runs all analyses, and synthesizes results into an actionable report.
The ISO severity block uses ISO 20816-3 machine group/support type
(zone boundaries from ISO 10816-3:2009, provenance noted in output).
The diagnosis DEGRADES instead of failing when the ISO verdict cannot
be produced honestly: if the stored signal has no declared unit (or
the sampling rate cannot cover the ISO evaluation band), the
iso_severity block is a structured refusal (status='refused' with
reason and remedy) while the spectral, bearing, and anomaly blocks
still run. Units are never guessed from amplitude — declare them via
load_signal(signal_unit=...) or the companion _metadata.json.
Args:
signal_id: ID of the stored signal.
rpm: Machine operating speed in RPM.
bearing_id: Bearing designation for fault detection (optional).
machine_group: 1 (large, >300 kW) or 2 (medium, 15-300 kW).
Default 2.
support_type: 'rigid' or 'flexible'. Default 'rigid'.
Raises:
ValueError: If the stored signal has no sampling rate.
Inputs: rpm (required), signal_id (required), bearing_id, support_type, +1 more. Returns: Full integrated diagnosis pipeline result.
estimate_rulA
Estimate Remaining Useful Life from repeated measurements over time.
RUL is only physically meaningful when fitted on a degradation trend
across MULTIPLE measurements of the same machine taken at different
times (days/weeks/months apart). This tool refuses a single
recording or single point — for within-recording screening use
analyze_signal_trend instead.
Two mutually exclusive input routes (both need `timestamps`, one
entry per measurement, strictly increasing, in `time_unit`):
1. `feature_values`: the degradation indicator already measured
externally (e.g. RMS velocity trended by a data collector).
2. `signal_ids`: one stored signal per measurement session (loaded
via load_signal); each recording is reduced to a single
`feature_name` value.
The degradation indicator is assumed to RISE toward
`failure_threshold`. A statistically significant increasing trend
(slope p-value < 0.05) is required before any RUL is computed; a
flat/insignificant series returns status 'no_degradation_trend'
with no RUL number.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
failure_threshold: Indicator value considered as failure, in the
same units as the feature values. No universal default is
imposed — but when the indicator is broadband VELOCITY RMS
in mm/s, the standard choice is the ISO 10816-3:2009 zone
C/D boundary that assess_severity / get_zone_boundaries()
reports for the machine's group and support (single source
of truth — no boundaries restated here).
timestamps: Measurement times in `time_unit`, strictly
increasing (e.g. hours since first measurement).
feature_values: Indicator values, one per measurement
(mutually exclusive with signal_ids).
signal_ids: Stored signal IDs, one per measurement session
(mutually exclusive with feature_values).
feature_name: Time-domain feature used to reduce each signal
(default: "rms"). Ignored for feature_values input.
method: "linear" (default), "exponential", or "kalman"
(kalman needs approximately uniform measurement spacing).
time_unit: Label for the time axis; RUL and
observation_horizon are expressed in this unit.
Returns:
RULEstimationResult with status, rul (only when estimated),
fit_r_squared (goodness of fit — NOT a confidence),
observation_horizon, and a plain-language message.
Inputs: timestamps (required), failure_threshold (required), method, time_unit, +3 more. Returns: Remaining Useful Life estimate from repeated measurements over time. RUL is onl…
extract_features_from_signalA
Extract time-domain features from a stored signal using sliding windows.
Segments the signal into overlapping windows and extracts 17 statistical features
from each segment. Features include: mean, std, RMS, kurtosis, crest factor, entropy, etc.
Requires the signal loaded via load_signal() first; the sampling rate
comes from the stored signal metadata. Returns an in-memory summary
only — no CSV is written to data/signals/.
Args:
signal_id: ID of the stored signal (from load_signal).
segment_duration: Duration of each segment in seconds (default: 0.1)
overlap_ratio: Overlap between segments, 0-1 (default: 0.5 = 50%)
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
FeatureExtractionResult with features matrix and metadata
Raises:
ValueError: If the signal_id is not loaded, or the stored signal
has no sampling rate.
Example:
extract_features_from_signal(
"healthy_motor",
segment_duration=0.2,
overlap_ratio=0.5
)
Inputs: signal_id (required), overlap_ratio, segment_duration. Returns: Result of time-domain feature extraction from signal segments.
extract_manual_specsA
Extract machine specifications from an equipment manual (PDF).
Extracts bearing designations (e.g. SKF 6205), operating speeds
(RPM), power ratings (kW/HP/MW), and a text excerpt. Results are
cached. If a bearing's geometry is not in the manual, follow up
with search_bearing_catalog(bearing_id=...); if it is not in the
catalog either, ask the user for the geometry — never invent it.
Args:
file_name: Manual filename in resources/machine_manuals/
use_cache: Use cached extraction if available (default: True)
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with extracted specifications and text excerpt.
Raises:
FileNotFoundError: If the manual does not exist (the message
lists the available manuals).
Inputs: file_name (required), use_cache. Returns: object
generate_diagnostic_reportA
Generate the integrated diagnostic report — one document, whole case.
Runs the full diagnosis, then renders signal overview, ISO severity,
anomaly state, characteristic-frequency matching, spectral energy, an
annotated envelope spectrum, and recommended actions into a single
self-contained document.
AUTHORSHIP CONTRACT — this matters more than it may appear. Every
evaluative sentence in the returned ``statements`` list was written by
this server. Reuse them verbatim when presenting the result. Do NOT coin
standard names, machine classes, severity zones, or confidence levels of
your own: this server deliberately publishes no confidence figure, and
the standards caveat that travels with every severity verdict must not be
dropped or paraphrased. If a question is not answered by these
statements, say so rather than filling the gap.
Unlike ``generate_diagnostic_report_docx``, this tool takes no content
sections from the caller. Supply the analysis inputs; the wording is the
server's.
Args:
signal_id: ID of the stored signal (from load_signal).
rpm: Machine operating speed in RPM.
bearing_id: Bearing designation for characteristic-frequency
matching. Omitted means the matching section states why it was
not attempted rather than disappearing.
machine_group: ISO 20816-3 group — 1 (large, >300 kW) or 2 (medium,
15-300 kW). Default 2.
support_type: 'rigid' or 'flexible'. Default 'rigid'.
baseline_signal_id: Optional stored signal from the same machine in a
known-good state. Supplying it turns absolute readings into
deltas, which is what tells a reader whether a condition is new
or stable.
formats: Renderings to produce — any of 'html', 'pdf'. Defaults to
['html']. 'pdf' requires
``pip install predictive-maintenance-mcp[pdf]``.
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dict with ``statements`` (every authored sentence, in document
order), ``files`` (one entry per rendering), ``verdict``,
``evidence_strength``, and ``provenance``.
Raises:
ValueError: If a signal id is not loaded, has no sampling rate, or an
unsupported format is requested.
Inputs: rpm (required), signal_id (required), formats, bearing_id, +3 more. Returns: object
generate_diagnostic_report_docxA
Generate a structured Word (.docx) diagnostic report for a stored signal.
Requires: ``pip install predictive-maintenance-mcp[docx]``
``sections`` is a dict whose keys define what to include (all optional):
- statistics: dict (RMS, Kurtosis, Crest Factor …)
- fft_peaks: list [{frequency, magnitude_db, note}, …]
- envelope_peaks: list [{frequency, magnitude_db, match}, …]
- bearing_frequencies: dict {BPFO, BPFI, BSF, FTF}
- iso: dict (mapped from assess_severity output)
- diagnosis: str (free-text diagnostic summary)
Args:
signal_id: ID of the stored signal (from load_signal); used for
the report title / filename.
sections: Content sections to include (see above)
title: Optional custom report title
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with file_path, file_name, and per-section summary.
Raises:
ValueError: If the signal_id is not loaded, or python-docx is
not installed.
Inputs: sections (required), signal_id (required), title. Returns: object
generate_envelope_reportA
Generate professional envelope analysis report (HTML) for a stored signal.
Generates a professional HTML report file instead of inline content.
Saves to reports/ directory. Requires the signal loaded via
load_signal() first; the sampling rate comes from the stored signal
metadata. Reference bearing frequencies (BPFO/BPFI/BSF/FTF) can be
passed explicitly or, if omitted, are read from the source file's
companion _metadata.json when present.
Args:
signal_id: ID of the stored signal (from load_signal).
filter_low: Bandpass filter low cutoff (Hz). Default 500 Hz
filter_high: Bandpass filter high cutoff (Hz). Default (None)
adapts to the signal: min(5000, Nyquist-1). An explicit value
above Nyquist is rejected, never clamped.
max_freq: Max envelope spectrum frequency to display. Default 500 Hz
num_peaks: Number of peaks to detect. Default 15
bearing_freqs: Optional dict with BPFO, BPFI, BSF, FTF
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with file path, metadata, and summary (NO HTML content)
Raises:
ValueError: If the signal_id is not loaded, or the stored signal
has no sampling rate.
Example:
>>> # Bearing frequencies computed for YOUR bearing/rpm (here: 6205
>>> # per CWRU geometry at 1797 RPM)
>>> result = generate_envelope_report(
... "real_train_OuterRaceFault_1",
... bearing_freqs={"BPFO": 107.36, "BPFI": 162.19, "BSF": 70.58, "FTF": 11.93}
... )
Inputs: signal_id (required), max_freq, num_peaks, filter_low, +2 more. Returns: object
generate_feature_comparison_reportA
Generate feature comparison report with violin plots comparing time-domain features.
Creates interactive HTML report with violin plots showing distribution of 17
time-domain features across different signal groups (e.g., Healthy vs Faulty).
Requires every signal loaded via load_signal() first; each signal's
sampling rate comes from its stored metadata.
**Strategy**: Same HTML report approach as other reports. Useful for understanding
which features are most discriminative for fault detection.
Args:
signal_groups: Dictionary mapping group names to lists of stored
signal IDs.
Example: {"Healthy": ["real_train_baseline_1"],
"Faulty": ["real_train_OuterRaceFault_1"]}
segment_duration: Segment duration in seconds (default: 0.1s for ML)
overlap_ratio: Overlap ratio 0-1 (default: 0.5)
features_to_plot: List of feature names to plot (default: all 17 features)
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with file path, metadata, and summary
Raises:
ValueError: If a signal_id is not loaded or has no sampling rate.
Example:
>>> generate_feature_comparison_report(
... signal_groups={
... "Healthy": ["real_train_baseline_1", "real_train_baseline_2"],
... "Inner Fault": ["real_train_InnerRaceFault_vload_1"],
... "Outer Fault": ["real_train_OuterRaceFault_1"]
... }
... )
Inputs: signal_groups (required), overlap_ratio, features_to_plot, segment_duration. Returns: object
generate_fft_reportA
Generate an interactive FFT spectrum report (HTML) for a stored signal.
Saves a self-contained Plotly HTML report (spectrum in dB, automatic
peak detection, harmonic labels) to the reports/ directory with a
timestamped filename — consecutive runs produce distinct files.
Requires the signal loaded via load_signal() first; the sampling
rate comes from the stored signal metadata.
Args:
signal_id: ID of the stored signal (from load_signal).
max_freq: Maximum frequency to display (Hz). Default 5000 Hz
num_peaks: Number of peaks to detect and label. Default 15
rpm: Optional shaft speed in RPM — peaks at integer multiples
of rpm/60 Hz are labeled as 1x/2x/... harmonics.
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with file path, metadata, and summary (NO HTML content)
Raises:
ValueError: If the signal_id is not loaded, or the stored signal
has no sampling rate.
Inputs: signal_id (required), rpm, max_freq, num_peaks. Returns: object
generate_iso_reportA
Generate an ISO 20816-3 evaluation report (HTML) for a stored signal.
Saves a self-contained Plotly HTML report (color-coded A-D zone
chart with the measured RMS marker, boundaries, severity text) to
the reports/ directory with a timestamped filename. The evaluation
itself is delegated to assess_severity — requires the signal loaded
via load_signal() first with sampling rate AND a declared unit
(units are never guessed).
Args:
signal_id: ID of the stored signal (from load_signal).
machine_group: 1 (large, >300 kW) or 2 (medium, 15-300 kW)
support_type: 'rigid' or 'flexible'
rpm: Operating speed in RPM (optional; selects the ISO band's
lower edge below 600 RPM)
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with file path, metadata, and summary (NO HTML content)
Raises:
ValueError: If the signal_id is not loaded, or the stored signal
has no sampling rate or no declared unit.
Inputs: signal_id (required), rpm, support_type, machine_group. Returns: object
generate_maintenance_recommendationsA
Generate maintenance recommendations based on severity and detected faults.
Combines ISO zone-based urgency with fault-specific maintenance
actions. This tool intentionally does NOT accept a confidence
value: any number supplied by the caller would be echoed into
advisory output without evidential basis.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
severity_zone: ISO zone letter — "A", "B", "C", or "D".
fault_types: Detected fault types from the closed canonical
vocabulary — outer_race/inner_race/ball/cage for bearings
(NOT the BPFO/BPFI/BSF/FTF acronyms) plus misalignment/
unbalance/looseness. None for zone-only advice.
Returns:
Formatted string listing all maintenance recommendations.
Raises:
ValueError: If any fault type is outside the canonical
vocabulary (the message lists the allowed values —
unknown values are never dropped silently).
Inputs: severity_zone (required), fault_types. Returns: result
generate_pca_visualization_reportA
Generate PCA visualization HTML report showing test data in 2D PCA space.
Creates interactive scatter plot with:
- Test/prediction data (green = predicted healthy, red = predicted anomaly)
- PC1 vs PC2 axes with variance explained
- Hover information showing segment details and prediction status
**IMPORTANT**: Labels show MODEL PREDICTIONS, not ground truth. Use `true_labels`
parameter to provide actual labels for validation visualization.
Requires the test signals loaded via load_signal() first; each
signal's sampling rate comes from its stored metadata.
Args:
model_name: Name of trained model (e.g., 'bearing_health_model')
test_signal_ids: Optional list of stored signal IDs to predict and visualize
true_labels: Optional dict mapping signal_ids to true labels.
Format: {"real_test_baseline_3": "healthy",
"real_test_InnerRaceFault_vload_6": "faulty"}
When provided, legend shows both true and predicted labels for validation.
segment_duration: Segment duration in seconds (default: 0.1s for ML)
overlap_ratio: Overlap ratio 0-1 (default: 0.5)
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with file path, metadata, and summary (includes validation metrics if true_labels provided)
Raises:
FileNotFoundError: If the model does not exist.
ValueError: If a signal_id is not loaded or has no sampling rate.
Example (with validation):
>>> generate_pca_visualization_report(
... model_name="bearing_health_model",
... test_signal_ids=["real_test_baseline_3", "real_test_InnerRaceFault_vload_6"],
... true_labels={"real_test_baseline_3": "healthy",
... "real_test_InnerRaceFault_vload_6": "faulty"}
... )
Inputs: model_name (required), true_labels, overlap_ratio, test_signal_ids, +1 more. Returns: object
generate_test_signalA
Generate a synthetic test signal, save it, and load it into the repository.
The signal is written to data/signals/ with a timestamped filename and a
companion _metadata.json declaring sampling_rate and signal_unit='g'
(synthetic acceleration), then auto-registered in the repository — the
returned signal_id is immediately usable by every analysis, diagnosis,
and ISO severity tool with no manual steps.
Signal content: 'bearing_fault' = 10 Hz impacts modulating a 1 kHz
carrier; 'gear_fault' = 200 Hz mesh tone + harmonics; 'imbalance' =
25 Hz (1500 RPM) tone; 'normal' = broadband noise.
Args:
signal_type: Synthetic fault pattern to generate.
duration: Signal duration in seconds (10 s gives 0.1 Hz resolution).
sampling_rate: Sampling frequency in Hz.
noise_level: Additive white-noise amplitude.
random_seed: Seed for reproducible noise (None = non-deterministic).
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
StoredSignalInfo of the auto-loaded signal (signal_id, declared
sampling_rate and unit 'g').
Inputs: duration, noise_level, random_seed, signal_type, +1 more. Returns: Metadata for a signal stored in the SignalRepository.
get_signal_infoA
Get metadata for a stored signal without loading the full array.
Includes the COMPLETE companion-metadata dict (source_metadata: rpm/
shaft_speed, reference frequencies, ...) alongside the repository
fields (sampling_rate, declared signal_unit, shape, timestamps).
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
signal_id: ID of a signal previously loaded via load_signal.
Returns:
StoredSignalInfo with source_metadata populated from the companion
_metadata.json (empty dict when the file has none).
Raises:
ValueError: If the signal_id is not in the repository.
Inputs: signal_id (required). Returns: Metadata for a signal stored in the SignalRepository.
list_html_reportsA
List HTML reports, or get one report's embedded metadata.
Without file_name: lists every report in reports/ with file name,
type, signal, and size. With file_name: returns that report's
embedded metadata block (absorbed get_report_info). Never returns
HTML content — metadata only, to avoid token consumption.
Args:
file_name: Optional report filename inside reports/ — returns
its metadata instead of the listing.
Returns:
List of report summaries (no file_name), or a dict with the
single report's metadata (file_name given).
Raises:
ValueError: If file_name escapes the reports directory, does
not exist, or carries no metadata block.
Inputs: file_name. Returns: result
list_machine_manualsA
List all machine manuals in resources/machine_manuals/ (PDF/TXT).
Use before read_manual_excerpt / extract_manual_specs, and pass the
returned filenames exactly as-is.
Returns:
List of dicts with filename, size_mb, modified, and path.
Inputs: no named parameters. Returns: result
list_signalsA
List signal files on disk or signals loaded in the repository.
scope='disk' (default): files under data/signals/ that load_signal can
open — use before loading. scope='memory': signals currently cached in
the in-memory repository with their metadata (signal_id, sampling_rate,
declared unit) — use to see which signal_ids are available for analysis.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
scope: 'disk' for loadable files, 'memory' for loaded signal_ids.
Returns:
Dict with scope, count, and either 'files' (relative paths, disk)
or 'signals' (StoredSignalInfo entries, memory).
Inputs: scope. Returns: object
load_signalA
Load one signal — or a batch — into the in-memory repository.
Once loaded, reference the signal by its signal_id in every analysis,
diagnosis, report, and prognostics tool (the load -> analyze ->
diagnose -> report flow uses signal_id as the single handle).
Batch form: pass a LIST of file paths (e.g. for training sets). The
batch is fail-fast and atomic — all paths and derived ids are
validated up front, and on the first problem ONE error names the
offending entries and nothing is loaded. One declared sampling_rate/
signal_unit applies to all files; per-file metadata wins only when
the parameter is omitted. Custom signal_id is not allowed for a
batch (ids derive from each file's relative path).
signal_id default: the path relative to data/signals/ with separators
replaced by underscores — 'real_train/baseline_1.csv' loads as
'real_train_baseline_1', so same-named files in different folders
never collide silently. Re-loading a path whose id already exists is
an explicit error unless overwrite=True.
Signal unit discipline: ISO 20816-3 severity verdicts require a
DECLARED unit — either via this parameter or a 'signal_unit' field in
the companion _metadata.json (explicit parameter wins). Units are
never guessed from signal amplitude; without a declared unit the ISO
severity block is refused with a structured reason and remedy.
Raw binary files (.bin/.raw/.dat): a headerless raw waveform loads
only with a declared decode contract — sample_format AND
sampling_rate are REQUIRED, either as explicit parameters here or as
fields of the companion <stem>_metadata.json next to the file
(explicit parameter wins). The other raw parameters carry documented
defaults, applied by the repository after that merge: byte_order
'little', n_channels 1, channel_index 0, header_offset 0, no
scale_factor. Integer sample formats (int16/int32) decode to raw ADC
counts — declare scale_factor to convert counts into the declared
physical unit (there is no implicit normalization). In a batch the
raw parameters broadcast to ALL files, exactly like sampling_rate.
Declaring raw parameters for a self-describing format (.csv, .npy,
...) is refused as a contradiction. With n_channels > 1 each load
extracts ONE channel and the DERIVED id gains a _ch<channel_index>
suffix; an explicit signal_id is used verbatim — no suffix applies.
Args:
ctx: MCP context. Unused — see this module's docstring on logging.
filepath: Filename relative to data/signals/ or absolute path —
or a list of such paths for an atomic batch load.
signal_id: Custom ID (single-file loads only; default derives
from the relative path).
sampling_rate: Sampling rate in Hz (overrides metadata file).
Required for raw binary files (here or in the companion).
signal_unit: Declared signal unit — 'g' or 'm/s2' (acceleration),
'mm/s' or 'm/s' (velocity). Overrides the metadata file.
overwrite: Replace existing entries on signal_id collision
instead of raising.
sample_format: Raw files only — declared sample dtype ('float32',
'float64', 'int16', 'int32'). REQUIRED for .bin/.raw/.dat
(here or in the companion metadata).
byte_order: Raw files only — declared endianness ('little' or
'big'); documented default 'little'.
n_channels: Raw files only — interleaved channel count in the
file; documented default 1.
channel_index: Raw files only — 0-based channel to extract;
documented default 0.
header_offset: Raw files only — bytes to skip before the first
sample; documented default 0.
scale_factor: Raw files only — optional multiplier applied after
decoding (e.g. ADC counts -> physical unit); default: no
scaling.
Returns:
StoredSignalInfo for a single load; a list of StoredSignalInfo
(input order) for a batch. Raw loads record the effective decode
parameters under raw_format.
Raises:
ValueError: If signal_unit is invalid, the signal data cannot be
loaded, a signal_id collides without overwrite=True, a batch
contains any invalid entry (nothing is loaded), a raw binary
file is missing a required declaration (ONE message names
everything missing plus both remedies), or raw parameters
are declared for a self-describing format.
Inputs: filepath (required), overwrite, signal_id, byte_order, +7 more. Returns: result
plot_signalA
Generate interactive time-domain plot for a stored signal.
Creates an interactive HTML plot showing the signal in the time domain.
Useful for inspecting signal quality, identifying anomalies, and
visualizing transients. Requires the signal loaded via load_signal()
first; the sampling rate comes from the stored signal metadata.
Args:
signal_id: ID of the stored signal (from load_signal).
time_range: [start_time, end_time] in seconds to zoom on a portion (optional)
show_statistics: Show RMS, peak levels as horizontal lines (default: True)
title: Custom plot title (optional)
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Path to generated HTML file
Raises:
ValueError: If the signal_id is not loaded, or the stored signal
has no sampling rate.
Example:
plot_signal(
"bearing_signal",
time_range=[0.1, 0.3], # Zoom on 100-300 ms
show_statistics=True
)
Inputs: signal_id (required), title, time_range, show_statistics. Returns: result
predict_anomaliesA
Predict anomalies in a stored signal using a trained model.
Requires the signal loaded via load_signal() first and a model
trained via train_anomaly_model (its result echoes the model_name
to pass here). Pipeline: segment -> features -> scaler -> PCA ->
predict -> aggregate.
Output is BOUNDED: counts, anomaly ratio, score percentiles, and
up to 10 worst segments — never per-segment arrays, regardless of
signal length.
Args:
signal_id: ID of the stored signal to analyze (from load_signal)
model_name: Name of trained model (default: 'anomaly_model')
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
AnomalyPredictionResult with aggregate statistics and health
assessment.
Raises:
FileNotFoundError: If the model does not exist (the message
lists the models actually on disk).
ValueError: If the signal_id is not loaded, or no sampling rate
is available for segmentation.
Inputs: signal_id (required), model_name. Returns: Result of anomaly detection prediction on new data. Bounded output by design: c…
read_manual_excerptA
Read a text excerpt from a machine manual (PDF or TXT).
Use for consecutive-page reading; for targeted questions prefer
search_documentation. Start with max_pages=10 and increase only if
needed (pages consume tokens).
Args:
file_name: Manual filename in resources/machine_manuals/
(PDF or TXT)
max_pages: Maximum pages to extract (ignored for TXT files)
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Extracted text from the manual.
Raises:
FileNotFoundError: If the manual does not exist.
Inputs: file_name (required), max_pages. Returns: result
search_bearing_catalogA
Search for bearing specifications in the local verified catalog.
Fallback for when the machine manual names a bearing but not its
geometry. The catalog is small BY DESIGN: only entries whose
geometry is traceable to a public source (mandatory `source`
citation). A miss is a legitimate negative outcome — ask the user
for the geometry; never guess it.
Args:
bearing_id: Bearing designation (e.g. "6205", "SKF 6205-2RS")
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with bearing specifications if found, or a
BearingCatalogMiss (status='not_found', suggestion,
catalog_contains) when the bearing is not in the catalog.
Raises:
Exception: If the catalog itself cannot be read (missing or
malformed common_bearings_catalog.json).
Inputs: bearing_id (required). Returns: result
search_documentationA
Semantic search across all machine manuals and bearing catalogs.
Uses vector retrieval (RAG) to find the most relevant passages from
PDFs, text files, and JSON catalogs in resources/.
Backends (chosen automatically):
- FAISS + sentence-transformers (pip install predictive-maintenance-mcp[vector-search])
- TF-IDF keyword search (default, zero extra deps)
The index is built lazily on first call and cached on disk. It is
automatically rebuilt when source files change.
Args:
query: Natural-language question or keywords
(e.g. "bearing 6205 geometry", "maintenance interval pump")
top_k: Number of passages to return (default: 5)
force_reindex: Rebuild the index even if cache is fresh (default: False)
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
Dictionary with ranked results, each containing text passage, source
file, relevance score, and chunk index.
Inputs: query (required), top_k, force_reindex. Returns: object
train_anomaly_modelA
Train ML-based anomaly detection model on healthy data (UNSUPERVISED/SEMI-SUPERVISED).
All signals are referenced by signal_id: load them first with
load_signal — its batch form accepts a list of file paths, e.g.
load_signal(filepath=["real_train/baseline_1.csv", ...]). Each
signal's sampling rate comes from its stored metadata.
Complete pipeline:
1. Extract features from healthy signals (segmentation + time-domain features)
2. Standardize features (StandardScaler - fitted on training data only)
3. Dimensionality reduction (PCA with specified variance explained)
4. Train novelty detection model (OneClassSVM or LocalOutlierFactor) on HEALTHY DATA ONLY
5. Optional hyperparameter tuning using validation data (semi-supervised)
6. Save model, scaler, and PCA transformer
**Training Mode:**
- UNSUPERVISED: Train only on healthy data with automatic hyperparameters
- SEMI-SUPERVISED: Train on healthy data, tune hyperparameters using validation set (healthy + fault)
**Note:** This is NOT supervised learning. OneClassSVM/LOF are trained ONLY on healthy data.
Fault data (if provided) is used ONLY for hyperparameter tuning after training.
**Validation Strategy:**
- If healthy_validation_ids provided: Use those explicitly (no split)
- If healthy_validation_ids NOT provided: Automatic 80/20 split of training data
- If fault_signal_ids provided: Enable semi-supervised mode (hyperparameter tuning)
Args:
healthy_signal_ids: Stored signal IDs with healthy machine data (for training)
segment_duration: Segment duration in seconds (default: 0.1)
overlap_ratio: Overlap ratio 0-1 (default: 0.5)
model_type: 'OneClassSVM' or 'LocalOutlierFactor' (default: 'OneClassSVM')
pca_variance: Cumulative variance to explain with PCA (default: 0.95)
fault_signal_ids: Optional stored signal IDs for HYPERPARAMETER TUNING (semi-supervised)
healthy_validation_ids: Optional stored healthy signal IDs for validation (specificity check).
If not provided, 20% of training data will be used.
model_name: Name for saved model files (default: 'anomaly_model')
ctx: MCP context. Unused — see this module's docstring on logging.
Returns:
AnomalyModelResult with model paths and performance metrics
Raises:
ValueError: If a signal_id is not loaded or has no sampling rate,
or model_name/model_type is invalid.
Inputs: healthy_signal_ids (required), model_name, model_type, pca_variance, +4 more. Returns: Result of anomaly detection model training.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 34 tools
Many tools are clearly separated by resource or analysis type, and the descriptions are detailed. However, several boundaries are fuzzy—diagnose_vibration and generate_diagnostic_report expose nearly the same integrated pipeline, and the frequency/report cluster (analyze_fft, compute_psd, compute_spectrogram_stft, generate_fft_report) requires careful reading to choose correctly.
Names consistently follow lower_snake_case verb_noun and are broadly predictable: list_*, load_*, generate_*_report, analyze_*. Minor deviations—plot_signal versus the generate_*_report family, compute_* versus analyze_* for related analyses, and list_html_reports actually listing all report types—keep it from being perfectly uniform.
34 tools is well above the 25+ threshold for a coherent set and will burden an agent with selection overhead. Many report generators could be consolidated, and the frequency-analysis/report cluster overlaps enough that the same underlying capability is exposed through several different tools.
The server covers the full predictive-maintenance workflow: signal generation/loading/inspection, time- and frequency-domain analysis, bearing checks, ISO severity, anomaly detection, integrated diagnostic reports, and RUL estimation. Gaps are minor—no model listing/deletion, no report deletion, no raw signal export—but the main load→analyze→diagnose→report flow has no dead ends.
Maintenance
Related MCP Connectors
Company and industrial data for AI assistants: datasets, SQL, dashboards, alarms, with approvals.
AI-powered diagnostics for elevator, escalator, and vertical transportation equipment
Manufacturing BI from your AI client: dashboards, OEE, spreadsheets, scheduling, text-to-CAD.
AI data analyst: ask about your Excel, CSV, GA4 or database data and get charts and dashboards back
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables predictive maintenance for electric motors by analyzing stator current signals to detect faults like broken rotor bars, bearing defects, and eccentricity, using spectral and envelope analysis techniques.2123 PyPI9MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to analyze plant-floor data using OEE, Pareto, SPC, and yield-loss calculations, providing continuous-improvement insights from manufacturing data.1-
- AlicenseNot gradedqualityBmaintenanceEnables exploration of manufacturing equipment data and analysis of failure risk, supporting monitoring, failure classification, and anomaly detection through natural language.MIT
- AlicenseAqualityCmaintenanceEnables AI assistants to load vibration signals, detect machinery faults with spectral evidence, assess severity against ISO 20816-3, and generate diagnostic reports locally without guessing.38MIT