netlogger-mcp
Query NetLogger for live and past amateur-radio nets and check-ins through an MCP-compatible assistant.
List nets on the air now, optionally filtered by name; includes frequency, band, mode, net control, logger, and monitoring count.
Get a live net's check-in list and the pointer/station being worked, using
server_nameandnet_name.List closed nets over the last N days (default 7; over 7 requires a name filter), with net IDs for past check-ins.
Get a closed net's check-in list using
server_name,net_name, andnet_id.Save your callsign once (tool or
NETLOGGER_MCP_CALLSIGN) so NetLogger can identify the requesting station.Get service version, NetLogger API version, and returned-record contract version.
Use shared caching/rate limits, stale answers instead of errors, and privacy filtering for addresses/ZIPs/IPs.
Click on "Deploy 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., "@netlogger-mcpwhat nets are on the air right now?"
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.
netlogger-mcp
MCP server for NetLogger: nets on the air now, live check-in lists and who's up, and past nets and their check-ins, through any MCP-compatible AI assistant.
Data from NetLogger's public XML Data Service (API 1.3). Part of the qso-graph project. No API key needed. Your callsign is asked for once (see below).
Install
uvx netlogger-mcp # run it; nothing to installRelated MCP server: lotw-mcp
Tools
Tool | Description | Key Parameters |
| Nets on the air now: frequency, band, mode, net control, logger, monitoring count | name_like |
| A live net's check-in list, plus the pointer (the station being worked now) | server_name, net_name |
| Closed nets over the last N days, with the net IDs past check-ins need | interval_days, name_like |
| A closed net's check-in list | server_name, net_name, net_id |
| Save your callsign (asked once, on first use) | callsign |
| Service version + upstream spec version (fleet identity attestation) | — |
What is NetLogger?
NetLogger is the logging program many amateur-radio nets use: net control or a logger keeps the check-in list, and anyone can follow the net live. Its server publishes active nets, check-in lists and past nets through a public API.
Your Callsign
Every request tells NetLogger which station is asking, so it can tell one user from another:
netlogger-mcp/<version> (KI7MT; +https://github.com/qso-graph/netlogger-mcp)The version is the installed one — it is read from the package, not written here.
On first use the assistant asks for your callsign and saves it. You're asked once. To set it yourself, use NETLOGGER_MCP_CALLSIGN=KI7MT.
It's saved in settings.json, in ~/.config/netlogger-mcp/ (Linux), ~/Library/Application Support/netlogger-mcp/ (macOS) or %APPDATA%\netlogger-mcp\ (Windows).
Good Neighbour Policy
NetLogger is a donation-funded service on one server, and it limits how often each call may be made. We keep to those limits:
Measure | Detail |
NetLogger's call limits | GetActiveNets 1/min, GetCheckins 3/min, GetPastNets 1/min, GetPastNetCheckins 10/min. Checked before a request is sent, never after. |
One budget per user | Every copy you run (Claude Desktop, Claude Code, a script) shares one budget, through a locked file beside |
Shared answers | Every copy also shares the answers it fetched, so a copy that has hit the limit gets another copy's recent answer, with its age, instead of an error. |
Response caching | Active nets 60 s, check-ins 20 s, past nets 60 s, past check-ins 1 hour. Filtering by name costs no extra calls. |
How old an answer is | Every answer has |
Stale answers over errors | When a limit is reached, the last answer comes back with its age rather than a new request. |
429 back-off | A "too many requests" on any call stops all calls for at least a minute, longer if NetLogger asks. |
Past-net windows | More than 7 days of past nets needs a name filter, NetLogger's rule to protect its server. |
Request timeout | 15-second timeout. |
User-Agent header | Every request names this project and your callsign, so NetLogger's operators can see who is asking. |
Bands and Frequencies
NetLogger's band and frequency are whatever the logger typed ("40M", "75M", "DMR", "7033", "3918 KHz", "147.030 91.5", "TG 3141"). They're returned as typed, and beside them, only when the text can be read reliably: frequency_mhz, band_adif (the ADIF band, from ADIF 3.1.7's Band enumeration), tone_hz and talkgroup. A frequency outside the amateur bands (e.g. GMRS) gets no band_adif.
Privacy
NetLogger's check-in data includes street addresses and ZIP codes, and past nets include the IP address of whoever opened them. None of these are ever returned.
Quick Start
Configure your MCP client
netlogger-mcp works with any MCP-compatible client. Add the server config and restart. The tools appear automatically.
Claude Desktop
Add to claude_desktop_config.json (~/Library/Application Support/Claude/ on macOS, %APPDATA%\Claude\ on Windows):
{
"mcpServers": {
"netlogger": {
"command": "uvx",
"args": ["netlogger-mcp"]
}
}
}Claude Code
Add to .claude/settings.json:
{
"mcpServers": {
"netlogger": {
"command": "uvx",
"args": ["netlogger-mcp"]
}
}
}ChatGPT Desktop
{
"mcpServers": {
"netlogger": {
"command": "uvx",
"args": ["netlogger-mcp"]
}
}
}Cursor
Add to .cursor/mcp.json (project-level) or ~/.cursor/mcp.json (global):
{
"mcpServers": {
"netlogger": {
"command": "uvx",
"args": ["netlogger-mcp"]
}
}
}VS Code / GitHub Copilot
Add to .vscode/mcp.json in your workspace:
{
"servers": {
"netlogger": {
"command": "uvx",
"args": ["netlogger-mcp"]
}
}
}Gemini CLI
Add to ~/.gemini/settings.json (global) or .gemini/settings.json (project):
{
"mcpServers": {
"netlogger": {
"command": "uvx",
"args": ["netlogger-mcp"]
}
}
}Ask questions
"What nets are on the air right now?"
"Are any 80m nets running?"
"Who's checked into the county ARES net, and who's up now?"
"Which nets ran in the last three days?"
"Show me the check-ins from last night's net."
As a Python Library
The same code works without an AI, with the same limits and cache. A library can't ask for your callsign, so you pass it in:
from netlogger_mcp.netlogger import NetLoggerSource
nl = NetLoggerSource(callsign="KI7MT")
for net in nl.active_nets()["nets"]:
live = nl.checkins(net["server"], net["name"])
print(net["name"], "up now:", live["pointer_callsign"])Apps can also name themselves, using ADIF's PROGRAMID and PROGRAMVERSION: NetLoggerSource(callsign="KI7MT", program_id="MyLogger", program_version="1.0").
Testing Without Network
NETLOGGER_MCP_MOCK=1 netlogger-mcpMCP Inspector
netlogger-mcp --transport streamable-http --port 8014Development
git clone https://github.com/qso-graph/netlogger-mcp.git
cd netlogger-mcp
uv sync --group dev
uv run pytestLicense
GPL-3.0-or-later. adif_band.json is the ADIF 3.1.7 Band enumeration, the work of the ADIF Developers Group (adif.org.uk), included unchanged.
Available Tools
6 toolsget_version_infoGet Version InfoA
Get netlogger-mcp's version, the NetLogger API version it is built for, and the version of the records it returns.
Returns: service_name, service_version (PyPI), spec_version (NetLogger API), contract_version.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral burden. It discloses the exact returned fields and clarifies the meaning of each version (PyPI, NetLogger API, contract), which adds useful context. It does not explicitly state read-only nature, auth requirements, or rate limits, but the read-only retrieval behavior is strongly implied and no contradiction exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two compact sentences plus a structured return list. It is front-loaded with the core purpose and wastes no words. Every part earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (zero parameters) and the presence of an output schema, the description is nearly complete. It explains what is returned even though the output schema covers this, and it clearly defines the tool's scope. The only minor gap is the absence of explicit usage guidance, which is largely inferable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. No parameter semantics need to be explained, and the description appropriately omits parameter details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (Get) and resource (version info), and precisely enumerates the three version types: the MCP version, the NetLogger API version, and the record version. It clearly distinguishes this informational tool from all operational siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or when-not-to-use guidance is provided. However, for a zero-parameter version retrieval tool, the usage is strongly implied: call it when version metadata is needed. No alternatives exist among siblings, so the lack of routing guidance is not critical.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
netlogger_active_netsNetlogger Active NetsC
List nets on the air now.
| Name | Required | Description | Default |
|---|---|---|---|
| name_like | No | Only nets whose name contains this text, ignoring case (e.g. OMISS). Empty for all. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It does not state that this is a read-only operation, nor describe freshness/latency of the 'now' data or how filtering interacts with the live set. Only the temporal scope is conveyed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single short sentence with no padding, and the key scope constraint ('now') is front-loaded. It is arguably under-specified rather than over-written, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (one optional param, output schema present, so return format need not be explained), and the description covers the core purpose. However, with no annotations it should say more about safety/behavior to be complete for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single name_like parameter is fully documented with case-insensitivity and empty-string semantics in the schema. The description adds nothing beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (nets) with a temporal scope qualifier ('on the air now') that implicitly distinguishes it from netlogger_past_nets. It does not name the sibling, but the active-vs-past contrast is inferable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance or mention of alternatives such as netlogger_past_nets or netlogger_checkins. The phrase 'on the air now' hints at the active filter, but the agent is left to infer when this tool is preferred over its siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
netlogger_checkinsNetlogger CheckinsA
Get a live net's check-in list, and the pointer: the serial number of the station net control is working now.
| Name | Required | Description | Default |
|---|---|---|---|
| net_name | Yes | The net's name, from netlogger_active_nets. | |
| server_name | Yes | The net's server, from netlogger_active_nets (e.g. NETLOGGER2). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden; it tells the agent this is a read operation ('Get') and that the result includes a check-in list plus a live pointer. However, it does not explicitly state read-only safety, permissions, rate limits, or whether the data changes during the net, so significant behavioral gaps remain.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with no padding; it states the action, resource, and a key output field directly. The colon construction is slightly unusual but does not waste words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the low complexity, 100% schema coverage, and the presence of an output schema, the description covers the core purpose and the pointer field adequately. It is weaker on routing to sibling tools and omits explicit read-only/permission context, but the structured fields fill most gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has full description coverage for both required parameters, including their source (netlogger_active_nets), so the baseline is 3. The description adds no parameter syntax or source detail beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get') and resource ('a live net's check-in list'), and it names the non-obvious pointer output. The word 'live' implicitly distinguishes it from netlogger_past_checkins, so an agent can tell it apart from the past-net siblings without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'a live net's' scopes usage to currently running nets, implicitly contrasting with netlogger_past_checkins, but no alternative tool is named and no explicit when/when-not or prerequisite is stated. This is implied usage rather than clear routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
netlogger_past_checkinsNetlogger Past CheckinsB
Get a closed net's check-in list.
| Name | Required | Description | Default |
|---|---|---|---|
| net_id | Yes | The net ID, from netlogger_past_nets. | |
| net_name | Yes | The net's name, from netlogger_past_nets. | |
| server_name | Yes | The net's server, from netlogger_past_nets. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. 'Get' implies a read operation, but the description does not explicitly state read-only behavior, side effects, authentication needs, or pagination. The output schema covers return values, but the safety profile remains unstated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no wasted words. It is appropriately sized for a simple retrieval tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The output schema exists, so return values need not be explained, and parameter descriptions already link the inputs to netlogger_past_nets. However, the description lacks explicit usage routing and behavioral context, leaving a gap for an agent deciding between this and netlogger_checkins.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all three parameters in detail. The description adds no parameter semantics beyond the schema, making the baseline of 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Get') and resource ('closed net's check-in list'), making the scope clear. It implicitly distinguishes past from active nets, but does not explicitly name the sibling tool netlogger_checkins as the active-net alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'closed net's' versus active nets, but the description gives no explicit when-to-use, when-not-to-use, or alternative-tool guidance. It relies on the agent to infer routing from the sibling list and the word 'closed'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
netlogger_past_netsNetlogger Past NetsA
List closed nets over the last few days, with the net IDs netlogger_past_checkins needs.
| Name | Required | Description | Default |
|---|---|---|---|
| name_like | No | Only nets whose name contains this text (e.g. OMISS). | |
| interval_days | No | How many days back (default 7). Over 7 needs name_like (NetLogger's rule). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. 'List' implies a read-only operation and it discloses closed-net and time-window scope, but it does not explicitly state safety, permissions, or rate-limit behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is a single front-loaded sentence with no wasted words. It states the purpose, scope, and downstream linkage efficiently.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the low parameter count, full schema coverage, and the presence of an output schema, the description is nearly complete: it explains what the tool returns and why it matters. It could more explicitly route the agent away from netlogger_active_nets, but no critical information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters in detail, including defaults and the NetLogger rule about intervals over 7 days. The description adds no parameter-level semantics beyond what the schema provides, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('List'), resource ('closed nets'), and time scope ('over the last few days'), and distinguishes itself from the active-nets sibling. It also clarifies the downstream use by tying the output to netlogger_past_checkins.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context: use it to get closed net IDs needed by netlogger_past_checkins. It does not explicitly say when not to use it or name an alternative like netlogger_active_nets, but the closed vs. active distinction is implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
netlogger_set_callsignNetlogger Set CallsignA
Save the user's amateur radio callsign. Needed once, before the first lookup.
NetLogger is told which station is asking, in every request, so it can tell one user from another. Ask the user for their own callsign; don't guess it.
| Name | Required | Description | Default |
|---|---|---|---|
| callsign | Yes | The user's callsign (e.g. KI7MT). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It usefully explains why the call is required (NetLogger identifies the station on every request), but does not disclose persistence, whether a repeat call overwrites the prior value, or error behavior for an invalid callsign. Return values are covered by the output schema, so that gap is acceptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action and the 'needed once, before the first lookup' constraint. Every sentence carries information; nothing is restated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter configuration tool with an output schema and full schema coverage, the description supplies the missing pieces: necessity, ordering relative to other calls, and argument sourcing. Only the overwrite/repeat-call behavior is left unspecified, a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, and the description adds genuine value by telling the agent the value must come from the user rather than be inferred or guessed. It does not add format/validation rules beyond the schema's example (KI7MT), which keeps it just short of the top score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Save') and resource ('the user's amateur radio callsign'), which cleanly separates it from the read-only lookup siblings (netlogger_active_nets, netlogger_checkins, etc.). An agent can identify this as the one write/configuration tool in the set without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the timing and necessity: 'Needed once, before the first lookup,' plus a directive on value sourcing ('Ask the user for their own callsign; don't guess it'). This gives the agent both when to call it and how to obtain the argument, with no ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v0.1.0- First observed
get_version_info - First observed
netlogger_active_nets - First observed
netlogger_checkins - First observed
netlogger_past_checkins - First observed
netlogger_past_nets - First observed
netlogger_set_callsign
TDQS
Scored across 6 tools
Each tool has a clearly distinct purpose: version info, user setup, active nets, live check-ins, past nets, and past check-ins. No two tools overlap in function, and descriptions make the active/live vs past/closed distinction explicit.
All tool names use snake_case, and five of six follow a netlogger_verb_noun pattern. The lone get_version_info breaks the prefix convention, but the deviation is minor and doesn't hinder readability.
Six tools is a well-scoped set for a read-only NetLogger client, covering setup, discovery, and retrieval for both active and past nets. Each tool earns its place without redundancy.
The surface covers version info, user identification, active/past net listing, and check-in retrieval, which is a complete read lifecycle. However, there is no tool to submit a check-in or retrieve detailed net metadata, which may be a gap depending on intended use.
Maintenance
Related MCP Connectors
Read-only access to live ADSBiq aircraft and network state, with community contribution metadata.
Trust, freshness, policy, and discovery layer for public MCP servers.
Read-only MCP server for The Quiet Protocol's engines, benchmarks, proof, and business data.
Hosted NeuroDock — stateless communication and planning tools over OAuth-secured Streamable HTTP.
Related MCP Servers
- AlicenseAqualityCmaintenanceExposes real-time ADS-B aircraft data from a feeder, enabling natural language queries for aircraft positions, receiver statistics, and flight searches.69GPL 3.0
- AlicenseAqualityAmaintenanceMCP server for ARRL Logbook of The World (LoTW) that enables querying confirmations, uploaded QSOs, DXCC credits, and user activity through any MCP-compatible AI assistant. Part of the qso-graph project, it is read-only and requires LoTW credentials for authenticated tools.6221 PyPI1GPL 3.0
- FlicenseNot gradedqualityDmaintenanceMCP server that provides read-only access to cached metadata of public activities, contests, and competitions from multiple sources via SQLite, enabling search and listing without hitting external sites.1-
- AlicenseNot gradedqualityAmaintenanceServes read-only archived ResMed CPAP data from a local SQLite database, enabling MCP clients to query nightly summaries, raw signals, and sync status over the LAN.183 npmMIT