feat(mcp): MCP server for agent-driven DAQiFi device control#277
Conversation
Add Daqifi.Mcp, a Model Context Protocol server (stdio) that lets an AI agent (Claude, Cursor, Codex, ...) drive a DAQiFi Nyquist device through Daqifi.Core: discover, connect, configure analog channels + sample rate, and run on-device SD-card logging. Distributed as a `dotnet tool`. Scope is intentionally the basic control loop; live streaming and SD file list/download are deferred to follow-ups. - 10 tools over a thin DaqifiAgent facade wrapping the real Core surface (DaqifiDeviceFactory, IStreamingDevice channel APIs, ISdCardOperations) - stdio host with all logging routed to stderr so it cannot corrupt the JSON-RPC stream - per-agent serialization of device mutations; graceful shutdown drains connected devices so serial ports are released on exit - sample rate clamped to the 1000 Hz hardware ceiling; --read-only and --max-sample-rate-hz flags - xUnit tests; release.yml publishes the dotnet tool on tagged releases Validated end-to-end against a real Nyquist1 (firmware 3.6.2) over USB. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR Summary by QodoAdd MCP stdio server + dotnet tool to control DAQiFi devices via Daqifi.Core
AI Description
Diagram
High-Level Assessment
Files changed (11)
|
Code Review by Qodo
1.
|
…shot) - ServerOptions: ignore non-positive --max-sample-rate-hz, and clamp the effective cap to [1, 1000] so a bad flag can't apply a <= 0 rate (Qodo #3) - Add public DaqifiDevice.GetChannelsSnapshot() (lock-protected) and use it in the MCP layer instead of folding the live Channels view, closing the concurrent-repopulation race that .ToArray() only narrowed (Qodo #2) - ConnectFromDeviceInfoAsync: use fully-positional args for clarity (Qodo #1; the named-then-positional form already compiled — CI was green — but this reads more clearly) - release.yml: add --skip-duplicate to the Daqifi.Core push so re-running a tagged release is idempotent, matching the MCP push (Qodo #4) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a short pointer to src/Daqifi.Mcp (intro line, "Where DAQiFi Core fits" table row, and a maintainer note that releases also publish the dotnet tool). Intentionally minimal — no product repositioning. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Adds
Daqifi.Mcp, a Model Context Protocol server (stdio) that lets an AI agent — Claude Desktop/Code, Cursor, Codex, etc. — drive a DAQiFi Nyquist device throughDaqifi.Corewith no application code: discover → connect → configure analog channels + sample rate → start/stop on-device SD-card logging.It's a thin facade over
Daqifi.Core(in-process, no protocol re-implementation), distributed as adotnet tool. Scope is intentionally the basic control loop; live data streaming and SD file list/download are deferred to follow-ups.What's in it
src/Daqifi.Mcp— the server: aDaqifiAgentfacade over the real Core surface (DaqifiDeviceFactory.ConnectFromDeviceInfoAsync,IStreamingDevice.EnableChannels,ISdCardOperations), 10 MCP tools, an stdio host with all logging routed to stderr (stdout is reserved for JSON-RPC).src/Daqifi.Mcp.Tests— xUnit coverage of option parsing and agent guard rails.release.yml— publishes thedotnet toolto NuGet on tagged releases (alongside the existingDaqifi.Corepush).Tools
discover_devices·connect_device·list_connected_devices·disconnect_device·get_device_status·list_channels·configure_analog_channels·set_sample_rate·start_sd_logging·stop_sd_loggingNotable design points
IStreamingDevice.EnableChannels/DisableChannel(+ the ADC bitmask), not the per-channel value interfaces.start_sd_loggingreturns the real on-card filename; errors surface Core's human-readable messages so the agent can self-correct.--read-only(block mutations) and--max-sample-rate-hz.How to run it
dotnet tool install -g Daqifi.Mcp # exposes the `daqifi-mcp` commandClaude Desktop (
claude_desktop_config.json):{ "mcpServers": { "daqifi": { "command": "daqifi-mcp", "args": [] } } }Cursor (
~/.cursor/mcp.json) is the same shape; Codex uses[mcp_servers.daqifi]in~/.codex/config.toml. Seesrc/Daqifi.Mcp/README.md.Test plan / verification
initialize+tools/listreturn all 10 tools with correct schemas[0,1,2,3]→ set rate →start_sd_logging(loggingToSdCard:trueconfirmed) →stop_sd_logging→ disconnect5000 → 1000,clamped:truewith an explanatory notestart_sd_loggingreturns the real filename (log_<timestamp>.bin)disconnect_device) → a fresh server immediately reconnects (serial port released, not leaked)Out of scope (follow-ups)
list_sd_files/download_sd_file(so the agent can see/retrieve what it logged)get_channel_summary)--read-onlymode🤖 Generated with Claude Code