A side-by-side look at the Forge MCP and Predictive Maintenance MCP Server MCP servers: transport, auth, tools, quality signals, and the config to install either one in Claude, Cursor, Windsurf or VS Code.
Verdict: choose Forge MCP for industrial & iot work over a hosted endpoint; choose Predictive Maintenance MCP Server for industrial & iot as a local process. You can also run both side by side in one mcpServers block.
FOUNDRYNET_API_KEY, FORGE_BASE_URL, PORT, REQUEST_TIMEOUT.identify_machine, normalize_telemetry, query_machine_history.list_signals, generate_test_signal, load_signal.Rows where the two servers differ are marked.
| Spec | ||
|---|---|---|
| Category | Industrial & IoT | Industrial & IoT |
| Quality signal | 59/100 · Good | 63/100 · Good |
| Install command | Confirmed | Confirmed |
| Transport | Remote HTTP/SSE | Local subprocess (stdio) |
| Auth | API key required | Not declared |
| Pricing | Freemium | Not declared |
| Required env vars | FOUNDRYNET_API_KEYFORGE_BASE_URLPORTREQUEST_TIMEOUT | None listed |
| Verified owner | Community listing | Community listing |
| GitHub stars | 0 | 105 |
| Directory activity | 3 views 0 installs 0 upvotes | 1 views 0 installs 0 upvotes |
| Tools | 32 | 34 |
| Full listing | View Forge MCP | View Predictive Maintenance MCP Server |
identify_machineProvision or retrieve a persistent identity (mint_id) for any
industrial machine. Works for CNC machines, industrial robots, PLCs,
additive manufacturing cells, injection molders, presses, turbines,
pumps, compressors, conveyors — any equipment from any OEM:
Fanuc, Siemens, Haas, DMG Mori, Mazak, Okuma, Hurco, Doosan, Makino,
ABB, KUKA, Universal Robots, Yaskawa, Stäubli, FANUC Robotics,
Komatsu, Caterpillar, John Deere, Trumpf, Bystronic, Amada, EMAG,
Bosch Rexroth, Beckhoff, Rockwell Allen-Bradley.
Returns the mint_id (universal handle, format "MINT-xxxxxx"). Idempotent
— calling again with the same (oem, model, serial) returns the same
mint_id with `created: false`.
USE WHEN: a user references a specific machine by OEM/model/serial and
you need a stable handle to attach normalized data, automations, or
tamper-evident work records to. Always call this first when a new machine is
introduced to the conversation, before normalize_telemetry or
create_automation.normalize_telemetryGive your agent a semantic understanding of machine data from any OEM:
translate raw vendor telemetry into one universal canonical schema (FCS,
FoundryNet Canonical Schema) so the agent can reason across vendors it has
never seen before.
Maps vendor-specific column names like "Spindle_Speed", "servo_load_x",
"CoolantTemp", "FeedRateOverride" into standard fields like
spindle_speed_rpm, axes.x_load_pct, sensor_readings.coolant_temp,
feed_override_pct.
Accepts a `data` dict of {raw_field: value}. If `machine_id` (mint_id
or internal_id) is omitted but oem+model+serial are provided, silently
auto-provisions the machine identity (same effect as calling
identify_machine first).
Each call:
- Returns canonical_data + a per-field mapping_id (use mapping_id
with /v1/feedback/{mapping_id}/correct if a mapping is wrong)
- Writes a row to forge_normalized_history (visible via
query_machine_history)
- Evaluates active triggers; the response includes a `triggers_fired`
array if any condition matched. The actual webhooks fire async, so
the array tells you what was triggered without blocking on remote
latency.
USE WHEN: you have raw machine data — a CSV row, a sensor reading, an
MES export, an alarm log line — and need to either (a) understand it
semantically using canonical field names, (b) feed an automation that
watches canonical fields, or (c) build up history for the machine.query_machine_historyRetrieve operational history for an identified machine. Each row is
one /v1/normalize call's canonical output (FCS field → value).
Query options:
from_dt, to_dt ISO-8601 timestamps to bound the time range
fields comma-separated FCS field names to project; omit for
full canonical_data
limit max rows (1–1000, default 100)
summary true → returns aggregate stats only (row_count,
time range, avg coverage_pct, fields_covered set)
without the raw rows. Always cheap.
USE WHEN: your agent needs to reason over how a machine has been running,
surface utilization or throughput or health trends, find patterns in
alarms or operational state, compare periods ("how was today vs
yesterday"), or discover what data is even available for a machine. Prefer
`summary=true` first to orient on volume + which fields are present,
then drill in with field projection on a smaller time window.create_automationLet your agent wire machine telemetry to any business system in plain
English — ERP, CMMS, MES, Slack, Teams, email, Zapier, n8n — via webhooks
already registered as tools on the Forge service. The agent describes the
condition and the action; Forge parses it into a structured trigger.
Examples of `instruction`:
"Alert maintenance Slack when spindle load exceeds 90 percent."
"Create a Fiix work order when coolant temperature stays above 35°C
for five minutes."
"Notify the supervisor when part_count hits 500."
"When the maintenance_type changes to CORRECTIVE, post to the ops
channel."
Returns a `parsed_trigger` JSON for HUMAN review — DOES NOT
auto-activate. The caller (you, with user confirmation) must
explicitly POST the parsed_trigger to /v1/triggers on the Forge API
to actually create it. The response includes
`confirmation_required: true` and may include `notes` if the parser
had to make a fuzzy match (e.g. resolved an ambiguous field name to
its closest canonical match).
USE WHEN: a user wants to set up monitoring, alerts, or automations
for machine state transitions. Always show the parsed_trigger to the
user verbatim and ask "Confirm to activate?" before they activate it.activate_automationActivate a parsed automation trigger on a machine. Call this AFTER
create_automation returns a parsed_trigger and the user explicitly
confirms they want to arm it.
Creates a live trigger that monitors the machine's normalized telemetry
and fires the listed actions when the condition matches. Each action
references a registered tool by tool_id; on fire, the tool's webhook
is POSTed with {{variable}} interpolation against the canonical data
context (mint_id, oem, model, serial, site, field, value, threshold,
plus every canonical field on the matched record).
Inputs:
machine_id mint_id ("MINT-…") or internal_id; resolved to canonical mint_id
name short human label, ≤ 80 chars (e.g. "high spindle load")
condition simple {field, op, value|threshold} OR compound {all: [...]}
ops: >, <, >=, <=, ==, !=
actions list of {tool_id, payload_overrides?, headers_overrides?}
enabled defaults to true; pass false to create the trigger paused
Returns the persisted trigger row including `id` (use it later to
pause/edit/delete via the Forge API). Once active, the trigger fires
on every subsequent normalize_telemetry call where the condition
matches — no further activation needed.
USE WHEN: the user has reviewed the parsed_trigger from
create_automation and said something like "yes, activate it" /
"go ahead" / "arm it." Never call this tool without explicit
confirmation — it changes machine behavior in a way the user can
feel (real Slack messages, real ERP work orders).list_automationsList all active automations / triggers configured for one machine.
Returns each trigger with: id, name, condition (field/op/value or
compound `all`), actions (each resolved to its tool name + url +
method), enabled state, fire_count, last_fired_at, last_error.
USE WHEN: the user asks "what automations do I have on this machine"
/ "show me my triggers" / "what alerts am I getting" / "what's
monitoring this machine right now". Always pass the machine's
mint_id (or internal_id — both resolve).list_guardrailsList the hard safety guardrails configured on one machine.
Returns each guardrail with: id, name, the plain-English instruction it
was created from, its structured condition, scope, and enabled state.
Guardrails are NOT automations. An automation fires an alert and a human
decides; a guardrail blocks the action and nothing decides. You cannot
create, edit, disable, or override a guardrail through this MCP server —
that requires a human administrator. Attempting a write returns 403.
USE WHEN: before proposing or activating anything on a machine — "what
are the limits on this machine", "what am I not allowed to do here",
"why was my automation rejected". Reading this first is cheaper than
being rejected: pair it with check_guardrail to test a specific value.check_guardrailTest whether a proposed action would be blocked, WITHOUT attempting it.
`proposed` is a dict of canonical field -> value you are considering, e.g.
{"spindle_speed_rpm": 13000}.
TWO LAYERS ANSWER, AND ONLY ONE OF THEM ALWAYS EXISTS.
1. Registry-wide PHYSICAL BOUNDS. Always checked, nothing to configure.
These are possibility envelopes for the canonical field, not limits for
your machine: spindle_speed_rpm is declared [-50000, 50000] for every
machine in the fleet.
2. Per-machine GUARDRAILS written by an engineer. These carry the real
operating limits — and they are OPT-IN. A machine nobody has authored
rules for has NONE, and `list_guardrails` returns {"count": 0}.
So on a freshly provisioned machine:
check_guardrail(mid, {"spindle_speed_rpm": 13000})
-> {"would_block": false, "guardrail": null, "reason": null,
"violations": [], "guardrails_evaluated": 0,
"declared_bounds": {"spindle_speed_rpm": [-50000.0, 50000.0]},
"physical_bounds_checked": true}
`would_block: false` with `guardrails_evaluated: 0` does NOT mean 13000 rpm
is safe for that spindle — it means nobody has told Forge what the spindle's
limit is, and 13000 is not physically impossible. DO NOT read it as
permission. Check `guardrails_evaluated`; if it is 0, say so to the user
rather than acting on the absence of a rule.
Once a rule exists the shape is what you would expect:
-> {"would_block": true, "guardrail": "Spindle overspeed protection",
"reason": "spindle_speed_rpm 13000 > limit 12000", "violations": [...]}
A field that resolves to no canonical at all is REFUSED, not passed:
`unresolvable_fields` is returned and the action is blocked, because an
unplaceable field cannot be range-checked.
This is a dry run: it writes nothing and is not recorded as a blocked
attempt. Call it BEFORE acting so you can self-correct to a safe value
instead of being rejected. If would_block is true, do not retry the same
value — adjust to satisfy the stated limit, or tell the user that a human
administrator must change the guardrail.
USE WHEN: you are about to recommend or set a value on a machine and want
to confirm it is inside the safe envelope — and to find out whether an
envelope has been declared at all.disable_automationPause an automation trigger without deleting it. The trigger stops
evaluating against incoming /v1/normalize calls but its configuration
(condition, actions, history) is preserved. Re-enable later by
PATCHing /v1/triggers/{id} with `{"enabled": true}` (or by asking
the user to confirm and creating a follow-up tool for resume).
USE WHEN: the user wants to TEMPORARILY stop an automation — e.g.
"pause the high-spindle alert during planned maintenance," "stop
that alarm for now, I'll re-enable it tomorrow." Distinct from
delete_automation, which is permanent.delete_automationSoft-deletes the trigger (recoverable for 30 days via
restore_automation). The trigger immediately stops evaluating against
/v1/normalize calls and is hidden from list_automations, but the row
persists with deleted_at set so an accidental delete can be undone.
Use restore_automation to undo. For permanent deletion, the API
supports ?permanent=true.
Past forge_trigger_executions rows for this trigger remain in either
case (audit trail).
USE WHEN: the user wants to remove an automation they no longer need —
"delete the coolant alert," "remove that trigger." Safer than hard
delete because misclicks are recoverable; tell the user about
restore_automation if they later change their mind.query_webhook_historyShow webhook delivery history for a trigger — HTTP status codes,
response times, retry counts, errors. Use to verify webhooks are
actually delivering.
Returns up to `limit` most-recent execution rows (default 10, max 200),
each with: fired_at, http_status, attempt_count, response_time_ms,
error (if any), tool_name, target_url, and the settlement reference
(settled_tx) once the row has been rolled up via batch settle.
USE WHEN: a user asks "did the alert actually go out?" / "why didn't
Slack get pinged?" / "is the trigger working?" / "show me the last
few fires." Soft-deleted triggers can still be queried — useful for
forensic audits after a misclick + restore.restore_automationRestore a previously soft-deleted automation trigger within its 30-day
recovery window. Re-enables the trigger so it evaluates against
incoming /v1/normalize calls again.
Returns the restored trigger row plus `restored: true` and the
`restored_at` timestamp. 410 (Gone) if the trigger was deleted more
than 30 days ago and is past the restorable window. 409 if the
trigger isn't actually deleted.
USE WHEN: a user accidentally deleted a trigger and wants it back.
Also useful as the "undo" half of a "delete then change my mind"
flow — pair with disable_automation when the user wants to pause
rather than delete in the first place.list_signalsList 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).
generate_test_signalGenerate 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').
load_signalLoad 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.
get_signal_infoGet 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.
clear_signalsRemove 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.
analyze_fft
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.
analyze_envelope
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.
analyze_statistics
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.
extract_features_from_signal
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
)
compute_power_spectral_densityCompute 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').
compute_spectrogram_stftCompute 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').
assess_severityAssess 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.
Paste either block (or both) into your client config, e.g. claude_desktop_config.json or ~/.cursor/mcp.json. We only show a config when the install command is confirmed.
{
"mcpServers": {
"foundrynet-forge-mcp": {
"url": "https://mcp.foundrynet.io/mcp"
}
}
}
{
"mcpServers": {
"predictive-maintenance-mcp-server": {
"command": "uvx",
"args": [
"predictive-maintenance-mcp"
]
}
}
}