MattermostでOpenClawを使うイメージ

【最新版】MattermostでOpenClawを使う方法(Botトークン+WebSocket連携)

Mattermost

Mattermost(プラグイン)

ステータス:プラグイン(Botトークン + WebSocketイベント)経由でサポートされています。チャンネル、グループ、DM(ダイレクトメッセージ)に対応します。

Mattermost はセルフホスト可能なチーム向けメッセージングプラットフォームです。製品詳細やダウンロードは公式サイト: mattermost.com

プラグインが必要

Mattermost はプラグインとして提供されており、コアインストールには同梱されていません。

CLI(npm レジストリ)でインストール:

openclaw plugins install @openclaw/mattermost

ローカルチェックアウト(git リポジトリから実行している場合):

openclaw plugins install ./extensions/mattermost

セットアップ中に Mattermost を選び、かつ git チェックアウトが検出されると、OpenClaw はローカルのインストールパスを自動で提案します。

詳細: Plugins

クイックセットアップ

  1. Mattermost プラグインをインストールします。
  2. Mattermost の bot アカウントを作成し、bot token をコピーします。
  3. Mattermost の base URL をコピーします(例:https://chat.example.com)。
  4. OpenClaw を設定し、Gateway を起動します。

最小の config:

{
  channels: {
    mattermost: {
      enabled: true,
      botToken: "mm-token",
      baseUrl: "https://chat.example.com",
      dmPolicy: "pairing",
    },
  },
}

ネイティブのスラッシュコマンド

ネイティブのスラッシュコマンドはオプトインです。有効化すると、OpenClaw は Mattermost API を通じて oc_* スラッシュコマンドを登録し、 Gateway の HTTP サーバー上のエンドポイントでコールバック POST を受け取ります。

{
  channels: {
    mattermost: {
      commands: {
        native: true,
        nativeSkills: true,
        callbackPath: "/api/channels/mattermost/command",
        // Mattermost が gateway に直接到達できない場合に使用(リバースプロキシ/公開URL)
        callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
      },
    },
  },
}

メモ:

  • native: "auto" は Mattermost ではデフォルトで無効です。有効化するには native: true を設定します。
  • callbackUrl を省略すると、OpenClaw は gateway の host/port と callbackPath から導出します。
  • マルチアカウントの場合、commands はトップレベル、または channels.mattermost.accounts.<id>.commands のどちらにも設定できます(アカウント側がトップレベルを上書き)。
  • コマンドコールバックはコマンドごとのトークンで検証され、トークンチェックが失敗すると fail-closed(拒否)します。
  • 到達性の要件:コールバックエンドポイントは Mattermost サーバーから到達可能である必要があります。
    • Mattermost が同一ホスト/同一ネットワーク名前空間で動いていない限り、callbackUrllocalhost にしないでください。
    • あなたの Mattermost の base URL が /api/channels/mattermost/command を OpenClaw にリバースプロキシしていない限り、callbackUrl を Mattermost base URL にしないでください。
    • curl https://<gateway-host>/api/channels/mattermost/command の GET が、OpenClaw の 405 Method Not Allowed を返すこと(404 ではない)を確認するのが簡易チェックです。
  • Mattermost の egress allowlist 要件:
    • callback が private/tailnet/internal アドレスを指す場合、Mattermost の ServiceSettings.AllowedUntrustedInternalConnections に callback の host/domain を含めてください。
    • フルURLではなく host/domain のエントリを使います。
    • Good:gateway.tailnet-name.ts.net
    • Bad:https://gateway.tailnet-name.ts.net

環境変数(デフォルトアカウント)

env vars を使いたい場合、gateway ホストに次を設定します:

  • MATTERMOST_BOT_TOKEN=...
  • MATTERMOST_URL=https://chat.example.com

env vars は デフォルト アカウント(default)にのみ適用されます。その他のアカウントは config 値を使う必要があります。

チャットモード

Mattermost は DM には自動で返信します。チャンネルでの挙動は chatmode で制御します。

  • oncall(デフォルト):チャンネルでは @メンションされたときだけ返信
  • onmessage:チャンネル内のすべてのメッセージに返信
  • onchar:メッセージがトリガープレフィックスで始まるときに返信

設定例:

{
  channels: {
    mattermost: {
      chatmode: "onchar",
      oncharPrefixes: [">", "!"],
    },
  },
}

メモ:

  • onchar でも、明示的な @メンションには返信します。
  • channels.mattermost.requireMention はレガシー config では尊重されますが、推奨は chatmode です。

スレッドとセッション

channels.mattermost.replyToMode で、チャンネル/グループの返信をメインチャンネルに出すか、 トリガーになった投稿の下にスレッドを開始するかを制御できます。

  • off(デフォルト):受信投稿がすでにスレッド内のときだけスレッド返信
  • first:トップレベルの投稿に対してスレッドを開始し、会話をスレッドスコープのセッションへルーティング
  • all:現時点では Mattermost では first と同挙動
  • DM はこの設定を無視し、スレッド化されません

設定例:

{
  channels: {
    mattermost: {
      replyToMode: "all",
    },
  },
}

メモ:

  • スレッドスコープのセッションは、トリガー投稿 id を thread root として使用します。
  • 現時点では、Mattermost に thread root ができると後続のチャンクやメディアも同じスレッドに継続されるため、firstall は同等です。

アクセス制御(DM)

  • デフォルト:channels.mattermost.dmPolicy = "pairing"(不明な送信者にはペアリングコードを返す)
  • 承認コマンド:openclaw pairing list mattermost / openclaw pairing approve mattermost <CODE>
  • 公開 DM:channels.mattermost.dmPolicy="open" に加えて channels.mattermost.allowFrom=["*"] が必要です。

チャンネル(グループ)

  • デフォルト:channels.mattermost.groupPolicy = "allowlist"(メンションゲート)
  • channels.mattermost.groupAllowFrom で送信者の allowlist を設定できます(ユーザー ID 推奨)。
  • @username による一致は可変で危険なため、channels.mattermost.dangerouslyAllowNameMatching: true のときだけ有効です。
  • オープンチャンネル:channels.mattermost.groupPolicy="open"(メンションゲート)
  • ランタイム注意:channels.mattermost が完全に欠けている場合、グループチェックは groupPolicy="allowlist" にフォールバックします(channels.defaults.groupPolicy を設定していても同様)。

送信(アウトバウンド)ターゲット

openclaw message send や cron/webhook 配信で使えるターゲット形式:

  • channel:<id>:チャンネル
  • user:<id>:DM
  • @username:DM(Mattermost API で解決)

Mattermost では 64ifufp... のような bare の opaque ID は(user ID か channel ID か)曖昧です。

OpenClaw は user-first で解決します:

  • その ID がユーザーとして存在する場合(GET /api/v4/users/<id> が成功)、/api/v4/channels/direct で direct channel を解決して DM を送信します。
  • そうでない場合、その ID は channel ID として扱われます。

決定的な挙動が必要な場合は、必ず user: / channel: プレフィックスを使ってください。

DM チャンネルのリトライ

OpenClaw が Mattermost の DM ターゲットへ送信する際、最初に direct channel を解決する必要がある場合があります。 その direct-channel 作成が一時的に失敗したとき、デフォルトでリトライします。

この挙動は channels.mattermost.dmChannelRetry(全体)または channels.mattermost.accounts.<id>.dmChannelRetry(アカウント単位)で調整できます。

{
  channels: {
    mattermost: {
      dmChannelRetry: {
        maxRetries: 3,
        initialDelayMs: 1000,
        maxDelayMs: 10000,
        timeoutMs: 30000,
      },
    },
  },
}

メモ:

  • これは DM チャンネル作成(/api/v4/channels/direct)にのみ適用され、すべての Mattermost API 呼び出しに適用されるわけではありません。
  • レート制限、5xx、ネットワーク/タイムアウトのような一時的失敗にリトライが適用されます。
  • 429 を除く 4xx は恒久的失敗と扱われ、リトライされません。

リアクション(message ツール)

  • message action=reactchannel=mattermost を使います。
  • messageId は Mattermost の post id です。
  • emojithumbsup:+1: のような名前を受け付けます(コロンは任意)。
  • remove=true(boolean)でリアクションを削除します。
  • リアクションの add/remove イベントは、ルーティング先のエージェントセッションへ system events として転送されます。

例:

message action=react channel=mattermost target=channel:<channelId> messageId=<postId> emoji=thumbsup
message action=react channel=mattermost target=channel:<channelId> messageId=<postId> emoji=thumbsup remove=true

設定:

  • channels.mattermost.actions.reactions:リアクションアクションの有効/無効(デフォルト true)
  • アカウント単位の上書き:channels.mattermost.accounts.<id>.actions.reactions

インラインボタン(message ツール)

クリックできるボタン付きのメッセージを送信できます。ユーザーがボタンをクリックすると、エージェントが選択内容を受け取り、返信できます。

ボタンを有効化するには、チャネルの capabilities に inlineButtons を追加します:

{
  channels: {
    mattermost: {
      capabilities: [&quot;inlineButtons&quot;],
    },
  },
}

message action=sendbuttons パラメータを渡します。ボタンは 2D 配列(行ごとのボタン)です:

message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]

ボタンのフィールド:

  • text(必須):表示ラベル
  • callback_data(必須):クリック時に返る値(action ID として使用)
  • style(任意):"default" / "primary" / "danger"

ユーザーがボタンをクリックすると:

  1. すべてのボタンが確認行に置き換わります(例:"✓ **Yes** selected by @user")。
  2. エージェントは選択を受信メッセージとして受け取り、返信します。

メモ:

  • ボタンコールバックは HMAC-SHA256 で検証されます(自動、追加設定不要)。
  • Mattermost は API レスポンスから callback data を取り除くため(セキュリティ機能)、クリック時にボタンはすべて削除されます。部分削除はできません。
  • action ID にハイフンやアンダースコアが含まれる場合、自動的にサニタイズされます(Mattermost のルーティング制約)。

設定:

  • channels.mattermost.capabilities:capability 文字列配列。ボタンのツール説明をエージェントの system prompt に入れるには "inlineButtons" を追加します。
  • channels.mattermost.interactions.callbackBaseUrl:ボタンコールバック用の外部 base URL(例:https://gateway.example.com)。Mattermost が gateway の bind host に直接到達できない場合に使用します。
  • マルチアカウントの場合:channels.mattermost.accounts.<id>.interactions.callbackBaseUrl でも設定できます。
  • interactions.callbackBaseUrl が省略されると、OpenClaw は gateway.customBindHost + gateway.port から導出し、最後に http://localhost:<port> にフォールバックします。
  • 到達性ルール:ボタンコールバックURLは Mattermost サーバーから到達可能である必要があります。localhost は Mattermost と OpenClaw が同一ホスト/同一ネットワーク名前空間のときだけ動きます。
  • callback が private/tailnet/internal の場合は、Mattermost の ServiceSettings.AllowedUntrustedInternalConnections にその host/domain を追加してください。

Direct API integration(外部スクリプト)

外部スクリプトや Webhook は、エージェントの message ツール経由ではなく Mattermost REST API 経由でボタン投稿もできます。 可能なら拡張側の buildButtonAttachments() を使ってください。生JSONを投稿する場合は次のルールに従います。

ペイロード構造:

{
  channel_id: "<channelId>",
  message: "Choose an option:",
  props: {
    attachments: [
      {
        actions: [
          {
            id: "mybutton01", // 英数字のみ — 下記参照
            type: "button", // 必須。これがないとクリックが黙って無視される
            name: "Approve", // 表示ラベル
            style: "primary", // 任意: "default" | "primary" | "danger"
            integration: {
              url: "https://gateway.example.com/mattermost/interactions/default",
              context: {
                action_id: "mybutton01", // ボタン id と一致させる(名称表示に使用)
                action: "approve",
                // ... 任意のカスタムフィールド ...
                _token: "<hmac>", // 下記 HMAC セクション参照
              },
            },
          },
        ],
      },
    ],
  },
}

重要ルール:

  1. attachments はトップレベルではなく props.attachments に入れます(トップレベルは黙って無視されます)。
  2. 各 action に type: "button" が必要です。ないとクリックが黙って捨てられます。
  3. 各 action に id フィールドが必要です。ないと Mattermost が action を無視します。
  4. action の id英数字のみ[a-zA-Z0-9])。ハイフンやアンダースコアは Mattermost の action ルーティングを壊し 404 になります。
  5. context.action_id はボタンの id と一致させます。そうしないと確認メッセージがボタン名ではなく生の ID になります。
  6. context.action_id は必須です。interaction handler はこれがないと 400 を返します。

HMAC トークン生成

Gateway は HMAC-SHA256 でボタンクリックを検証します。外部スクリプトは gateway の検証ロジックに一致するトークンを生成する必要があります。

  1. bot token から secret を導出します:HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)
  2. _token を除く全フィールドを含む context オブジェクトを作ります。
  3. キーをソートし、スペースなしでシリアライズします(gateway はキーソートした上で JSON.stringify 相当のコンパクト出力を使います)。
  4. 署名:HMAC-SHA256(key=secret, data=serializedContext)
  5. hex digest を _token として context に追加します。

Python 例:

import hmac, hashlib, json

secret = hmac.new(
    b"openclaw-mattermost-interactions",
    bot_token.encode(), hashlib.sha256
).hexdigest()

ctx = {"action_id": "mybutton01", "action": "approve"}
payload = json.dumps(ctx, sort_keys=True, separators=(",", ":"))
token = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()

context = {**ctx, "_token": token}

よくある HMAC の落とし穴:

  • Python の json.dumps はデフォルトでスペースが入ります(例:{"key": "val"})。separators=(",", ":") を使い、JS のコンパクト出力(例:{"key":"val"})に合わせてください。
  • _token を除く)context の 全フィールドを必ず署名してください。subset だけ署名すると黙って検証に失敗します。
  • sort_keys=True を必ず使ってください(gateway は署名前にキーをソートし、Mattermost が保存時に順序を並べ替える可能性があります)。
  • secret はランダムではなく bot token から導出します(決定的)。ボタンを作る側と検証する gateway 側で secret が一致する必要があります。

ディレクトリアダプタ

Mattermost プラグインには、Mattermost API 経由でチャンネル名とユーザー名を解決する directory adapter が含まれています。 これにより openclaw message send や cron/webhook の配信ターゲットで #channel-name@username を使えるようになります。

追加の設定は不要です(アカウント config の bot token を使います)。

マルチアカウント

Mattermost は channels.mattermost.accounts で複数アカウントをサポートします:

{
  channels: {
    mattermost: {
      accounts: {
        default: { name: "Primary", botToken: "mm-token", baseUrl: "https://chat.example.com" },
        alerts: { name: "Alerts", botToken: "mm-token-2", baseUrl: "https://alerts.example.com" },
      },
    },
  },
}

トラブルシューティング

  • チャンネルで返信がない:ボットがチャンネルに居ることを確認し、(oncall なら)@メンションする/(onchar なら)トリガープレフィックスを使う/chatmode: "onmessage" にする。
  • 認証エラー:bot token、base URL、アカウントが enabled かを確認。
  • マルチアカウント問題:env vars は default アカウントにしか適用されません。
  • ボタンが白い箱になる:エージェントが不正なボタンデータを送っている可能性。各ボタンに textcallback_data があるか確認。
  • ボタンが表示されるがクリックしても何も起きない:Mattermost サーバー設定で AllowedUntrustedInternalConnections127.0.0.1 localhost が含まれていること、そして ServiceSettings.EnablePostActionIntegrationtrue であることを確認。
  • ボタンが 404 を返す:ボタンの id にハイフン/アンダースコアが含まれている可能性。[a-zA-Z0-9] のみ使用。
  • Gateway ログに invalid _token:HMAC 不一致。全 context フィールドを署名しているか、キーソート、コンパクト JSON(スペースなし)を確認(上の HMAC セクション参照)。
  • Gateway ログに missing _token in context:ボタン context に _token が入っていません。integration payload 作成時に含めてください。
  • 確認表示がボタン名でなく生 ID:context.action_id がボタンの id と一致していません。両方を同じサニタイズ済み値にします。
  • エージェントがボタンを知らない:Mattermost チャネル config に capabilities: ["inlineButtons"] を追加します。

参考

BizClaw 導入支援

OpenClaw の構築を
まるごと代行します

Mac mini のセットアップから Slack・iMessage 連携まで、届いた日から使える状態でお届けします。

サービスを見る

関連記事

Read article
AIエージェントのメモリスタックとは?2026年に重要度が上がる理由をやさしく解説

AIエージェントのメモリスタックとは?2026年に重要度が上がる理由をやさしく解説

Read article
OpenClaw vs Hermes vs Claude、創業者はどれを選ぶべき?2026年版の実務比較

OpenClaw vs Hermes vs Claude、創業者はどれを選ぶべき?2026年版の実務比較

Read article
X公式MCPサーバーとは?AIエージェント運用で何が変わるのかを実務目線で解説

X公式MCPサーバーとは?AIエージェント運用で何が変わるのかを実務目線で解説