
【最新版】MattermostでOpenClawを使う方法(Botトークン+WebSocket連携)
2026年3月18日
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
クイックセットアップ
- Mattermost プラグインをインストールします。
- Mattermost の bot アカウントを作成し、bot token をコピーします。
- Mattermost の base URL をコピーします(例:
https://chat.example.com)。 - 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 が同一ホスト/同一ネットワーク名前空間で動いていない限り、
callbackUrlをlocalhostにしないでください。 - あなたの 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 が同一ホスト/同一ネットワーク名前空間で動いていない限り、
- 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
- callback が private/tailnet/internal アドレスを指す場合、Mattermost の
環境変数(デフォルトアカウント)
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 ができると後続のチャンクやメディアも同じスレッドに継続されるため、
firstとallは同等です。
アクセス制御(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=reactでchannel=mattermostを使います。messageIdは Mattermost の post id です。emojiはthumbsupや:+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: ["inlineButtons"],
},
},
}message action=send で buttons パラメータを渡します。ボタンは 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"
ユーザーがボタンをクリックすると:
- すべてのボタンが確認行に置き換わります(例:
"✓ **Yes** selected by @user")。 - エージェントは選択を受信メッセージとして受け取り、返信します。
メモ:
- ボタンコールバックは 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 セクション参照
},
},
},
],
},
],
},
}重要ルール:
- attachments はトップレベルではなく
props.attachmentsに入れます(トップレベルは黙って無視されます)。 - 各 action に
type: "button"が必要です。ないとクリックが黙って捨てられます。 - 各 action に
idフィールドが必要です。ないと Mattermost が action を無視します。 - action の
idは 英数字のみ([a-zA-Z0-9])。ハイフンやアンダースコアは Mattermost の action ルーティングを壊し 404 になります。 context.action_idはボタンのidと一致させます。そうしないと確認メッセージがボタン名ではなく生の ID になります。context.action_idは必須です。interaction handler はこれがないと 400 を返します。
HMAC トークン生成
Gateway は HMAC-SHA256 でボタンクリックを検証します。外部スクリプトは gateway の検証ロジックに一致するトークンを生成する必要があります。
- bot token から secret を導出します:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) _tokenを除く全フィールドを含む context オブジェクトを作ります。- キーをソートし、スペースなしでシリアライズします(gateway はキーソートした上で
JSON.stringify相当のコンパクト出力を使います)。 - 署名:
HMAC-SHA256(key=secret, data=serializedContext) - 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アカウントにしか適用されません。 - ボタンが白い箱になる:エージェントが不正なボタンデータを送っている可能性。各ボタンに
textとcallback_dataがあるか確認。 - ボタンが表示されるがクリックしても何も起きない:Mattermost サーバー設定で
AllowedUntrustedInternalConnectionsに127.0.0.1 localhostが含まれていること、そしてServiceSettings.EnablePostActionIntegrationがtrueであることを確認。 - ボタンが 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"]を追加します。
参考
関連記事

AIエージェントのメモリスタックとは?2026年に重要度が上がる理由をやさしく解説
2026年4月8日
OpenClaw vs Hermes vs Claude、創業者はどれを選ぶべき?2026年版の実務比較
2026年4月8日