コンテンツにスキップ

OpenClawとMattermostを連携:5分でボットを構築する方法

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

CLI(npmレジストリ)を使用してインストールしてください:

Terminal window
openclaw plugins install @openclaw/mattermost

ローカルのチェックアウト(gitリポジトリから実行している場合)からインストールする場合はこちらです:

Terminal window
openclaw plugins install ./path/to/local/mattermost-plugin

セットアップ中にMattermostを選択し、gitのチェックアウトが検出された場合、OpenClawは自動的にローカルのインストールパスを提案します。

詳細はこちら:Plugins

  1. Mattermostプラグインをインストールします。
  2. Mattermostのボットアカウントを作成し、bot tokenをコピーします。
  3. MattermostのベースURL(例:https://chat.example.com)をコピーします。
  4. 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の送信許可リスト(egress allowlist)の要件:
    • コールバック先がプライベート、Tailnet、または内部アドレスの場合は、Mattermostの ServiceSettings.AllowedUntrustedInternalConnections にコールバックのホストまたはドメインを含めるように設定してください。
    • フルURLではなく、ホストまたはドメインのエントリを使用してください。
      • 良い例: gateway.tailnet-name.ts.net
      • 悪い例: https://gateway.tailnet-name.ts.net

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

Section titled “環境変数(デフォルトアカウント)”

環境変数を使いたい場合は、Gatewayのホストに以下を設定してください:

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

環境変数はデフォルトのアカウント(default)にのみ適用されます。その他のアカウントについては、設定ファイルの値を使用する必要があります。

MattermostはDM(ダイレクトメッセージ)に対して自動的に応答します。チャンネル内での動作は chatmode で制御できます。

  • oncall (デフォルト): チャンネル内で @メンションされた時のみ応答します。
  • onmessage: チャンネル内のすべてのメッセージに応答します。
  • onchar: メッセージが特定のトリガー接頭辞で始まる時に応答します。

設定例:

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

注意点:

  • onchar を使用している場合でも、明示的な @メンションには応答します。
  • 以前の設定である channels.mattermost.requireMention も引き続き尊重されますが、現在は chatmode の使用を推奨しています。

channels.mattermost.replyToMode を使用すると、チャンネルやグループでの返信をメインチャンネルにそのまま投稿するか、きっかけとなった投稿の下にスレッドを開始するかを選択できます。

  • off (デフォルト): 受信した投稿がすでにスレッド内にある場合のみ、スレッドで返信します。
  • first: トップレベルの投稿に対してスレッドを開始し、その会話をスレッドスコープのセッションにルーティングします。
  • all: 現在の Mattermost においては first と同じ動作になります。
  • ダイレクトメッセージ(DM)はこの設定を無視し、スレッド化されません。

設定例:

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

注意点:

  • スレッドスコープのセッションは、トリガーとなった投稿の ID をスレッドのルートとして使用します。
  • Mattermost が一度スレッドルートを特定すると、その後のメッセージやメディアも同じスレッド内で継続されるため、現時点では first と all は同じ挙動になります。
  • デフォルト設定: channels.mattermost.dmPolicy = "pairing" が適用されます。これにより、不明な送信者にはペアリングコードが送信されます。
  • 承認コマンド:
    • openclaw pairing list mattermost
    • openclaw pairing approve mattermost <CODE>
  • 公開 DM 設定: すべてのユーザーからの DM を許可するには、channels.mattermost.dmPolicy="open" と channels.mattermost.allowFrom=["*"] を組み合わせて設定してください。
  • デフォルト設定: channels.mattermost.groupPolicy = "allowlist" が適用されます(メンションによる制限あり)。
  • 許可リストへの追加: channels.mattermost.groupAllowFrom を使用して送信者を許可します(ユーザー ID での指定を推奨します)。
  • 名前によるマッチング: @username によるマッチングは変更される可能性があるため、channels.mattermost.dangerouslyAllowNameMatching: true が設定されている場合のみ有効になります。
  • 公開チャンネル: channels.mattermost.groupPolicy="open" を設定します(メンションによる制限は維持されます)。
  • 実行時の注意: channels.mattermost の設定が完全に存在しない場合、channels.defaults.groupPolicy が設定されていても、グループチェックは groupPolicy="allowlist" にフォールバックされます。

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>)を使用するのがベストです。

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 クライアントエラーは恒久的なエラーとみなされ、リトライは行われません。

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=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 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" から選べます。

ユーザーがボタンをクリックした後の流れは以下の通りです。

  1. すべてのボタンが確認メッセージ(例: 「✓ @user が Yes を選択しました」)に置き換わります。
  2. エージェントは選択内容をインバウンドメッセージとして受信し、次のアクションを実行します。

いくつか注意点があります。

  • ボタンのコールバックは 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 に追加してください。

外部スクリプトや 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
},
},
},
],
},
],
},
}

重要なルール:

  1. アタッチメントはトップレベルの attachments ではなく、必ず props.attachments に入れてください。
  2. すべてのアクションに type: "button" を含めてください。これがないとクリックしても反応しません。
  3. すべてのアクションに id フィールドが必要です。ID がないアクションは Mattermost に無視されます。
  4. アクションの id は 英数字のみ ([a-zA-Z0-9]) で構成してください。ハイフンやアンダースコアを使うと Mattermost のサーバー側ルーティングが失敗し、404 エラーになります。
  5. context.action_id はボタンの id と一致させてください。これにより、確認メッセージで ID ではなくボタン名(例: 「Approve」)が表示されるようになります。
  6. context.action_id は必須項目です。これがないとハンドラーが 400 エラーを返します。

HMAC トークンの生成:

Gateway は HMAC-SHA256 を使ってボタンのクリックを検証します。外部スクリプトでトークンを作る際は、以下の手順で Gateway の検証ロジックに合わせてください。

  1. ボットトークンからシークレットを生成します: HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)
  2. _token フィールドを除いたすべてのコンテキストフィールドを持つオブジェクトを用意します。
  3. キーをアルファベット順にソートし、スペースなしでシリアル化します(Gateway は JSON.stringify のコンパクトな出力を使います)。
  4. 署名を作成します: HMAC-SHA256(key=secret, data=serializedContext)
  5. 得られた 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 側で同じシークレットを共有する必要があります。

Mattermostプラグインには、Mattermost APIを通じてチャンネル名やユーザー名を解決するディレクトリアダプターが含まれています。これがあるおかげで、openclaw message sendコマンドやcron、webhookでの通知の際に、#channel-nameや@usernameといった形式で送信先を直接指定できるようになります。

特別な設定は必要ありません。このアダプターは、アカウント設定にある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" },
},
},
},
}
  • チャンネルで返信がない場合: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

OpenClaw Expert

まだ解決しませんか?

このページで解決しない場合は、OpenClaw Expertに直接質問してください。