# rftools [Health: Active]

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/antonpogrebenko-public/rftools-mcp  
**GitHub Stars:** 8  
**npm Downloads (last month):** 2332  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/rftools

## Description
197 RF & electronics calculators for AI agents: microstrip, link budget, filters, power and more.

## Tools
Capabilities this server exposes over MCP:

- **list_calculators** — List the RF and electronics calculators on rftools.io, or those in one category.
Inputs: category, optional: one of rf, pcb, power, signal, antenna, general, motor, protocol, emc, thermal, sensor, unit-conversion, audio, iot. An unknown category is refused with this list.
Example: {"category":"pcb"}
Returns: A JSON array with each calculator's slug, title, category and description. search_calculators finds one by words instead of listing all 255.
- **search_calculators** — Find the calculators that fit a task described in words, in English or in any of the languages rftools.io is published in.
Inputs: query, the words to match (required; English, de, es, fr, ja, ko, pt); category, optional: one of rf, pcb, power, signal, antenna, general, motor, protocol, emc, thermal, sensor, unit-conversion, audio, iot; limit, optional, 1 to 25 results (default 10).
Example: {"query":"trace impedance on FR4 microstrip","limit":5}
Returns: The matches, highest score first, each with slug, title, category, a one-line description, the page URL and its score, plus how many calculators matched in all. A search that matches nothing is reported as an error saying so, not as an empty list. Pass a slug to get_calculator_schema or run_calculation.
- **get_calculator_info** — Describe one calculator: its inputs with units, defaults and bounds, its outputs, formula and keywords.
Inputs: slug, a calculator identifier from list_calculators or search_calculators.
Example: {"slug":"microstrip-impedance"}
Returns: The calculator's slug, title, category and description; its inputs (key, label, unit, defaultValue, min, max, tooltip); its outputs (key, label, unit, tooltip); the formula and keywords. get_calculator_schema returns the same inputs as a JSON Schema.
- **get_calculator_schema** — Give the exact input contract of one calculator as a JSON Schema, with its outputs, formula reference and page URL.
Inputs: slug, a calculator identifier. A misspelt one is refused, naming the closest identifiers.
Example: {"slug":"microstrip-impedance"}
Returns: inputSchema, a JSON Schema 2020-12 object whose properties are the input keys, each a number with its unit (x-unit), minimum, maximum, default and description; outputs (key, label, unit); formula (primary text, LaTeX where there is one, and the reference it comes from); and url.
- **run_calculation** — Compute a calculator's outputs for given inputs, locally in this server, with no API key.
Inputs: slug, and inputs keyed by the calculator's input names in the units get_calculator_schema reports. An input left out takes its declared default and is listed in defaultedInputs; a key the calculator does not declare is not read and is named in a warning; a value outside the declared range is still computed, with a warning naming the range.
Example: {"slug":"microstrip-impedance","inputs":{"traceWidth":3,"substrateHeight":1.6,"dielectricConstant":4.3}}
Returns: slug; results, one per output with key, label, value and unit; webUrl; defaultedInputs; warnings and errors when there are any; and provenance: the formula source, assumptions, whether the inputs lie in the range the calculator is stated for, the inputs used and the engine version.
- **solve_calculation** — Find the value of one calculator input that makes an output equal a target, such as the trace width that gives 50 Ω on microstrip-impedance.
Inputs: slug; inputs, the calculator's other inputs keyed by name in its units; solveFor, the input to solve; target {output, value}; grid, optional, a step to round the answer to; range [low, high], required when solveFor states no bound. get_calculator_schema states every input and output key, unit and bound.
Example: {"slug":"microstrip-impedance","inputs":{"substrateHeight":1.6,"dielectricConstant":4.2,"copperThickness":35},"solveFor":"traceWidth","target":{"output":"impedance","value":50}}
Returns: The solved value (rounded to the grid when one is given, with the unrounded value), reached, which is false when no value in the range meets the target and the nearest value found is returned instead, the number of evaluations, warnings, and the full calculator result at that value with its provenance.
Runs on rftools.io, not locally: it needs RFTOOLS_API_KEY and spends one metered call from the account's monthly allowance, like POST /calculate.
- **simulate_antenna_sim** — Solve your own wire antenna with the NEC-2 method of moments: dipoles, Yagis, verticals and loops, element by element.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Free lane: solveMode cannot be optimize without a paid key. Cross-parameter checks: sweep_stop_after_start. Time budget 1200 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"solveMode":"instant","freq":146000000}
Returns: Peak gain, front-to-back ratio, beamwidths, feed impedance and VSWR (per frequency on a sweep, with the VSWR bandwidth), the azimuth and elevation patterns described as series, and for Optimize the recommended design and its Pareto front. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_emi_radiated** — Estimate radiated emissions from PCB loops and cables using Paul's analytical DM/CM models.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Time budget 240 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"standard":"fcc_b","measDist":3,"dmCurrent_mA":5,"loopArea_cm2":0.5,"cmCurrent_uA":2,"cableLen_m":1,"fClk_MHz":480,"dutyCycle":50,"tRise_ns":0.5,"nTrials":100000} (the "USB 2.0 Trace Loop" preset)
Returns: Pass or fail against the chosen limit, the margin at the 5th, 50th and 95th percentiles, the strongest harmonics, and the emission spectrum and limit line described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_eye_diagram** — Upload a Touchstone (.s2p) file and generate a PRBS eye diagram.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Takes 1 to 1 .s2p/.s4p file(s) via inputFiles (inline) or inputPaths (local paths); the server uploads them. Uploading a file needs an API key; set RFTOOLS_API_KEY. Time budget 120 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"dataRate":10000000000,"prbs":"prbs15","samplesPerUI":64,"inputPaths":["/path/to/file.s2p"]}
Returns: Eye height, eye width and peak-to-peak and RMS jitter (null with a reason when the eye has no crossings), the channel loss, and the eye traces, impulse response and transfer function described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_fdtd_sparam** — Solve microstrip stubs, coupled-line filters, via transitions, and step discontinuities across a ladder of named solve modes — from a 2D cross-section in seconds to a fine 3D openEMS field solve.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Free lane: solveMode cannot be normal or fine without a paid key. Cross-parameter checks: sweep_span_within_center. Time budget 32400 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"structureType":"microstrip_open_stub","substrateName":"FR4","subEr":4.4,"subH":1.6,"subTanD":0.02,"traceW":3}
Returns: The solve mode and method actually used, S11 and S21 in dB and the Smith-chart traces described as series, the summary figures such as resonance, notch depth and input impedance, and flags for a degraded or physically invalid result. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_filter_monte_carlo** — Analyse how component tolerances affect your filter's passband ripple and stopband rejection.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Free lane: monteCarloIterations max 500. Time budget 120 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"filterType":"butterworth","bandType":"lowpass","order":5,"freqCutoff":1000000000,"ripple":0.5,"impedance":50}
Returns: The yield in percent with its 95% confidence interval against the stated ripple and rejection limits, each component with its sensitivity, and the Monte Carlo envelope and the ideal and standard-value responses described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_impedance_matching** — Synthesize L, Pi, T, or ladder matching networks for broadband impedance transformation.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Takes up to 2 .s2p file(s) via inputFiles (inline) or inputPaths (local paths); the server uploads them. Uploading a file needs an API key; set RFTOOLS_API_KEY. Cross-parameter checks: sweep_stop_after_start. Time budget 120 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"sourceR":50,"sourceX":0,"loadR":200,"loadX":0,"freqStart":800000000,"freqStop":1200000000}
Returns: The chosen topology and its component values, snapped to the requested series and ideal, the worst-case return loss in the band and whether the target was met, the achieved bandwidth and Q, and the S11 and Smith-chart trajectory described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_magnetics_optimizer** — NSGA-II optimizer finds Pareto-optimal core and winding designs across 40 cores (E, ETD, PQ, RM and toroids) and 104 core/material combinations, with TDK and Ferroxcube ferrites and Micrometals iron powder.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Cross-parameter checks: converter_load_nonzero. Time budget 360 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"topology":"flyback_xfmr","Vin":48,"Vout":12,"Iout":3,"fSw":100000,"dutyCycle":0.45}
Returns: The best design (core, turns, air gap, wire gauges and flux densities), its losses, efficiency and temperature rise with a thermal pass or fail, and the Pareto front and evolution history described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_pdn_impedance** — Choose decoupling capacitors for a PCB power delivery network.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Cross-parameter checks: port_within_board, sweep_stop_after_start. Time budget 360 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"boardWidth_mm":85,"boardLength_mm":54,"dielectricEr":4.5,"lossTangent":0.02,"boardThickness_mm":1,"portX_mm":28.3,"portY_mm":18,"vrmBandwidth_hz":100000,"vrmDcr_mohm":5,"targetImpedance_mohm":15,"freqMin_hz":1000,"freqMax_hz":500000000,"maxCapCount":15} (the "Credit Card Size (85x54mm)" preset)
Returns: The chosen decoupling capacitors, the worst impedance in the decoupling band against the target with a pass or fail and any frequencies no budget can reach, the cavity resonances of the board, and the impedance curves described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_radar_detection** — Compute probability of detection (Pd) vs range for pulsed radar systems.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Cross-parameter checks: probability_in_open_unit_interval. Time budget 300 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"frequency_hz":3000000000,"peakPower_w":5000,"antGainTx_dbi":35,"antGainRx_dbi":35,"noiseFig_db":4,"pulseWidth_s":0.00001,"nPulses":20,"swerlingModel":"1","targetRcs_dbsm":5,"rangeMax_km":300} (the "Surveillance Radar (Long Range)" preset)
Returns: The detection ranges at 50% and 90% probability, the SNR at maximum range, and the probability of detection against range with its 5th to 95th percentile band and the ROC curve described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_rf_cascade** — Compute cascaded noise figure, gain, IIP3, and P1dB for an N-stage RF signal chain using Friis formulas.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Takes up to 12 .s2p file(s) via inputFiles (inline) or inputPaths (local paths); the server uploads them. Uploading a file needs an API key; set RFTOOLS_API_KEY. Time budget 180 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"stages":"[{\"name\":\"LNA\",\"type\":\"amp\",\"gain_db\":15,\"nf_db\":1.5,\"iip3_dbm\":-5,\"p1db_dbm\":-15},{\"name\":\"BPF\",\"type\":\"filter\",\"gain_db\":-1.5,\"nf_db\":1.5,\"iip3_dbm\":40,\"p1db_dbm\":30},{\"name\":\"Mixer\",\"type\":\"mixer\",\"gain_db\":-7,\"nf_db\":8,\"iip3_dbm\":12,\"p1db_dbm\":2},{\"name\":\"IF Amp\",\"type\":\"amp\",\"gain_db\":20,\"nf_db\":4,\"iip3_dbm\":10,\"p1db_dbm\":0},{\"name\":\"IF Filter\",\"type\":\"filter\",\"gain_db\":-2,\"nf_db\":2,\"iip3_dbm\":40,\"p1db_dbm\":30},{\"name\":\"ADC Driver\",\"type\":\"amp\",\"gain_db\":6,\"nf_db\":6,\"iip3_dbm\":18,\"p1db_dbm\":8}]"}
Returns: Total gain, noise figure, input and output IIP3 and P1dB, SFDR and output power, the cumulative figures after each stage, and the Monte Carlo yield against the specs with its distributions described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_sat_link_budget** — Compute probabilistic link margins using ITU-R propagation models (P.618 rain, P.676 gaseous, P.840 cloud) with climate data read from the ITU-R maps at your site.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Time budget 240 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"latitude_deg":40,"longitude_deg":-74,"linkType":"satellite","frequency_ghz":0.437,"eirp_dbw":-3,"gt_db_k":-12,"distance_km":739,"elevationAngle_deg":30,"modulation":"bpsk","reqEbN0_db":5,"dataRate_bps":9600,"targetAvailability_pct":95} (the "Amateur CubeSat (UHF, AMSAT/SatNOGS)" preset)
Returns: The nominal link budget (free-space loss, gas, cloud and rain attenuation, C/N0 and margin), the margin at the target availability, Monte Carlo margin percentiles, the availability curve described as a series, each climate value with the ITU-R Recommendation it came from, and what is not modelled. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_smps_control_loop** — Model switch-mode power supply control loops using small-signal transfer functions.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Cross-parameter checks: converter_duty_in_ccm_range, converter_load_nonzero. Time budget 300 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"topology":"buck","controlMode":"voltage_mode","Vin":12,"Vout":5,"Iout":2,"L":0.000047}
Returns: The nominal crossover frequency, phase margin and gain margin with a stability verdict, Monte Carlo margin statistics including the share of trials with no margin, and the loop gain, phase and plant responses described as series. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **simulate_sparam_pipeline** — Upload up to 4 Touchstone files and get component values (L, C, R, Q, self-resonance) for a single component, plus insertion loss, return loss, group delay, TDR and passband ripple — all in one automated report.
Inputs: Units, ranges and defaults are in each parameter's schema; one left out takes its default. Takes 1 to 4 .s1p/.s2p/.s3p/.s4p file(s) via inputFiles (inline) or inputPaths (local paths); the server uploads them. Uploading a file needs an API key; set RFTOOLS_API_KEY. Cross-parameter checks: sweep_stop_after_start. Time budget 120 s; waitSeconds (default 90, max 600) bounds the wait.
Example: {"refImpedance":50,"freqStart":0,"freqStop":0,"inputPaths":["/path/to/file.s1p"]}
Returns: The port count, frequency range and detected two-port topology, each analysis stage it ran (network representations, passivity, and the extracted R, L or C with Q and self-resonance) with its values described as series, and any advisories. Also warnings, provenance and the result page link; series are described, not listed (full: true returns everything). If waitSeconds runs out first: the jobId and progress, and the job keeps running.
Runs as a job on rftools.io and counts against the monthly run allowance (free lane without a key).
- **list_simulation_tools** — List the server-side simulation job types with their tool names, parameters, file rules, free-lane bounds and time budgets.
Inputs: none.
Example: {}
Returns: count (13 today); the tier allowances; what runs without a key; how long a result link lives; the duplicate-submission window; and for each job type its simulate_* tool name, jobType, title, parameter names, time budget, file rules and free-lane bounds.
Free tier: 5 runs/month. Pro: 100/month. API tier: 10 000/month. A job runs without a key on the free lane; a job that takes a file does not. Uploading a file needs an API key; set RFTOOLS_API_KEY.
- **submit_simulation** — Start a simulation job named by its job type and return at once with its id, without waiting for the result.
Inputs: jobType, one of the 13 job types list_simulation_tools names; params, that job type's parameters, validated here against its contract before anything is sent (each one's unit, range and default is in the matching simulate_* tool's schema); inputFiles or inputPaths for a job type that takes files. Uploading a file needs an API key; set RFTOOLS_API_KEY.
Example: {"jobType":"antenna_sim","params":{"solveMode":"instant","freq":146000000}}
Returns: jobId, jobType, status, queue position, the time budget, a suggested wait and the result page URL. An identical submission inside 60 s returns the same job.
Counts against the monthly run allowance. The typed simulate_* tool for a job type does the same and waits for the result.
- **get_simulation_status** — Report how far a submitted simulation job has got.
Inputs: jobId, as submit_simulation or a simulate_* tool returned it.
Example: {"jobId":"0b7c6f3e-5d1a-4c2e-9f8a-2a4e6b1d9c07"}
Returns: status, progress from 0 to 1, stage, queue position, start and finish times, whether a result is ready, when the job expires, the result page URL, and for a failed job the error and its kind.
Poll this rather than holding a call open; it spends nothing.
- **get_simulation_result** — Fetch the result of a finished simulation job.
Inputs: jobId; full, optional, true for the whole payload instead of the summary (default false).
Example: {"jobId":"0b7c6f3e-5d1a-4c2e-9f8a-2a4e6b1d9c07"}
Returns: The headline values, warnings and provenance, with every series described rather than listed, the result page URL and a result link that lives 15 minutes. A job that has not finished returns its status and progress instead.
- **run_simulation** — Run a simulation job named by its job type and wait a bounded time for its result.
Inputs: jobType, one of the 13 job types list_simulation_tools names; params, that job type's parameters, validated here against its contract before anything is sent (each one's unit, range and default is in the matching simulate_* tool's schema); inputFiles or inputPaths for a job type that takes files. Uploading a file needs an API key; set RFTOOLS_API_KEY. waitSeconds, 0 to 600 (default 90); full, optional, true for the whole payload.
Example: {"jobType":"antenna_sim","params":{"solveMode":"instant","freq":146000000},"waitSeconds":60}
Returns: The same result the job type's simulate_* tool returns. If the wait runs out first, the jobId and current progress instead, and the job keeps running.
Counts against the monthly run allowance. Sends progress notifications while it waits. The typed simulate_* tool for a job type takes the same parameters with their units in its schema.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "rftools": {
    "command": "npx",
    "args": ["-y","rftools-mcp"],
    "env": {
      "RFTOOLS_API_KEY": ""
    }
  }
}
```

**Requires environment variables:** `RFTOOLS_API_KEY` — the values above are empty placeholders; fill in real credentials before running (see the repository for what each one is for).

## Documentation

## What rftools MCP server does

The rftools MCP server gives MCP-compatible AI clients access to 255 RF and electronics calculators hosted by the rftools package, plus 13 server-side simulation job types. Calculator coverage includes microstrip and transmission-line work, link budgets, filters, power electronics, antennas, component selection, and related engineering calculations. Results include calculator outputs and, for calculation runs, information about defaults, assumptions, formulas, references, and provenance.

The simulation tools cover antenna analysis with NEC-2, EMI radiated-emissions estimation, eye diagrams from S-parameters, FDTD transmission-line analysis, RF filter Monte Carlo analysis, impedance matching, magnetics and transformer optimization, PDN impedance and capacitor optimization, radar detection Monte Carlo runs, RF cascade budgets, satellite and terrestrial link budgets, SMPS control-loop stability, and S-parameter pipelines.

## How it works

The package runs as an MCP server and can be launched with `npx -y rftools-mcp`. Calculator operations can run locally without registration or an API key. Simulation calls that do not use files can be submitted without a key through the free lane, subject to the limits and parameter bounds returned by the service.

Simulation work is submitted as jobs. The available MCP surface includes tools for listing, searching, and inspecting calculator schemas, running or solving calculations, listing simulation types, submitting or running simulations, and checking job status and results. Solving for an input value against a target output is a server-side operation and requires an API key. Reference tables are also available as MCP resources under the `rftools://reference/{domain}/{id}` pattern.

## Setup and configuration

Install the server through an MCP client's standard command configuration. Claude Desktop, Cursor, Windsurf, and Claude Code examples in the project all invoke `npx -y rftools-mcp`. Claude Desktop, Cursor, and Windsurf configurations can pass the key through an `env` object; Claude Code can pass it with `-e RFTOOLS_API_KEY=...`.

Set `RFTOOLS_API_KEY` when the agent must upload an input file, use the server-side calculation solver, or access paid simulation modes. The key is generated from an rftools.io dashboard. Without a key, file inputs are rejected before the file is read or sent.

## Tools and capabilities

The listed simulation entry points include `simulate_antenna_sim`, `simulate_fdtd_sparam`, `simulate_filter_monte_carlo`, `simulate_rf_cascade`, `simulate_sat_link_budget`, and `simulate_sparam_pipeline`, among others. Calculator discovery can use keyword search across titles, descriptions, inputs, outputs, and several translated title and keyword sets. A calculator schema reports units, ranges, defaults, outputs, formulas, references, and the associated page URL.

Use this server for design exploration, engineering checks, parameter studies, and RF analysis workflows where an AI agent needs structured numerical results. Simulation and solver calls consume account allowance and should be treated as non-read-only operations by an MCP host.

## Limitations and notes

Simulation availability depends on the free-lane limits and parameter bounds. An API key is required for file uploads and for the antenna optimizer and FDTD `normal` and `fine` meshes. The server communicates with rftools.io for the applicable server-side operations; its tools do not delete or overwrite external data. Repeated metered submissions can consume allowance, although identical job submissions are merged only within a 60-second window.

_Full upstream README: https://allmcps.com/mcp/rftools/readme_

