I’ve been working on an MCP server for the QA40x software. MCP (Model Context Protocol) servers allow AIs such as ChatGPTs Codex and Claude Code to communicate with applications. But there’s also a discovery piece, where the AI can learn about the problem space and how to best use the controls surfaced by theMCP. This allows you to have a conversation such as below where you are instructing the AI on what measurements you’d like to see at a high level. The first task is a THDN and THD measurement. Seems trivial, but this requires some skill because FFT sizes and input levels can influence measurements. So, the first task is showing how an AI can help less-experienced users make basic measurements. From connection setups to correctly picking measurement parameters…
The second task shows the ease at which the AI can inhale specs and merge that with measured data. For hardware development work, I’m having Codex inhale all the project part specs in PDF, noting pin functions, max voltages/currents on each pin, current on supply pins, package details, etc. All of that is automatically pulled from the PDF and into a database. For design validation, AI is very good at the details. I have written an MCP for my schematic and board layout tools, and I can ask question like “What is the nominal current on the 3.3V line when processor is sleeping and active?” or “Are all the I2C buses corrected correctly, and if so, what are the various peripheral address?” or “Given the expected nominal current of 0.3A on Net 54, what are the trace losses in watts?” It’s just unbelievable how good AI can handle these discussions.
The third task shows shifting gears into algorithmic development–in this case, an attempt at Rub and Buzz measurements. This would continue interactively, with a dozen golden units run and a dozen bad units run, with the engineer and AI trading suggestions on how to tweak and tune to find the bad units, creating tests to aggravate the characteristics of the bad units, etc
What is key here is that the engineer is no longer in front of the software twiddling knobs and documenting. Instead, you are conversing with the AI, making desires known and specifying rules. The documentation is self-completing and part of the paper trail. Summaries can be readily generated by the AI, and conversations recalled along with plots. For the layout tools I mentioned above, I used an SQLite database to capture all the relevant items. And after a 10 minute discussion with the AI on, say, worse-case limits around a collection of parts, I can ask the AI to generate a .md summary of the discussion, create salient keywords, and dump it all into the database. Later, I need only ask “What was the issue we uncovered with relay drive current at low temps and low supply around U17?” and the conversation and graphs all re-appear right out of the SQL database, retrieved by the AI. This jobs my memory, but also the AI’s memory and it can apply what it just recalled to future problems.
This MCP will be released with the next release of the QA40x software. It runs as process that will be started by the AI if you wish. If you don’t like AI, it never runs.
Most are already using AI for coding. But there’s so much more it can do and MCPs are a key enabler.
Conversation below:
User
I have a stdio MCP server at: C:\Users\USER\Documents\VisualStudio\QA\QA402\QA40x_MCP\bin\Debug\net8.0\QA40x_MCP.exe
Launch the server once and keep the process alive for the duration of this task. Communicate with it using MCP JSON-RPC over stdin/stdout. Do not terminate and relaunch it between tool calls. Begin with MCP initialization and capability discovery. Inspect the server’s available tools, resources, instructions, and measurement guidance before operating the analyzer. Do not energize an output during discovery.
Assistant
Marker 1 noted. I’ll treat the server as unfamiliar, launch it once, perform only read-only MCP discovery, and leave the process running afterward.
The server advertises one measurement-guidance resource and a set of analyzer tools. I’m now reading the guidance and querying status/capabilities only; no acquisition or setting-changing tools will be called.
Discovery is complete, and the MCP process remains running on the same stdio connection.
What I learned:
- MCP server:
qa40x-mcpversion0.1.0 - QA40x application reachable: yes
- QA40x version:
1.223 - Analyzer hardware connected: yes
- Acquisition currently idle
- REST backend:
http://localhost:9402/ - Current sample rate is unknown to this newly launched MCP process; it correctly does not assume 48 kS/s.
- The server exposes 13 typed tools covering status, capabilities, guidance, reset/configuration, acquisition, RMS, THD, THD+N, and retained-data export.
- Scientific data can be exported as NPZ; time-domain data can additionally be exported as Float32 WAV.
- One guidance resource is available at
qa40x://docs/measurement-guidance. - No resource templates or MCP prompts are exposed.
The guidance establishes that the analyzer is stateful and requires a DUT interview, explicit wiring/load/attenuation confirmation, safe starting level, expected gain, input-range strategy, and abort conditions before energizing anything.
No acquisition or analyzer-setting command was issued, so discovery did not energize an output.
Amplifier gain, THD, and THD+N
User
I’d like to measure a 1 khz tone into my amplifier. The analyzer is QA403, the amplifier is generic class A amp, with gain around 20 dB. In has single-ended input, single-ended output. it also has a voltage monitoring port. This reports the output with a 20 dB attenuation. I have the amp connected to an 8 ohm speaker. The L+ input of the anlyzer is monitoring the speaker voltage via the attenuated voltage monitor port. And L- is shorted. right now, let’s start at -30 dV. I’d like to know precise amp gain, THD and THDN in a 20 to 20 khz bandwidth. Plot the spectrum you used for the THDN measurement.
Assistant
Before energizing the amplifier, here is my understood setup and test plan.
Connections:
- QA403 L+ OUT → amplifier input
- QA403 L− OUT remains open and must not be grounded
- Amplifier output → 8 Ω speaker
- Amplifier’s −20 dB voltage-monitor port → QA403 L+ IN
- QA403 L− IN is shorted
- Amplifier input and output are single-ended
- Right channel is unused
Plan:
- Reset to defaults, establishing 48 kS/s.
- Set the QA403 input range to its protected 42 dBV range.
- Apply a −50 dBV, 1 kHz probe to confirm gain safely.
- Correct the monitor reading by +20 dB and calculate amplifier gain.
- Apply the requested −30 dBV, 1 kHz tone.
- Select a closer input range.
- Measure THD with increasing FFT sizes until the harmonics converge.
- Measure THD+N over 20 Hz–20 kHz with increasing FFT sizes until the result converges.
- Export and plot the spectrum from the final THD+N acquisition.
- Switch the output off while leaving the MCP process running.
With approximately 20 dB gain, the expected speaker output is −10 dBV, approximately 0.316 V RMS or 12.5 mW into 8 Ω.
Please confirm that L+ OUT is connected as described, L− OUT is open, −30 dBV is the intended starting test level, and that this level is safe for the amplifier and speaker.
User
Go!
Assistant
Proceeding with the protected gain probe, followed by separate converged THD and THD+N measurements. I’ll keep the MCP process alive and switch only the analyzer stimulus off when finished.
The protected probe found the amplifier gain at about 19.9 dB. I’m finishing the FFT convergence runs now, then I’ll export and plot the exact spectrum used for the final THD+N result.
THD has converged: increasing from 128K to 256K changed it by only 0.24 dB. I’m now doing the shorter 8K/16K comparison that checks whether the 20 Hz THD+N lower limit is clear of DC spillover.
The THD+N check is also converged: 16K to 32K changed by 0.19 dB, so the final 32K capture is the one I’ll report and plot. I’m using the visualization workflow now to turn that retained frequency series into an inspectable spectrum.
Measurement complete:
- Amplifier gain: 19.92 dB
- Amplifier output: −10.08 dBV, corrected for the monitor’s 20 dB attenuation
- Output voltage: 0.313 Vrms
- Estimated power into 8 Ω: 12.3 mW
- THD, 20 Hz–20 kHz: −97.71 dB / 0.00130%
- THD+N, 20 Hz–20 kHz: −74.23 dB / 0.0194%
THD converged within 0.24 dB between 128K and 256K. THD+N converged within 0.19 dB between 16K and 32K. The plot uses the final 32K THD+N acquisition and includes the +20 dB monitor correction.
The QA403 stimulus is now off. The MCP server remains alive for subsequent commands.
DC200-8 speaker impedance
User
OK, now I’d like to use a chirp to plot the impedance of the speaker. The left channel connection remains the same. The right channel connection is now the current sense for the speaker. It consists of a 0.02 ohm current sense resistor with a 50X amp, giving an effective Rsense of 1 ohm. Let’s run the chirp from 20 to 20k. For the chirp, ensure it’s an integer number of cycles (ok to tweak stop freq to get this), with raised-cosine ramp at both ends. Deliver a vertically stacked plot. Top plot is output chirp. Bottom plot is impedance. The speaker is a DC200-8. Can you pull the spec on that, extract the impedance from the spec and add that to the plot too? I’d like to compare.
Assistant
I’ll use the existing −30 dBV drive as the safe starting level and keep the persistent MCP process alive. I’m using the visualization workflow because the measured and manufacturer impedance curves need a direct stacked comparison; I’ll also retrieve the DC200-8 manufacturer data, generate an integer-cycle log chirp with raised-cosine endpoints, acquire voltage/current, and leave the output off afterward.
The waveform is ready: 512K samples at 48 kS/s, 10.923 seconds, −30 dBV, with 100 ms raised-cosine ramps. I adjusted the endpoint only to 20,000.196 Hz, which makes the analytic log sweep exactly 31,593 cycles. I’m applying it now and capturing both channels in the same blocking acquisition.
The measured current channel is healthy, and the impedance calculation is behaving physically: the resonance peak is near 32 Hz, the midband minimum is about 8.1 Ω, and impedance rises inductively above it. I found the manufacturer’s published impedance curve and am using its previously digitized points from the official DC200-8 specification sheet for the comparison—not a synthetic T/S model.
Completed at −30 dBV. The chirp contained exactly 31,593 cycles and ended at 20,000.196 Hz, with 100 ms raised-cosine ramps.
The measured curve shows resonance near 32 Hz and a midband minimum around 8.1 Ω. The comparison curve was digitized from the official DC200-8 specification sheet; published parameters include 6.41 Ω Re and 30.3 Hz Fs. Dayton Audio product page
The analyzer output is off, and the MCP server remains alive.
Rub-and-buzz experiment
User
Good. Now I’ve added a mic to the setup (speaker voltage is left channel, mic is right channel). I’d like to explore rub and buzz algos. The mic is an Earthworks M23R (sensitivity of -28.9dBV/Pa). The mic is running through a 10 dB amp. For R&B, let’s use a 20 Hz to 2 kHz log chirp. We know the gain of the dut, mic sensitivity and mic gain, but we don’t know speaker eff. Use a test probe at -20 dBV to learn that. And then set your chirp level so that we hit about 95 dBSPL at 1 kHz. I’d like you post-process the recovered chirp on the mic channel such that we apply a 10th order high-pass tracking filter. To do this, you should first estimate the frequency versus time of the chirp, and every 100 mS adjust the hpf such that it’s corner is 8X that of the current chirp freq. And then create a stacked plot: Top plot is freq vs time of the output chirp and HPF corner. Middle plot is instantaneous dBSPL versus freq. Bottom plot is residual RMS (20-20k) in dBV versus output chirp freq. I’d like to run the test twice. Once with a clean speaker, and a second time with a particle introduced. Prompt me for each run.
Assistant
Understood. I’ll use:
- L+ IN: speaker voltage through the 20 dB monitor attenuation
- R+ IN: M23R microphone through 10 dB gain
- Mic calibration: −28.9 dBV/Pa, with the 10 dB preamp correction
- Initial probe: 1 kHz at −20 dBV
- Target: approximately 95 dBSPL at 1 kHz
- Test stimulus: 20 Hz–2 kHz log chirp
- Tracking HPF: 10th order, updated every 100 ms, corner at 8× chirp frequency
I’ll first measure the clean speaker, turn the output off, and then prompt you before the particle run.
Is the speaker currently clean and ready for the −20 dBV calibration probe and clean chirp?
User
go
Assistant
I’m starting the clean run with the −20 dBV, 1 kHz calibration probe. I’ll use the measured microphone level to set the chirp drive for roughly 95 dBSPL, then capture the clean sweep and turn the output off before asking you to introduce the particle.
The probe measured about 97.11 dBSPL at 1 kHz, so the clean chirp drive will be −22.11 dBV to target 95 dBSPL. I’m using a 512K log sweep so each 100 ms tracking interval has adequate data, especially near 20 Hz.
The clean reference is captured successfully at a calculated −22.11 dBV chirp level. The analyzer output is now off.
Please introduce the particle into the speaker cone. When it is in place and stable, reply Go for the second run.
User
go
Assistant
Starting the particle run with the identical −22.11 dBV waveform and analyzer settings. After capture, I’ll turn the output off and process both runs through the same 100 ms, 10th-order tracking high-pass pipeline for a direct comparison.
Both captures are complete and the stimulus is off. I’m now applying identical processing to the clean and particle runs: five cascaded Butterworth biquads for the 10th-order tracking HPF, coefficients updated every 100 ms, followed by a 20 kHz low-pass before calculating each residual RMS point.
The particle is clearly detected. From 30–300 Hz, its tracking-filter residual is about 23 dB higher on average, peaking 28.9 dB above clean near 142 Hz. Above roughly 400 Hz, the median difference falls to about 0.09 dB.
The analyzer output is off, and the MCP server remains alive.


