Skip to main content
Glama

mqtt-readonly-mcp

First attempt. This is an early, hobby-grade release: it works on the author's own Home Assistant setup and has a test suite, but it has not been used by many people or on many brokers. Expect rough edges, and please read the disclaimer before you point it at anything you care about.

A small listen-only MQTT tool for Claude Code and other MCP clients.

Purpose

The goal is to let an AI assistant watch the traffic on a smart-home MQTT broker live, understand it, and then help you bring that traffic under control through Home Assistant.

The tool itself only listens. It shows the assistant what Home Assistant, Zigbee2MQTT, Frigate and your devices are publishing: which topics are chatty, what a sensor sends when something happens, how busy the broker is. The assistant then uses that picture, together with Home Assistant, to change things: for example lowering a presence radar's update rate or turning down a noisy Zigbee2MQTT log level. Those changes are made through Home Assistant (or Zigbee2MQTT), not through this tool, and they need your approval like any other change the assistant proposes.

  • server.py: an MCP server (stdio). Keeps a rolling buffer of what the broker publishes, so the assistant can ask "what did topic X send in the last N minutes?".

  • stream.py: prints one line per message, for Claude Code's Monitor tool (live notifications in the chat).

  • mqtt_common.py: shared code (buffer, redaction, payload formatting, connection).

Neither program contains any publish code. tests/test_no_publish.py fails if publish-like code appears in them.

Related MCP server: MQTT MCP Server

What it is good for

It was built to answer questions like these on a real smart home:

  • Which device is flooding the broker? (mqtt_rates found that one presence radar produced 87% of about 1,400 messages per minute; after the radar's update rate was lowered in Home Assistant, traffic fell to about a fifth.)

  • Did the Zigbee2MQTT change I just made actually reduce traffic?

  • What exactly does this sensor publish when the door opens? (mqtt_wait)

Redaction: on by default, how to switch it

Message payloads end up in the AI conversation, and MQTT carries secrets (the Zigbee2MQTT network key, camera passwords in URLs, API tokens). So redaction is on by default.

You want

Set

Secrets scrubbed (default)

nothing, or MQTT_RO_REDACT=1

Payloads exactly as published

MQTT_RO_REDACT=0

Set it in the environment of the server, for example when registering with Claude Code:

claude mcp add --scope user mqtt-readonly -e MQTT_RO_HOST=192.168.1.10 -e MQTT_RO_REDACT=0 -- /path/to/.venv/bin/python /path/to/server.py

To turn redaction back on, remove that variable or set MQTT_RO_REDACT=1, then restart the server (in Claude Code, reload the session). The same variable controls stream.py. Details of what is scrubbed are in Redaction below. Turn it off only on a broker whose traffic you are happy to paste into a chat.

Requirements

  • Python 3.10 or newer

  • An MQTT broker you can log in to. Create a separate login for this tool.

  • pip install -r requirements.txt (mcp is pinned below 2 because version 2 renamed the server API)

Setup

  1. Create a virtual environment and install the requirements.

    python -m venv .venv
    .venv/bin/pip install -r requirements.txt        # Windows: .venv\Scripts\pip
  2. Put the broker login in a credentials file that is not inside this project. The default location is ~/.config/mqtt-readonly/credentials.json:

    {"username": "mqtt_readonly", "password": "..."}

    Restrict it to your own account (chmod 600, or icacls on Windows). The tool never prints it.

  3. Register the server with Claude Code. The password is not on the command line:

    claude mcp add --scope user mqtt-readonly \
      -e MQTT_RO_HOST=192.168.1.10 -e MQTT_RO_PORT=1883 \
      -- /path/to/.venv/bin/python /path/to/server.py

    Any other MCP client works the same way: run python server.py over stdio with the environment variables below.

Environment variables

Variable

Default

Meaning

MQTT_RO_HOST

127.0.0.1

Broker address

MQTT_RO_PORT

1883

Broker port

MQTT_RO_CRED_FILE

~/.config/mqtt-readonly/credentials.json

Credentials file

MQTT_RO_NO_AUTH

unset

1 connects without a login (local test broker only)

MQTT_RO_FILTERS

#

Comma-separated subscription filters

MQTT_RO_ALLOW

empty (allow all)

Comma-separated topic filters this tool may see at all (see below)

MQTT_RO_IGNORE

empty

Comma-separated topic filters to skip (noisy sources)

MQTT_RO_BUFFER

5000

Messages kept in the rolling buffer

MQTT_RO_REDACT

1

0 reports payloads exactly as published (see below)

The connection is plain MQTT. There is no TLS option yet, so use it on a trusted network.

Tools

Tool

What it does

mqtt_status

Connection state, buffer fill, uptime

mqtt_topics(prefix, limit)

Topics seen, newest first, with counts

mqtt_tree(prefix, depth, limit)

Topic tree: topics grouped by their first depth levels, with topic and message counts, busiest first

mqtt_broker_stats

Broker statistics from $SYS: version, uptime, clients, subscriptions, retained messages, messages per minute

mqtt_last(topic_filter, limit)

Latest value per matching topic (includes retained values)

mqtt_recent(topic_filter, minutes, limit)

Messages from the buffer, oldest first

mqtt_rates(minutes, limit, group_levels)

Messages per minute, busiest first: finds chatty topics

mqtt_wait(topic_filter, seconds, max_messages)

Waits for NEW messages (max 60 s)

MQTT wildcards + and # work in every filter. Retained messages (replayed on connect) go only into the last-value map, not the buffer. Responses are capped at 20,000 characters.

Limiting what it can see (MQTT_RO_ALLOW)

By default the tool subscribes to # and can read every topic your login can. Set MQTT_RO_ALLOW to a comma-separated list of topic filters to make that a hard limit:

MQTT_RO_ALLOW=zigbee2mqtt/#,alarm/#,$SYS/#
  • The server only subscribes to filters inside the allow list, and drops any message outside it before it is stored.

  • stream.py reads the same variable and refuses ([ERROR], exit code 2) any --filter the allow list does not cover, so the Monitor tool cannot widen access.

  • MQTT_RO_FILTERS only chooses what the server subscribes to. MQTT_RO_ALLOW is the limit that also constrains stream.py.

  • Include $SYS/# if you want mqtt_broker_stats to work.

This restricts the tool, not your broker login. For enforcement on the broker itself, use an ACL (see "What read-only means here").

Broker statistics

The server also subscribes to $SYS/# (the # filter alone does not match $SYS topics). Mosquitto publishes these roughly every 10 seconds, so only the latest value of each is kept and they never fill the message buffer. mqtt_broker_stats reports a short list of the useful figures. If the broker publishes no $SYS topics, or your login may not read them, the tool says so rather than failing. Other brokers use different $SYS names, so the output may be sparse there.

Redaction

Message payloads end up in the AI conversation, and MQTT carries secrets: the Zigbee2MQTT network key, camera passwords in URLs, API tokens. So redaction is on by default:

  • JSON values whose key contains pass, secret, token, key, psk, auth or credential become [REDACTED], at any depth.

  • The same pattern is applied to non-JSON text (key=value), and user:password@ inside URLs is masked.

  • zigbee2mqtt/bridge/* topics (except bridge/state) report their size only, because they carry network and device configuration.

  • Redaction runs before a payload is trimmed or stored, so a secret cannot survive a cut.

  • Binary payloads (camera JPEGs) are shown as [binary N bytes].

Redaction is pattern based. It will miss a secret that sits under an unusual key name, so treat it as a safety net, not a guarantee. Set MQTT_RO_REDACT=0 only on a broker whose traffic you are happy to paste into a chat. JSON is re-serialised compactly when redaction is on, so spacing differs from the original.

Monitor (live stream)

python stream.py --filter "zigbee2mqtt/#" --exclude "zigbee2mqtt/bridge/#" --max-per-minute 30 --seconds 120

Each printed line becomes a chat notification when run through Claude Code's Monitor tool, so a per-minute cap applies and the excess is summarised as [suppressed N messages ...]. It prints [ERROR] ... and exits if credentials are missing, the login fails, or the broker cannot be reached. Retained replay is skipped unless you pass --retained.

What "read-only" means here

The code has no publish path, and a test enforces that. But the broker login can still publish unless you restrict it on the broker. For real enforcement, give the login read access only. With Mosquitto, an ACL file like this does it:

user mqtt_readonly
topic read #

Be careful: once you enable acl_file, every other user and client must also be listed in it, or they lose access. Back up the broker configuration first.

Known limits

  • The buffer holds 5,000 messages by default. A very chatty device shortens the window; use MQTT_RO_IGNORE or lower that device's update rate. mqtt_rates reports the effective window.

  • The buffer only holds what arrived while the server was running.

  • No TLS and no MQTT 5 specific features.

Tests

Most tests run without a broker. The integration tests need a throwaway broker and skip themselves when it is not running:

docker run -d --rm --name mqtt-ro-test -p 18830:1883 eclipse-mosquitto:2 mosquitto -c /mosquitto-no-auth.conf
python -m unittest discover -s tests -t .
docker stop mqtt-ro-test

(Git Bash on Windows needs MSYS_NO_PATHCONV=1 in front of docker run.) tests/demo_publisher.py publishes sample messages to that test broker so the Monitor tool has something to stream. It is a test helper and is not part of the server.

Acknowledgments

  • Pat (OdorDecoder): idea, requirements, testing on a real Home Assistant installation, and every decision about what the tool should and should not do.

  • Claude (Anthropic's AI assistant, used through Claude Code): wrote the code, tests and documentation in collaboration with Pat.

  • Built on the MCP Python SDK, Eclipse Paho MQTT client and Eclipse Mosquitto (used as the throwaway test broker).

  • Ideas for features came from looking at descriptions of other MQTT MCP servers: mcmqtt, tspspi/mcpMQTT and rsbohn/mqtt-bridge. No code was copied from them, and thanks to their authors for showing what is useful.

Disclaimer: use at your own risk

This is a first attempt, shared as is, under the MIT license, which already says the software comes without warranty of any kind. In plain words:

  • The author takes no responsibility for anything that goes wrong from using, misusing or relying on this software. That includes, without limit, exposed secrets or private data, a broker or smart-home device that misbehaves or loses access, wrong advice from an AI assistant that uses this tool, and any cost or damage that follows.

  • The tool is read-only in its own code, but your broker login may still be able to publish unless you restrict it on the broker. See "What read-only means here".

  • Redaction is pattern based and can miss a secret. Do not rely on it as your only protection. Review what you send to any AI service.

  • Test on a non-critical setup first, and take a backup before changing your broker or Home Assistant configuration.

A note on personal information

Care was taken to scrub this repository of personal information: the author's network addresses, file paths, credentials and device names were removed from the code, tests and documentation, and the full git history was checked for secrets before publishing. The example values you see (such as 192.168.1.10, mqtt_readonly or the fake passwords in the tests) are placeholders. No scrub is perfect, so if you spot something that should not be here, please open an issue.

License

MIT, see LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Enables AI assistants to publish and subscribe to MQTT topics with configurable transport options (STDIO, Streamable HTTP, SSE), supporting both local development and web deployments with flexible broker authentication.
    2
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Connects AI assistants to MQTT brokers for smart home automation and IoT device control, enabling topic discovery, sensor reading, command sending, and event monitoring.
    2
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to query MQTT message history stored in SQLite, including topic inventories, last values, historical data, silent devices, and collector connection gaps. Supports publishing messages when write mode is enabled.
    9
    MIT