OpenClawとMattermostを連携:5分でボットを構築する方法
プラグインが必要です
Section titled “プラグインが必要です”Mattermostはプラグインとして提供されており、コア・インストールには含まれていません。
CLI(npmレジストリ)を使用してインストールしてください:
openclaw plugins install @openclaw/mattermostローカルのチェックアウト(gitリポジトリから実行している場合)からインストールする場合はこちらです:
openclaw plugins install ./path/to/local/mattermost-pluginセットアップ中にMattermostを選択し、gitのチェックアウトが検出された場合、OpenClawは自動的にローカルのインストールパスを提案します。
詳細はこちら:Plugins
クイックセットアップ
Section titled “クイックセットアップ”- Mattermostプラグインをインストールします。
- Mattermostのボットアカウントを作成し、bot tokenをコピーします。
- MattermostのベースURL(例:
https://chat.example.com)をコピーします。 - OpenClawを設定し、Gatewayを起動します。
最小限の構成例です:
{ channels: { mattermost: { enabled: true, botToken: "mm-token", baseUrl: "https://chat.example.com", dmPolicy: "pairing", }, },}ネイティブのスラッシュコマンド
Section titled “ネイティブのスラッシュコマンド”ネイティブのスラッシュコマンドはオプトイン方式です。有効にすると、OpenClawはMattermost APIを介して oc_* スラッシュコマンドを登録し、GatewayのHTTPサーバーでコールバックのPOSTを受け取ります。
{ channels: { mattermost: { commands: { native: true, nativeSkills: true, callbackPath: "/api/channels/mattermost/command", // Use when Mattermost cannot reach the gateway directly (reverse proxy/public URL). callbackUrl: "https://gateway.example.com/api/channels/mattermost/command", }, }, },}注意点:
- Mattermostでは
native: "auto"はデフォルトで無効になります。有効にするにはnative: trueを設定してください。 callbackUrlを省略した場合、OpenClawはGatewayのホスト/ポートとcallbackPathからURLを自動生成します。- マルチアカウント設定の場合、
commandsはトップレベル、またはchannels.mattermost.accounts.<id>.commandsの下で設定できます(アカウントごとの値がトップレベルの設定を上書きします)。 - コマンドのコールバックは、コマンドごとのトークンで検証されます。トークンのチェックに失敗した場合は、安全のために処理を拒否(fail closed)します。
- 到達可能性の要件:Mattermostサーバーからコールバックエンドポイントにアクセスできる必要があります。
- MattermostがOpenClawと同じホストやネットワーク名前空間で動作していない限り、
callbackUrlにlocalhostを設定しないでください。 - そのURLが
/api/channels/mattermost/commandをOpenClawにリバースプロキシしていない限り、callbackUrlにMattermostのベースURLを設定しないでください。 curl https://<gateway-host>/api/channels/mattermost/commandで簡単に確認できます。OpenClawから404ではなく、GETに対して405 Method Not Allowedが返ってくれば正常です。
- MattermostがOpenClawと同じホストやネットワーク名前空間で動作していない限り、
- Mattermostの送信許可リスト(egress allowlist)の要件:
- コールバック先がプライベート、Tailnet、または内部アドレスの場合は、Mattermostの
ServiceSettings.AllowedUntrustedInternalConnectionsにコールバックのホストまたはドメインを含めるように設定してください。 - フルURLではなく、ホストまたはドメインのエントリを使用してください。
- 良い例:
gateway.tailnet-name.ts.net - 悪い例:
https://gateway.tailnet-name.ts.net
- 良い例:
- コールバック先がプライベート、Tailnet、または内部アドレスの場合は、Mattermostの
環境変数(デフォルトアカウント)
Section titled “環境変数(デフォルトアカウント)”環境変数を使いたい場合は、Gatewayのホストに以下を設定してください:
MATTERMOST_BOT_TOKEN=...MATTERMOST_URL=https://chat.example.com
環境変数はデフォルトのアカウント(default)にのみ適用されます。その他のアカウントについては、設定ファイルの値を使用する必要があります。
チャットモード
Section titled “チャットモード”MattermostはDM(ダイレクトメッセージ)に対して自動的に応答します。チャンネル内での動作は chatmode で制御できます。
oncall(デフォルト): チャンネル内で @メンションされた時のみ応答します。onmessage: チャンネル内のすべてのメッセージに応答します。onchar: メッセージが特定のトリガー接頭辞で始まる時に応答します。
設定例:
{ channels: { mattermost: { chatmode: "onchar", oncharPrefixes: [">", "!"], }, },}注意点:
oncharを使用している場合でも、明示的な @メンションには応答します。- 以前の設定である
channels.mattermost.requireMentionも引き続き尊重されますが、現在はchatmodeの使用を推奨しています。
スレッドとセッション
Section titled “スレッドとセッション”channels.mattermost.replyToMode を使用すると、チャンネルやグループでの返信をメインチャンネルにそのまま投稿するか、きっかけとなった投稿の下にスレッドを開始するかを選択できます。
off(デフォルト): 受信した投稿がすでにスレッド内にある場合のみ、スレッドで返信します。first: トップレベルの投稿に対してスレッドを開始し、その会話をスレッドスコープのセッションにルーティングします。all: 現在の Mattermost においてはfirstと同じ動作になります。- ダイレクトメッセージ(DM)はこの設定を無視し、スレッド化されません。
設定例:
{ channels: { mattermost: { replyToMode: "all", }, },}注意点:
- スレッドスコープのセッションは、トリガーとなった投稿の ID をスレッドのルートとして使用します。
- Mattermost が一度スレッドルートを特定すると、その後のメッセージやメディアも同じスレッド内で継続されるため、現時点では
firstとallは同じ挙動になります。
アクセス制御 (DM)
Section titled “アクセス制御 (DM)”- デフォルト設定:
channels.mattermost.dmPolicy = "pairing"が適用されます。これにより、不明な送信者にはペアリングコードが送信されます。 - 承認コマンド:
openclaw pairing list mattermostopenclaw pairing approve mattermost <CODE>
- 公開 DM 設定: すべてのユーザーからの DM を許可するには、
channels.mattermost.dmPolicy="open"とchannels.mattermost.allowFrom=["*"]を組み合わせて設定してください。
チャンネル (グループ)
Section titled “チャンネル (グループ)”- デフォルト設定:
channels.mattermost.groupPolicy = "allowlist"が適用されます(メンションによる制限あり)。 - 許可リストへの追加:
channels.mattermost.groupAllowFromを使用して送信者を許可します(ユーザー ID での指定を推奨します)。 - 名前によるマッチング:
@usernameによるマッチングは変更される可能性があるため、channels.mattermost.dangerouslyAllowNameMatching: trueが設定されている場合のみ有効になります。 - 公開チャンネル:
channels.mattermost.groupPolicy="open"を設定します(メンションによる制限は維持されます)。 - 実行時の注意:
channels.mattermostの設定が完全に存在しない場合、channels.defaults.groupPolicyが設定されていても、グループチェックはgroupPolicy="allowlist"にフォールバックされます。
送信先の指定方法
Section titled “送信先の指定方法”openclaw message send や cron、webhooks では、以下の形式で送信先を指定できます。
channel:<id>:チャンネルを指定user:<id>:DMを指定@username:DMを指定(Mattermost API を通じて解決されます)
Mattermost において、プレフィックスのない ID(例:64ifufp...)は、ユーザー ID なのかチャンネル ID なのかが曖昧です。
OpenClaw では、以下の優先順位でこれらを解決します。
- まず、その ID がユーザーとして存在するか確認します(
GET /api/v4/users/<id>が成功した場合)。存在すれば、/api/v4/channels/directを経由してダイレクトチャンネルを特定し、DM を送信します。 - ユーザーが見つからない場合は、チャンネル ID として扱われます。
動作を確定させたい場合は、常に明示的なプレフィックス(user:<id> または channel:<id>)を使用するのがベストです。
DM チャンネル作成のリトライ
Section titled “DM チャンネル作成のリトライ”OpenClaw が Mattermost の DM 宛に送信する際、まずダイレクトチャンネルを特定する必要があります。このとき、チャンネル作成で一時的なエラーが発生した場合は、デフォルトでリトライが実行されます。
この挙動は、Mattermost プラグイン全体の設定として channels.mattermost.dmChannelRetry で調整できます。また、特定のアカウントに対して個別に設定する場合は channels.mattermost.accounts.<id>.dmChannelRetry を使用してください。
{ channels: { mattermost: { dmChannelRetry: { maxRetries: 3, initialDelayMs: 1000, maxDelayMs: 10000, timeoutMs: 30000, }, }, },}注意点:
- この設定はダイレクトチャンネルの作成(
/api/v4/channels/direct)にのみ適用され、すべての Mattermost API 呼び出しに適用されるわけではありません。 - リトライは、レート制限、5xx レスポンス、ネットワークエラー、タイムアウトなどの一時的な失敗に対して行われます。
429以外の 4xx クライアントエラーは恒久的なエラーとみなされ、リトライは行われません。
リアクション (message tool)
Section titled “リアクション (message tool)”Mattermostでリアクションを操作する方法を紹介します。
message action=reactをchannel=mattermostと組み合わせて使用します。messageIdには Mattermost の投稿 ID を指定してください。emojiはthumbsupや:+1:といった名前を受け付けます(コロンはあってもなくても大丈夫です)。- リアクションを消したいときは、
remove=true(boolean) を設定します。 - リアクションの追加や削除のイベントは、システムイベントとしてルーティング先のエージェントセッションに転送されます。
例:
message action=react channel=mattermost target=channel:<channelId> messageId=<postId> emoji=thumbsupmessage 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 tool)
Section titled “インタラクティブボタン (message tool)”クリック可能なボタン付きのメッセージを送信できます。ユーザーがボタンをクリックすると、エージェントがその選択内容を受け取り、それに応じた応答を返すことが可能です。
まず、チャンネルの capabilities に inlineButtons を追加してボタンを有効にしましょう。
{ channels: { mattermost: { capabilities: ["inlineButtons"], }, },}送信には message action=send を使い、buttons パラメータを指定します。ボタンは 2 次元配列(ボタンの行の集まり)として定義します。
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]ボタンのフィールドについて:
textとcallback_data(いずれも必須): 表示されるラベルと、クリック時に返される値(アクション ID)です。style(任意):"default","primary","danger"から選べます。
ユーザーがボタンをクリックした後の流れは以下の通りです。
- すべてのボタンが確認メッセージ(例: 「✓ @user が Yes を選択しました」)に置き換わります。
- エージェントは選択内容をインバウンドメッセージとして受信し、次のアクションを実行します。
いくつか注意点があります。
- ボタンのコールバックは HMAC-SHA256 検証を使用しますが、これは自動で行われるため特別な設定は不要です。
- Mattermost のセキュリティ仕様により、API レスポンスからコールバックデータが削除されます。そのため、クリック時にはすべてのボタンが削除されます(一部だけ残すことはできません)。
- アクション ID にハイフンやアンダースコアが含まれている場合、Mattermost のルーティング制限を回避するために自動でサニタイズされます。
設定の詳細:
channels.mattermost.capabilities: capability 文字列の配列です。"inlineButtons"を追加すると、エージェントのシステムプロンプトにボタンツールの説明が含まれるようになります。channels.mattermost.interactions.callbackBaseUrl: 任意の設定です。ボタンコールバック用の外部ベース URL(例:https://gateway.example.com)を指定します。Mattermost が Gateway のバインドホストに直接アクセスできない場合に役立ちます。- マルチアカウント構成の場合は、
channels.mattermost.accounts.<id>.interactions.callbackBaseUrlでも設定可能です。 interactions.callbackBaseUrlを省略した場合、OpenClaw はgateway.customBindHost+gateway.portから URL を生成し、それがなければhttp://localhost:<port>を使用します。- 到達性のルールとして、ボタンのコールバック URL は Mattermost サーバーからアクセスできる必要があります。
localhostが使えるのは、Mattermost と OpenClaw が同じホストやネットワーク名前空間にいる場合だけです。 - コールバック先がプライベートなネットワークや Tailscale 内にある場合は、そのホストやドメインを Mattermost の
ServiceSettings.AllowedUntrustedInternalConnectionsに追加してください。
直接 API 連携 (外部スクリプト)
Section titled “直接 API 連携 (外部スクリプト)”外部スクリプトや Webhook を使って、エージェントの message ツールを通さずに Mattermost REST API から直接ボタンを投稿することもできます。可能な限り拡張機能の buildButtonAttachments() を使ってください。生の JSON を投稿する場合は、以下のルールを厳守してください。
ペイロード構造:
{ channel_id: "<channelId>", message: "Choose an option:", props: { attachments: [ { actions: [ { id: "mybutton01", // alphanumeric only — see below type: "button", // required, or clicks are silently ignored name: "Approve", // display label style: "primary", // optional: "default", "primary", "danger" integration: { url: "https://gateway.example.com/mattermost/interactions/default", context: { action_id: "mybutton01", // must match button id (for name lookup) action: "approve", // ... any custom fields ... _token: "<hmac>", // see HMAC section below }, }, }, ], }, ], },}重要なルール:
- アタッチメントはトップレベルの
attachmentsではなく、必ずprops.attachmentsに入れてください。 - すべてのアクションに
type: "button"を含めてください。これがないとクリックしても反応しません。 - すべてのアクションに
idフィールドが必要です。ID がないアクションは Mattermost に無視されます。 - アクションの
idは 英数字のみ ([a-zA-Z0-9]) で構成してください。ハイフンやアンダースコアを使うと Mattermost のサーバー側ルーティングが失敗し、404 エラーになります。 context.action_idはボタンのidと一致させてください。これにより、確認メッセージで ID ではなくボタン名(例: 「Approve」)が表示されるようになります。context.action_idは必須項目です。これがないとハンドラーが 400 エラーを返します。
HMAC トークンの生成:
Gateway は HMAC-SHA256 を使ってボタンのクリックを検証します。外部スクリプトでトークンを作る際は、以下の手順で Gateway の検証ロジックに合わせてください。
- ボットトークンからシークレットを生成します:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) _tokenフィールドを除いたすべてのコンテキストフィールドを持つオブジェクトを用意します。- キーをアルファベット順にソートし、スペースなしでシリアル化します(Gateway は
JSON.stringifyのコンパクトな出力を使います)。 - 署名を作成します:
HMAC-SHA256(key=secret, data=serializedContext) - 得られた 16 進ダイジェストを
_tokenとしてコンテキストに追加します。
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"})。JavaScript の出力に合わせるため、必ずseparators=(",", ":")を使ってください。 _token以外のすべてのコンテキストフィールドを署名対象にしてください。一部だけだと検証に失敗します。sort_keys=Trueを忘れないでください。Gateway は署名前に必ずソートを行います。- シークレットはランダムに作らず、必ずボットトークンから派生させてください。ボタン作成側と Gateway 側で同じシークレットを共有する必要があります。
ディレクトリアダプター
Section titled “ディレクトリアダプター”Mattermostプラグインには、Mattermost APIを通じてチャンネル名やユーザー名を解決するディレクトリアダプターが含まれています。これがあるおかげで、openclaw message sendコマンドやcron、webhookでの通知の際に、#channel-nameや@usernameといった形式で送信先を直接指定できるようになります。
特別な設定は必要ありません。このアダプターは、アカウント設定にあるbot tokenを自動的に使用して動作します。
マルチアカウント
Section titled “マルチアカウント”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" }, }, }, },}トラブルシューティング
Section titled “トラブルシューティング”- チャンネルで返信がない場合:Botがチャンネルに参加していることを確認し、メンション(oncall)を送るか、トリガー接頭辞(onchar)を使用してください。または、
chatmode: "onmessage"を設定してみてください。 - 認証エラー:Botの token、base URL、およびアカウントが有効化されているかを確認してください。
- 複数アカウントの問題:環境変数は
defaultアカウントにのみ適用されます。 - ボタンが白いボックスとして表示される:Agent が不正な形式のボタンデータを送信している可能性があります。各ボタンに
textとcallback_dataフィールドの両方が含まれているか確認してください。 - ボタンは表示されるがクリックしても反応しない:Mattermost サーバー設定の
AllowedUntrustedInternalConnectionsに127.0.0.1 localhostが含まれていること、および ServiceSettings のEnablePostActionIntegrationがtrueになっていることを確認してください。 - クリック時にボタンが 404 エラーを返す:ボタンの
idにハイフンやアンダースコアが含まれている可能性があります。Mattermost のアクションルーターは英数字以外の ID では正しく動作しません。[a-zA-Z0-9]のみを使用してください。 - Gateway が
invalid _tokenをログ出力する:HMAC の不一致です。一部のフィールドだけでなく、すべてのコンテキストフィールドを署名対象に含め、キーをソートし、コンパクトな JSON(スペースなし)を使用しているか確認してください。詳細は上記の HMAC セクションを参照してください。 - Gateway が
missing _token in contextをログ出力する:_tokenフィールドがボタンのコンテキストに含まれていません。統合ペイロードを構築する際に、これらが含まれていることを確認してください。 - 確認画面にボタン名ではなく生の ID が表示される:
context.action_idがボタンのidと一致していません。両方に同じサニタイズ済みの値を設定してください。 - Agent がボタンを認識しない:Mattermost チャンネル設定に
capabilities: ["inlineButtons"]を追加してください。
- Channels Overview — サポートされているすべてのチャンネル
- Pairing — DM 認証とペアリングのフロー
- Groups — グループチャットの動作とメンションによる制限
- Channel Routing — メッセージのセッションルーティング
- Security — アクセスモデルとセキュリティ強化
OpenClaw Expert
まだ解決しませんか?
このページで解決しない場合は、OpenClaw Expertに直接質問してください。