MINARA

Mattermost

Self-hosted Mattermost with bot-token outbound + outgoing-webhook inbound. Public channels only on the inbound side.

🟡 Outbound-ready, inbound only on public channels via outgoing webhook, the lightest-friction path. Mattermost's WebSocket bot mode (which supports DMs and private channels) is a future enhancement.

What you get

  • Outbound text via POST /api/v4/posts with bot personal access token. Threaded replies via root_id are supported.
  • Inbound outgoing webhook at /webhooks/mattermost. Mattermost POSTs to the webhook URL when a configured trigger word appears in a public channel.
  • Text only this PR. File uploads via Mattermost's Files API and attachments parsing are deferred.
  • 16383-char text limit (Mattermost's default PostMessageMaxRunes).

Setup

1. Create a bot account

  1. Sign in to Mattermost as a System Admin
  2. System Console → "Integrations" → "Bot Accounts": "Add Bot Account"
  3. Pick a username (e.g. minara), display name, optional avatar. On Save, Mattermost reveals the Bot Personal Access Token. Save it (you cannot retrieve it later)
  4. Invite the bot into the target channel: /invite @minara in the channel composer

2. Set up an outgoing webhook (optional, for inbound)

  1. Same screen, "Integrations" → "Outgoing Webhooks": "Add Outgoing Webhook"
  2. Configure:
    • Channel: the public channel the webhook listens in
    • Trigger words: e.g. @bot, !minara (Mattermost only fires the webhook when a message starts with one of these)
    • Callback URLs: https://<your-host>/webhooks/mattermost
  3. Save. Copy the generated Token (becomes MATTERMOST_OUTGOING_WEBHOOK_TOKEN)

3. Configure Minara

minara auth messaging add
# pick `mattermost` from the list.

Or set env vars:

MATTERMOST_URL=https://mattermost.example.com
MATTERMOST_BOT_TOKEN=<personal access token>
MATTERMOST_DEFAULT_CHANNEL_ID=<channel id from Channel URL>
MATTERMOST_OUTGOING_WEBHOOK_TOKEN=<outgoing-webhook token>

The channel id appears in the URL when you open a channel: https://mattermost.example.com/team/channels/<id> → the <id> slug.

4. Test

minara auth messaging test mattermost

Inbound webhook

Mattermost's outgoing webhook POSTs application/x-www-form-urlencoded to /webhooks/mattermost with fields including:

token=<webhook token>
channel_id=<channel id>
user_id=<user id>
user_name=<username>
text=<the user's message>
post_id=<message id>
trigger_word=<matched trigger>
from_webhook=false

Minara verifies the token field against MATTERMOST_OUTGOING_WEBHOOK_TOKEN in constant time. The from_webhook === "true" flag filters self-loops (the bot's own posts re-arriving via the trigger).

Limits & caveats

  • Outgoing webhooks only fire in PUBLIC channels. Private channels and DMs need the WebSocket bot path (planned). Configure trigger words carefully so a hot channel does not flood the agent.
  • Trigger-word prefix only. Mattermost matches the trigger at the start of the message. @bot hello works, hello @bot does not.
  • Constant-time compare, not HMAC. The token is the entire authentication surface for inbound. Treat it as a secret.
  • No streaming edits. Mattermost's PUT /posts/<id> exists but the gateway does not wire it.

Troubleshooting

"401 Unauthorized" on outbound

  • MATTERMOST_BOT_TOKEN is wrong, expired, or scoped to a different team. Generate a fresh token in System Console and update env.

"Outgoing webhook does not fire"

  • The channel is private (only public is supported)
  • The message did not start with one of the trigger words
  • The webhook is configured on a different channel than the message

"401 on inbound"

  • MATTERMOST_OUTGOING_WEBHOOK_TOKEN mismatch. The token rotates if you re-create the webhook; sync env.

Reference

On this page