npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@partme.ai/openclaw-mqtt

v0.1.13

Published

MQTT protocol bridge for OpenClaw — IoT device integration via embedded Aedes MQTT broker

Downloads

315

Readme

OpenClaw MQTT

OpenClaw plugin — MQTT channel bridge with multi-topic routing and explicit topic bindings

npm Node License

English | 简体中文

📖 Introduction

@partme.ai/openclaw-mqtt is an OpenClaw channel plugin for OpenClaw that embeds an MQTT broker (Aedes) and bridges MQTT devices to OpenClaw agents. The plugin uses defineChannelPluginEntry / ChannelPlugin per the OpenClaw channel plugin guide (not definePluginEntry, which is for non-channel plugins). It supports:

  • Explicit topicPattern -> agentId bindings
  • Multi-topic allowlist (subscribeTopics)
  • Inbound payload parsing strategy (JSON.text first, fallback plain text)
  • Runtime reply dispatch via OpenClaw dispatchReplyFromConfig

🎯 Core Capabilities

  • Embedded broker: no external broker required for basic integration.
  • Explicit routing first: topicBindings has higher priority than standard topic fallback.
  • Standard fallback: openclaw/agent/<agentId>/in still works when no binding matches.
  • Reply topic control: use replyTopic per binding, otherwise derive from inbound topic.
  • Session context mapping: each MQTT session records agent/account/reply topic context.
  • Enterprise security baseline (RabbitMQ-inspired): optional MQTT over TLS, user-level topic ACL (publishAllow / subscribeAllow), anonymous control, and payload size limits.

Plugin lifecycle

  • The embedded broker starts when the Gateway runs gateway.startAccount for the MQTT channel (single account default in this release).
  • HTTP GET /mqtt/status is registered in registerFull (plugin-authenticated route) and exposes broker stats, active channels.mqtt snapshot, and policy hot-reload metadata (policy.version, policy.updatedAt, summary fields).
  • Session key scope follows OpenClaw global session.dmScope (for example per-channel-peer), instead of a channel-local channels.mqtt.session.dmScope.
  • If channels.mqtt.session.dmScope is present, the plugin logs a warning and ignores it.\n- package.jsonopenclaw.setupEntry points to dist/setup-entry.js, a lightweight entry that only exports the ChannelPlugin via defineSetupPluginEntry. OpenClaw can load it during setup or when the channel is disabled/unconfigured, instead of the full index entry (see Setup entry).

Scaling note (Aedes)

Default deployment is single-process in-memory. For multi-gateway horizontal scale you would need a shared MQEmitter (for example mqemitter-redis) and optional persistence backends from the Aedes ecosystem; this package does not wire those in yet—documented here for future extension.

🏗️ Message Flow

  1. Device publishes MQTT message.
  2. Plugin checks subscribeTopics allowlist.
  3. Plugin resolves route:
    • First: topicBindings
    • Fallback: standard openclaw/agent/<agentId>/in
  4. Plugin parses payload (JSON.text -> plain text fallback).
  5. Plugin dispatches to OpenClaw runtime.
  6. Reply is published to replyTopic or derived /out topic.

🚀 Quick Start

Prerequisites

  • OpenClaw >= 2026.4.0
  • Node.js 20+

Install

openclaw plugins install @partme.ai/openclaw-mqtt

Minimal config (openclaw.json)

{
  "channels": {
    "mqtt": {
      "port": 1883,
      "maxConnections": 1000,
      "subscribeTopics": [
        "devices/+/in",
        "openclaw/agent/+/in"
      ],
      "topicBindings": [
        {
          "topicPattern": "devices/+/in",
          "agentId": "iot-agent",
          "accountId": "default",
          "replyTopic": "devices/reply"
        }
      ],
      "payload": {
        "mode": "jsonTextOrPlain"
      },
      "auth": {
        "enabled": true,
        "allowAnonymous": false,
        "users": [
          {
            "username": "device-01",
            "passwordHash": "e3b0c44298fc1c149afbf4c8996fb924...",
            "hashAlgorithm": "sha256",
            "publishAllow": ["devices/device-01/in"],
            "subscribeAllow": ["devices/device-01/out"],
            "aclRules": [
              { "action": "inbound", "topicPattern": "devices/device-01/in", "effect": "allow", "accountId": "default" },
              { "action": "outbound", "topicPattern": "devices/device-01/out", "effect": "allow", "accountId": "default" },
              { "action": "publish", "topicPattern": "devices/+/admin/#", "effect": "deny" }
            ]
          }
        ]
      },
      "tls": {
        "enabled": false,
        "port": 8883,
        "certFile": "/etc/openclaw/certs/server.pem",
        "keyFile": "/etc/openclaw/certs/server.key",
        "caFile": "/etc/openclaw/certs/ca.pem"
      },
      "limits": {
        "maxPayloadBytes": 1048576
      },
      "session": {
        "maxExpirySeconds": 86400,
        "persistentAcrossReconnect": true
      },
      "qos0": {
        "mailboxSoftLimit": 200
      },
      "retain": {
        "allowInboundRetain": true,
        "outboundRetain": false
      },
      "audit": {
        "enabled": true,
        "format": "json"
      },
      "will": {
        "allow": true,
        "allowedTopicPatterns": ["devices/+/will"]
      }
    }
  }
  ,
  "session": {
    "dmScope": "per-channel-peer"
  }
}

🧭 Topic Rules

  • Standard inbound: openclaw/agent/<agentId>/in
  • Standard outbound: openclaw/agent/<agentId>/out
  • Explicit mapping: configured by topicBindings.topicPattern

Priority:

  1. topicBindings match
  2. Standard inbound parsing
  3. Drop message when neither matches

🧪 Testing

Unit tests

npm test

Integration test client

npm run test:client

scripts/test-client.ts will:

  • connect to broker (default mqtt://127.0.0.1:1883)
  • subscribe multiple reply topics
  • publish JSON payload and plain text payload
  • fail on timeout when no reply is received

Environment variables:

  • MQTT_BROKER_URL
  • MQTT_CLIENT_ID
  • MQTT_TEST_SUBSCRIBE_TOPICS — comma-separated list (overrides default reply topics)
  • MQTT_TEST_PUBLISH_CASES — optional JSON array of { "topic": "...", "payload": "..." } (overrides default publish cases)
  • MQTT_TEST_TOPIC_JSON
  • MQTT_TEST_TOPIC_PLAIN
  • MQTT_TEST_REPLY_TOPIC
  • MQTT_TEST_REPLY_TOPIC_2
  • MQTT_TEST_TIMEOUT_MS

🤖 GitHub Actions

| Workflow | Trigger | Purpose | | --- | --- | --- | | .github/workflows/ci.yml | Push / PR to main or master | Install, typecheck, build, test, upload dist/ | | .github/workflows/release.yml | Tag v* / manual dispatch | Build, test, publish npm package |

📦 Publishing

  • Package: @partme.ai/openclaw-mqtt
  • Required secret: NPM_TOKEN
  • Release guide: RELEASING.md

Tag release example:

npm version patch
git push origin main --follow-tags

📁 Project Structure

openclaw-mqtt/
├── src/
│   ├── index.ts              # defineChannelPluginEntry + registerFull (HTTP)
│   ├── setup-entry.ts        # defineSetupPluginEntry(mqttPlugin) — openclaw.setupEntry
│   ├── mqtt-plugin.ts        # ChannelPlugin
│   ├── gateway-mqtt.ts       # Gateway startAccount / broker lifecycle
│   ├── outbound.ts           # ChannelOutboundAdapter
│   ├── inbound.ts            # dispatch to OpenClaw runtime
│   ├── broker.ts             # Aedes TCP server
│   ├── topic-router.ts
│   ├── session-mapper.ts
│   ├── mqtt-config.ts
│   ├── runtime.ts
│   └── openclaw-peer.d.ts    # types when openclaw is not installed locally
├── scripts/
│   └── test-client.ts
├── openclaw.plugin.json
├── package.json
└── README.md / README_CN.md

OpenClaw documentation

Official docs for plugins, the SDK, and this channel’s building blocks:

Plugins

Building plugins

SDK reference

❓ FAQ

Does this plugin require an external MQTT broker?

No. It embeds aedes and starts a local broker service.

How is payload parsed?

Default mode is jsonTextOrPlain: parse JSON.text first, otherwise use raw text.

How do I bind one topic to one agent?

Use topicBindings with topicPattern and agentId; optionally set replyTopic.

📄 License

MIT