daq-mcp
With the daq-mcp server, you can:
Discover and inspect NI DAQ devices: List connected devices and get detailed channel inventories, voltage ranges, and sample rates.
Read sensor data: Acquire voltage samples from analog input channels (with summary statistics) and read logic levels from digital input lines.
Write to outputs safely: Drive analog output channels to DC voltages (clamped to safe limits) and set digital lines high or low; writes are disabled by default and require an explicit allowlist.
Analyze waveforms: Acquire finite analog waveforms and get summary stats (mean, RMS, peak-to-peak, standard deviation, preview) instead of raw data.
Diagnose hardware: Run device self-tests to verify health.
Live monitoring and continuous acquisition: Start/stop background data streams and use a web dashboard for real-time visualization.
Simulate hardware: Operate in a pure-Python simulation mode without physical DAQ hardware, ideal for development and testing.
Safety features: Writes are opt-in, channels must be on an allowlist, analog outputs are clamped, and read-back confirms written values.
Click on "Install 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., "@daq-mcpMonitor analog input Dev1/ai0"
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.
daq-mcp
An MCP server that lets an AI coding client talk to NI DAQ hardware.
Most MCP demos wrap APIs or filesystems. This one wraps a data-acquisition device: list channels, read voltages, write digital lines, acquire a short waveform. That is interesting because the failure modes are physical — a hallucinated channel name or a stray analog output can damage equipment or hurt someone. The protocol plumbing is the easy part; the safety model is the point of the project.
Safety model
Writes are off by default. Only channels on an explicit allowlist can be touched, and only channels wired as outputs can be written. Analog output is clamped to a configured voltage range, and every write returns what actually happened (including clamp flags and digital read-back) so the model can verify its own actions.
Control | Default | Env / constant |
Digital / analog writes | disabled |
|
Readable channels |
|
|
Writable channels |
|
|
AO clamp range | ±5 V |
|
Direction is enforced, not just documented. Channels are declared by direction and the writable set is derived from the output groups, so a line wired to a button is readable but cannot be driven. That is not pedantry: driving a line that a button also drives puts two drivers in opposition, which is a short.
The channel lists in server.py describe one particular bench (a USB-6421 with
two buttons and two LEDs). Edit them to match your wiring before enabling
writes — an allowlist that does not describe your hardware protects nothing.
The MCP tools never import nidaqmx directly. They call a backend interface.
That boundary is what makes the server testable and portable.
Related MCP server: rigol-dho-mcp
Tools
Tool | Purpose |
| enumerate connected devices |
| channel inventory for a device |
| model, serial, limits for one device |
| sample an analog input |
| drive an analog output (clamped) |
| read one digital line |
| drive one digital line, with read-back |
| finite waveform reduced to statistics |
| device built-in self-test |
| continuous background acquisition |
Simulated by default (no NI drivers required)
Clone this on a machine without NI-DAQmx — including macOS — and it still
runs. Set DAQ_MCP_SIMULATE=1 to force the pure-Python backend, or leave it
unset: the server tries the real driver and falls back to simulation with a
clear log line if NI is missing.
The simulator exposes two fake devices (Dev1 / Dev2) with realistic
channel inventories. Dev1/ai0 is a slow sine with noise; Dev1/ai1 is a
noisy DC level. Digital lines keep state across calls.
Live dashboard
The MCP tools are snapshots by design, and MCP is request/response, so neither can express "show me the signal as it happens". For that there is a browser dashboard: a scrolling plot of one analog channel, live digital input states, and toggles for the digital outputs.
DAQ_MCP_ALLOW_WRITE=1 uv run server.py --dashboard-only$env:DAQ_MCP_ALLOW_WRITE="1"; uv run server.py --dashboard-onlyThen open http://127.0.0.1:8765/. --dashboard-only implies the dashboard
and skips the MCP loop entirely; to get the dashboard alongside a normal MCP
server (the mode an editor launches), drop the flag and set
DAQ_MCP_DASHBOARD=1 instead.
Standalone mode exists because an MCP server speaking stdio with no client attached reads EOF immediately and exits, taking the dashboard with it.
Variable | Default | Meaning |
| off | serve the dashboard |
|
| listen port |
|
| loopback only by default |
|
| channel to stream |
|
| sample rate in Hz |
The dashboard runs inside the MCP server process rather than beside it.
NI-DAQmx reserves a channel for the lifetime of a task, so a separate process
could not read ai0 while the server held it. Sharing a process means the
model and the human see and drive exactly the same hardware, and browser writes
go through the same allowlist and write-enable checks as model writes.
While a stream is running, read_analog and monitor_analog on that channel
serve from the rolling buffer instead of opening a competing task; the response
carries "source": "live_buffer" so the caller knows. The agent can also drive
the stream itself with start_live, live_status, and stop_live.
Only one server at a time
A DAQmx channel belongs to exactly one task, and the dashboard binds a fixed port, so two copies of this server cannot share a device. Run the standalone dashboard or let your editor launch the server — not both. MCP Inspector spawns its own copy and collides the same way.
Symptom | Meaning |
| another process already holds the channel |
| the consumer stalled; the task is dead and must restart |
| the device is not plugged in or lost power |
port already in use | another dashboard is running |
On Windows, killing uv run ... leaves the child Python process alive still
holding the device and the port. Kill the python.exe running server.py:
Get-CimInstance Win32_Process -Filter "Name='python.exe'" |
Where-Object { $_.CommandLine -like '*server.py*' }Install
Requires Python 3.11+ and uv.
cd MCP-NIDAQMX
uv syncOptional real-hardware extra (needs NI-DAQmx drivers on the machine):
uv sync --extra hardwareRun the server:
uv run server.pyUseful environment variables:
DAQ_MCP_SIMULATE=1 # force simulated backend
DAQ_MCP_ALLOW_WRITE=1 # enable digital / analog outputVerify with MCP Inspector
cd MCP-NIDAQMX
DAQ_MCP_SIMULATE=1 npx -y @modelcontextprotocol/inspector uv run server.pyOn Windows PowerShell, pass the variable with Inspector's -e flag rather than
setting it in the shell — Inspector spawns the server with a sanitized
environment and does not forward arbitrary shell variables:
cd path\to\MCP-NIDAQMX
npx -y @modelcontextprotocol/inspector -e DAQ_MCP_SIMULATE=1 uv run server.pyIf tools return "No results yet" for list_devices, the server is talking to
real hardware and correctly reporting zero devices — the simulate flag did not
reach it. The startup log line on stderr reports which backend was selected.
Cursor configuration
Add to your Cursor MCP settings (user-level mcp.json). Prefer the full path
to uv so Cursor does not depend on PATH:
{
"mcpServers": {
"daq-mcp": {
"command": "C:\\Users\\<you>\\.local\\bin\\uv.exe",
"args": [
"run",
"--directory",
"C:\\path\\to\\MCP-NIDAQMX",
"server.py"
],
"env": {
"DAQ_MCP_SIMULATE": "1"
}
}
}
}Add "DAQ_MCP_ALLOW_WRITE": "1" only when you intentionally enable outputs.
A copy-paste template lives at .cursor/mcp.json.example. Put your real
machine config in .cursor/mcp.json (gitignored) or in Cursor's user MCP
settings — do not commit local paths or write-enable flags.
Tests
uv run pytestAll tests run against the simulated backend.
Tool design decisions
One tool per complete operation. Splitting "create task / add channel / start / read / close" into separate tools would force the model into multiple round-trips and make it easy to leave a hardware task open. Each tool opens what it needs, does one job, and closes everything before returning.
Summary over raw data for waveforms. monitor_analog returns mean, RMS,
peak-to-peak, standard deviation, and a downsampled preview of at most 50
points. Dumping thousands of floats into the model context is expensive and
rarely what you need for "is my sensor behaving?"
Streaming errors are fatal, not swallowed. Continuous acquisition is the
one place holding a task open, and a dead task returns no samples in exactly
the same way an idle one does. Only "samples not ready yet" is ignored; every
other driver error stops the monitor, releases the channel, and surfaces the
message in live_status and the dashboard. A stall that reports itself is
worth far more than one that keeps the UI looking healthy.
Project layout
server.py # MCP tools + safety layer + dashboard wiring
src/daq_mcp/backend/ # DAQBackend ABC, simulated + nidaqmx backends
src/daq_mcp/live.py # continuous acquisition thread + rolling window
src/daq_mcp/dashboard.py # Starlette app, SSE stream, single-page UI
tests/ # pytest against the simulatorMaintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceMCP server for controlling Universal Robots arms and Robotiq grippers via RTDE protocol, enabling motion, force, I/O, and gripper operations.1MIT
- AlicenseAqualityBmaintenanceMCP server for controlling and reading Rigol DHO800/DHO900 oscilloscopes over LAN via SCPI commands.111MIT
- Flicense-qualityBmaintenanceMCP server for ADALM2000 (M2k) — AWG, scope, and PSU control via FastMCP 3.4.
- AlicenseAqualityCmaintenanceA safety-bounded MCP server for discovering data-acquisition devices and performing finite analog-voltage and digital-input reads through NI's nidaqmx Python package.9Apache 2.0
Related MCP Connectors
MCP server for fcc-ecfs
MCP server for network documentation, generated by doc2mcp.
An MCP server for deep research or task groups
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/rhit-folayaod/daq-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server