Skip to content

feat: process_folder MCP tool for single-call folder workflows (v4.2.0)#60

Merged
RFingAdam merged 4 commits into
mainfrom
process-folder-mcp
May 13, 2026
Merged

feat: process_folder MCP tool for single-call folder workflows (v4.2.0)#60
RFingAdam merged 4 commits into
mainfrom
process-folder-mcp

Conversation

@RFingAdam
Copy link
Copy Markdown
Owner

Summary

Adds process_folder(folder_path, intent, report, freqs, report_path) — a single MCP entry point that scans a directory, picks the right RFlect workflow (passive HPOL/VPOL pair, active TRP, cal-drift archive, or UWB sweep), runs it, and optionally produces a DOCX report.

Replaces the previous list → bulk → analyze → report chain that MCP clients (Claude Code, Cline, …) had to script manually:

process_folder("/path/to/lab/captures")                     # auto-detect
process_folder("/path/to/wifi", intent="passive", report=True)
process_folder("/path/to/trp",  intent="active",  report=True)
process_folder("/path/to/cals", intent="cal_drift")
process_folder("/path/to/uwb",  intent="uwb")

What changed

  • New rflect-mcp/tools/orchestration.pyregister_orchestration_tools(mcp) exposing process_folder. Auto-detect priority: cal_drift > passive > active > uwb. Mixed folders proceed with the winner and surface a mixed_intents_detected warning.
  • Refactor rflect-mcp/tools/uwb_tools.py — analyze body extracted to _analyze_uwb_channel_dict() so both the existing analyze_uwb_channel MCP tool and the new orchestrator share it.
  • Wire rflect-mcp/server.py — registered, help-text extended.
  • Tests tests/test_mcp_process_folder.py — 9 new tests covering folder-missing, invalid-intent, no-match, mixed-intent priority, explicit passive/active/uwb (monkey-patched delegates), real-delegate cal-drift end-to-end with fixtures, report-failure isolation.
  • Version bumped 4.1.9 → 4.2.0 across pyproject.toml, plot_antenna/__init__.py, README.md, installer.iss, settings.json, .bumpversion.cfg. RELEASE_NOTES entry added.

Behavior contract

  • Never raises. All failure modes (folder missing, no match, partial H/V pair, per-file UWB error, report write failure) return as warnings[] entries.
  • Idempotent for cal-drift — content-hashed dedupe means repeat ingests skip duplicates.
  • No nested-lock risk — the orchestrator does not acquire _measurements_lock; delegates that do (e.g., get_loaded_measurements()) take it briefly and release.

Test plan

  • pytest tests/test_mcp_process_folder.py -v — 9/9 pass
  • pytest tests/test_mcp_integration.py tests/test_mcp_tools.py tests/test_mcp_report.py tests/test_uwb_analysis.py tests/test_uwb_real_data.py tests/test_cal_drift.py — 133 passed, 74 skipped (skips are chamber-data tests unchanged from baseline)
  • Server smoke test: 34 tools registered, process_folder present
  • End-to-end with a real chamber folder once Pages/main lands

🤖 Generated with Claude Code

RFingAdam and others added 2 commits April 16, 2026 13:21
Adds automatic tracking of every Active Chamber Calibration run plus a
GUI + MCP workflow for comparing any two runs. Built on the foundation
restored in e142a8c so chamber/equipment drift (and methodology changes)
are caught before they corrupt downstream measurements.

Core (plot_antenna/cal_drift.py):
- CalRunMeta: one row per TRP Cal file + SHA-256 of every input file +
  header-parsed signal source / receiver / output level from the HPol ref.
- parse_trp_cal_file / parse_cal_file_header / parse_ref_file_header /
  parse_cal_summary_file reuse the "Test Frequency" header-scan pattern.
- history_dir() resolves env RFLECT_CAL_DRIFT_DIR > user_settings.json >
  platform default (~/.config/RFlect/cal_drift on Linux).
- record_run() is idempotent on output_sha256; list_runs / load_points /
  get_run / update_notes / set_setup_group / delete_run round-trip CSV.
- import_historical_dir() walks a directory tree, pairs each TRP Cal file
  with its sibling summary, and falls back to antenna/band-aware scanning
  so BLPA cals never get matched with the HORN gain standard that sits in
  the same folder.
- compute_drift() outer-joins baseline vs current on frequency, returns
  per-pol stats (mean/std/max|Δ|/pct>0.5dB/pct>1dB), a method-consistency
  map, and a missing-frequency audit. Cross-setup_group comparisons are
  flagged on the consistency tab.
- render_delta_plot() / export_markdown() / export_pdf() produce the
  two-panel freq-vs-ΔdB view and printable reports.

Auto-capture (plot_antenna/file_utils.py):
- generate_active_cal_file() appends to the drift log right before return.
  Failures are logged and swallowed — drift recording never breaks cal
  generation. Batch and MCP callers are covered since the hook lives in
  the library, not the GUI.

GUI (plot_antenna/gui/cal_drift_dialog.py + main_window.py + tools_mixin.py):
- New "Tools -> Calibration Drift History..." opens a three-pane dialog:
  runs tree (grouped antenna / band / date) on the left, metric notebook
  (summary stats, consistency, missing-freq audit, raw deltas) in the
  middle, matplotlib plot + PNG/PDF/Markdown export on the right.
- Right-click menu: Set as Baseline, Set as Current, Edit setup group,
  Edit notes, Delete run.
- [Import Historical...] button ingests the user's Downloads archive in
  one click; [Change History Folder...] persists a custom path.

MCP (rflect-mcp/tools/cal_drift_tools.py):
- Eight tools: cal_drift_ingest, cal_drift_list_runs, cal_drift_compare,
  cal_drift_report, cal_drift_history_dir, cal_drift_set_history_dir,
  cal_drift_set_setup_group, cal_drift_set_notes. All delegate to the
  core library so GUI and MCP share identical logic.

Testing (tests/test_cal_drift.py + conftest.py + fixtures):
- 20 tests covering parse / record idempotency / cross-epoch consistency /
  missing-freq audit / historical import / exports.
- tests/conftest.py autouse fixture routes RFLECT_CAL_DRIFT_DIR at a
  per-session tmp dir so the auto-capture hook never pollutes a user's
  real history during testing.
- Synthetic fixtures under tests/fixtures/cal_drift/ keep CI free of any
  ~/Downloads dependency. End-to-end test with real 2026-04-14 samples
  is guarded by the same skip-if-missing pattern as
  test_active_calibration.py.

Verified against the user's ~/Downloads/Calibration Data archive:
12 historical runs (2023-06, 2024-08, 2024-11, 2026-04 x BLPA 690-2700 /
BLPA 4800-6000 / HORN 5850-8200-or-8250) ingested cleanly. BLPA 690-2700
drift 2024 -> 2026 is <0.65 dB and 0% of points over 1 dB; BLPA 4800-6000
drift in the same window is max 4.97 dB and 99% of points over 1 dB —
the tracker immediately surfaced a methodology/hardware issue on the
5 GHz path that was not obvious from any single run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add `process_folder(folder_path, intent, report, freqs, report_path)`
so MCP clients (Claude, Cline, etc.) can run a standard RFlect procedure
on a directory with one call instead of chaining
list_measurement_files → bulk_process_* → analyze → generate_report.

- Intent auto-detection scans for cal-drift, passive HPOL/VPOL pairs,
  active TRP files, and UWB S-parameter sweeps. Priority on tie:
  cal_drift > passive > active > uwb; mixed folders surface a warning.
- Delegates to existing batch helpers (no duplicated logic). UWB analysis
  body extracted from analyze_uwb_channel into _analyze_uwb_channel_dict
  so both the existing MCP tool and process_folder share it.
- Never raises — folder-missing, no-match, partial pairs, per-file UWB
  errors, and report write failures all return as structured warnings[].
- Bumps version 4.1.9 → 4.2.0 and adds RELEASE_NOTES entry.

Tests: 9 new tests in tests/test_mcp_process_folder.py (intent detection,
mixed-intent priority, explicit intents with monkey-patched delegates,
real-delegate cal-drift end-to-end, report-failure isolation). Full MCP
regression suite (133 tests) still passes; 74 skips are the chamber-data
tests that need the local TestFiles directory and remain unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
RFingAdam and others added 2 commits May 13, 2026 09:16
Apply Black 24 formatting to plot_antenna/. The Black CI step in
tests.yml was failing on Python 3.11 because cal_drift.py and several
GUI mixins introduced via eed9c5a had not been formatted.

No behavior change. Black config: line-length 100, target-version py311.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The selection-combining test asserted `combined == 5.0` exactly, which
fails as `4.999999999999999 == 5.0` on some numpy/Python builds (notably
ubuntu CI under Python 3.12) because combining_gain() roundtrips through
a linear → dB conversion. Use pytest.approx(5.0, abs=1e-9) so the assertion
is robust to last-bit float rounding without weakening the contract.

Pre-existing failure surfaced now because the cal_drift commit (eed9c5a)
that PR #60 carries forward had never been pushed to origin before, so
CI on this PR is the first run that hits this code on Python 3.12.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@RFingAdam RFingAdam merged commit bf49485 into main May 13, 2026
9 checks passed
@RFingAdam RFingAdam deleted the process-folder-mcp branch May 13, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant