Webhooks by Wakeshift について
Webhooks by Wakeshift は、外部イベントで AI エージェントの会話を起動したい開発者向けに、監視可能な webhook URL を提供します。MCP ツールでイベントを購読し、POST、PUT、PATCH の受信を会話に通知します。
主な機能
- 01webhook リンクと受信 URL の作成
- 02イベントの購読と解除
- 03最近の投稿と webhook 情報の表示
- 04GitHub、Stripe、Linear の署名検証
- 05イベントと接続状態のライブ表示
活用シーン
- 01GitHub のワークフロー失敗時にエージェントを起動
- 02Stripe の決済イベントを受けて処理を開始
- 03Linear の更新をエージェントに通知
MCP 対応
Streamable HTTP の MCP サーバーとして、`watch`、`unwatch`、`recent_posts`、`webhook_info` を提供します。MCP クライアントは `webhook.received` を購読し、リクエスト受信時に会話を起動できます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://try.wakeshift.ai/t/{link}/mcpclaude mcp add --transport http ai-wakeshift-webhooks https://try.wakeshift.ai/t/{link}/mcp{"mcpServers":{"ai-wakeshift-webhooks":{"type":"http","url":"https://try.wakeshift.ai/t/{link}/mcp"}}}Cursor で開く{"servers":{"ai-wakeshift-webhooks":{"type":"http","url":"https://try.wakeshift.ai/t/{link}/mcp"}}}VS Code で開く{"mcpServers":{"ai-wakeshift-webhooks":{"type":"http","url":"https://try.wakeshift.ai/t/{link}/mcp"}}}{"mcpServers":{"ai-wakeshift-webhooks":{"serverUrl":"https://try.wakeshift.ai/t/{link}/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
Webhook
エージェントを起動する Webhook URL です。リンクを取得して、エージェント(Claude Code、Codex、Cursor、Antigravity、opencode、Copilot CLI、または任意の MCP クライアント)に追加し、監視するよう指示します。すると、Webhook URL への POST(curl、Postman、GitHub、Stripe、Linear、ご自身のアプリからの POST)ごとにエージェントが起動します。Wakeshift は try.wakeshift.ai で実行されます。TypeScript SDK の @wakeshift/sdk を基盤にしています。
仕組み
- ステートレスリンク。 リンクのコードは
TRY_SECRETで署名され、ランダムな Webhook ID と作成日時が指定されています。MCP URL(/t/<code>/mcp)、ページ(/l/<code>)、Webhook URL(/in/<token>、署名チェックごとに 1 つ)、署名シークレットはすべてこのコードから導出されます。何も保存されません。リンクは 7 日間使用されないと期限切れになります。最後に使用された日時はデータベースに保存されます(インスタンスごとに最大 5 分に 1 回書き込まれます)。期限切れになると、Wakeshift に Webhook を忘れるよう依頼します(Webhook ID を指定したforgetUser。その Webhook にとってはアプリのユーザーです)。これにより、そのワークスペース、それを監視していた会話、そのサブスクリプションと配信が削除されます。期限切れの処理では、リンク自身の行を削除するトランザクション内でデータベースにキューを追加し、各インスタンスが 10 分ごとにキューを処理します。失敗した場合は、Wakeshift が完了を返すまでバックオフ(1 分から始まり、最大 6 時間まで倍増)で再試行します。 - SDK のユーザーは Webhook、投稿はイベントです。
webhook.received(引数:Webhook の ID。サブスクライブできるのは、その Webhook 自身の SDK ユーザー、つまりリンクを持つ人だけです)には、投稿内容が含まれます。summary、何が起きたかを示す 1 行、その後に解析済みの本文と送信者を示すヘッダーが続きます。各ツールはattached.events(wake.attachが返すハンドル)でラップされ、Wakeshift の引数はattached.inputsを通して受け取ります。watchはcall.subscribeで呼び出し元の会話をサブスクライブし、unwatchはcall.unsubscribeでサブスクリプションを終了します。ラッパーは各ツールの結果に Wakeshift のブロックを 1 つ追加します。ブロックには、サブスクライブ後に会話をどのように起動するか、保留中のメッセージ、またはそれ以外の場合は Codex スレッドのビーコンが含まれます。呼び出しが失敗すると、その呼び出しが作成したサブスクリプションは終了します。MCP Events に対応するクライアント(ChatGPT)は会話をサブスクライブしません。ブロックには、webhook.receivedを自分でサブスクライブするよう記載されています。投稿はevent.emitになります。wake.attachはsubscribe_events、unsubscribe_events、list_subscriptionsを追加します。 - MCP: セッションを使用する Streamable HTTP で、サインインは不要です(URL 内のコードが認証情報です)。インスタンスにはセッション情報を保存しません。initialize のクライアント名、バージョン、ケイパビリティは
Mcp-Session-Idの下に保存され、各リクエストでは、保存された情報から MCP サーバーを新たに構築し、リクエストが到達したインスタンスで処理します(ステートレスモードの SDK トランスポート。セッション ID はここで検証され、不明な場合や別のリンクのものの場合は 404 を返します)。そのため、セッションは再起動後も維持され、スティッキーセッションは不要です。また、クライアント名とケイパビリティ(Cursor、opencode などをどのように起動するか、自分でサブスクライブするクライアントかどうかを決定します)は、どのインスタンスからも参照できます。再構築されたサーバーは、保存された initialize の情報からgetClientVersionとgetClientCapabilitiesに応答し、ラッパーはそれらを読み取ります。7 日間操作のないセッションは削除されます(クライアントは再度 initialize します)。ツール:watch、unwatch、recent_posts、webhook_info。 - Webhook:
/in/<token>へのPOST、PUT、またはPATCH。本文は最大 64 KB です。イベントのtextは何が起きたかを示します。GitHub の場合(X-GitHub-Eventから)GitHub workflow_run completed: failure on main (tests) in acme/api、Stripe の場合Stripe invoice.payment_failed: in_…, USD 49.00, open (evt_…, test mode)、Linear の場合Linear Issue create: ENG-123 Checkout page 500s、それ以外の場合はPOST to your webhook(空の本文だった場合は(empty body)付き)となります。残りの情報はdataに含まれます。textでは本文を繰り返さないため、小さな投稿ならdataの全体が Monitor の 1 行(480 バイト)に収まります。dataには解析済みの本文(bodyまたはbody_base64)、メソッド、コンテンツタイプ、送信者を示すいくつかのヘッダー(Linear-EventとLinear-Deliveryを含みます。Authorization、Cookie、署名は含みません)、および Stripe と Linear の場合はsource(イベントタイプと ID)が含まれます。再試行は 1 回の公開として扱います。重複判定にはIdempotency-Key、X-GitHub-Delivery、Linear-Delivery、または Stripe イベントのevt_ID を使います。GitHub、Stripe、Linear の URL では、そのサービス独自の ID のみを使います(Idempotency-Keyは署名されないため、取得された配信を新しいキーで再送すると、エージェントが再び起動します)。Stripe URL では、署名済み本文内のevt_ID のみを使います。GETは投稿方法を説明します。上限を 256 KB 超える本文は、読み込まずに接続を切断します。 - 署名チェック: ページのタブにはチェックごとに URL が表示され、それぞれ異なるトークンを持つため、チェック済み URL をオープン URL に変えることはできません。オープン URL は、ユーザーが(下記のとおり)置き換えるまで、それを持つ人なら誰でも引き続き使えます。GitHub の
X-Hub-Signature-256とAuthorization: Bearerには、Webhook ごと、チェックごとに導出したシークレット(try_gh_…、try_bearer_…)を使います。Stripe と Linear では、それぞれ独自のシークレットを作成します。ユーザーがそのシークレットをページに貼り付けると、その URL のトークンに封入されます(TRY_SECRETから導出したキーを使う AES-256-GCM)。保存されるのはこの形式だけです。リンクの期限が切れるまで、URL は Webhook のチェック済み URL として保持されます(下記参照)。Stripe のStripe-Signature(t=…,v1=…、t.bodyの HMAC-SHA256)は 5 分以内でなければなりません。Linear のLinear-Signature(本文の 16 進数形式の HMAC-SHA256)では、webhookTimestampが 1 分以内である必要があります。 - 新しいオープン URL: オープンタブの「新しい URL を取得」(
POST /l/<code>/rotate)はオープン URL を置き換えます。以降、そのトークンには Webhook のオープン URL 世代が含まれ、これはデータベースの Webhook ごとのhooks.open_genに保存されます。世代が異なるオープン URL への投稿やGETは、すべてのインスタンスでただちに 410(replaced)になります。Webhook ID(SDK ユーザーであり、サブスクリプションを持ちます)、リンクと MCP URL、履歴、チェック済み URL はそのまま維持され、ライブビューには URL が変更されたことを示す行が表示されます。依頼できるのはリンクのコードだけです(Webhook URL は別の権限であり、依頼できません)。また、このサイトのページからのみ依頼できます。OriginまたはSec-Fetch-Siteに別のサイトから送信されたことが示されているリクエストは 403 になります。Webhook ごとに 1 時間あたり 10 回までで、それを超えると 429 になります。 - エージェントに通知する URL:
watchとwebhook_infoは、ユーザーが最後に選んだチェック済み URL(開いた GitHub または bearer タブ、作成した Stripe または Linear URL、またはサービスが最後に投稿した URL)を返し、使用するチェックの種類を示します。リンクが有効な間は保持されます。 - 制限(データベースでアトミックにカウントするため、インスタンス間で適用されます。固定ウィンドウは 1 時間および UTC の 1 日です):Webhook の各 URL につき 1 時間あたり 60 件、1 日あたり 500 件の投稿(429 と
Retry-Afterを返します)。これにより、オープン URL を持つ人がチェック済み URL の枠を使い切ることはありません。拒否された投稿(401、413)はカウントされません。再試行はカウントされます(いずれも Wakeshift へのリクエストであるため、同じIdempotency-Keyを再利用しても制限を回避できません)。すべての Webhook を合わせて 1 時間あたり 20,000 件、アドレスごとに 1 時間あたり新規リンク 30 件(IPv6 アドレスは /64 単位。アドレスは 1 時間、HMAC として保持されます)。TRY_PER_HOUR、TRY_PER_DAY、TRY_GLOBAL_PER_HOUR、TRY_LINKS_PER_HOURで変更でき、利用規約とプライバシーポリシーに現在の制限が記載されています。 - 過負荷: 1 インスタンスが同時に処理するリクエストは 256 件までです(そのうち投稿は 4 分の 3 までとし、ページやツール呼び出し用に余裕を残します)。開いているストリームは 900 件までです(ライブビュー、MCP GET、listen ストリーム)。1 つの Webhook につき、ライブビューは最大 20 件、これとは別にエージェントのストリームは 20 件までです。これにより、エージェントがページの接続枠を使い切ることはありません。1 つの MCP セッションにつき GET ストリームは 2 件までです(ライブビューはそれを超えると 429、GET ストリームは 405 になります)。上限を超えた場合や、データベースに接続できない場合、または接続数が上限に達した場合は、
Retry-Afterと簡潔なメッセージを添えて 503 を返します(Webhook は JSON、MCP は JSON-RPC、ページはページ形式)。500 は返しません。データベースの応答が遅くても、リンクのページは履歴なしで表示されます。ライブビューは再試行し、その旨を表示します(下記参照)。公開時の Wakeshift 独自の 429 または 503 は、投稿元にRetry-After付きの 503 として返されます。 - ページのライブビュー は、このサーバーからの SSE(
/l/<code>/live)です。各投稿(受信、拒否、レート制限、投稿内容の冒頭、配信先となった監視中の会話の数)、各 watch と unwatch が表示されます。行はデータベースに保存されます(Webhook ごとに直近 50 件)。Webhook のチャネル(try_<hook>)でのNOTIFYによって、すべてのインスタンスのページに届きます。各インスタンスは、ページを開いている Webhook のみLISTENし、接続が切れて復旧するたびに直近の行を再生します。また、無言で切断されていることを検知できるよう、その接続に 30 秒ごとに ping を送ります。Webhook の拒否された投稿とレート制限された投稿については、署名不正の大量投稿で実際の投稿が押し出されないよう、インスタンスごとに 1 分あたり最大 10 行までです。それ以外は集計され、1 分が経過するかインスタンスが停止すると、各インスタンスがその件数を Webhook の 1 分ごとの行に加算し、ページ上でその行をその場で更新します。すべてのインスタンスの合計を示す行は 1 分に 1 回だけで、各インスタンスが Webhook ごとに最大 1 回書き込みます。書き込みに追いつけないライブビューは切断されます(EventSource が再接続します)。各行にはseqを SSE ID として付与し、ライブビューは最後に受け取った番号より後の行を要求します(?after=<seq>、または EventSource の自動再接続時はLast-Event-ID)。そのため、間が空いても、その間に起きたことが表示されます(直近 50 件の範囲内)。サーバーから拒否された場合(429、503)、EventSource は再接続を諦めます。ページは 2 秒後に再試行し、その後最大 30 秒まで間隔を倍増させます(少しランダム化されます)。接続できると 2 秒に戻り、ページが再表示されたとき、ネットワークが復旧したとき、またはステータスポーリングが応答を受け取ったとき(page.ts のliveConnection)にはただちに再試行します。ページにはwatchの呼び出し元、「sent to N watching conversations」の投稿ごとの表示、エージェントが現在接続されているかどうかと接続方法(stream、hooks、polling)が表示されます。10 秒ごとに/l/<code>/statusをポーリングし、Webhook ID を使って Wakeshift にwebhook.receivedの状態を問い合わせます(読み取り専用のevent.status)。
自分で実行する
-
Wakeshift コンソールで Build → New app を開き、キー(
wst_…)をコピーします。 -
空の Postgres データベースを作成します。Webhooks は起動時にテーブルを作成します(
migrations/)。 -
リポジトリのルートから、SDK、次に Webhooks をビルドします。
(cd third_party/wakeshift-node && npm ci && npm run build) cd webhooks && npm ci && npm run build -
.env.exampleを.envにコピーして値を入力し、実行します。変数 WAKESHIFT_KEY手順 1 のアプリのキー WAKESHIFT_COREWakeshift の URL(デフォルトは https://app.wakeshift.ai)TRY_SECRETリンクに署名します。32 バイト以上のランダムな値を指定してください。変更すると、すべてのリンクが無効になります TRY_DATABASE_URL手順 2 のデータベース。すべてのインスタンスで共有します TRY_DB_POOLインスタンスあたりの接続数(デフォルトは 3)。これに加えて、ライブビューのリッスン用に 1 接続を使用します PUBLIC_URLコピーの公開 URL(デフォルトは http://localhost:$PORT)PORTリッスンするポート(デフォルトは 8380) TRY_PROXY_HOPSX-Forwarded-Forに値を追加する、手前にあるプロキシの数(Google のロードバランサーでは 2)。0 にすると、ソケットのアドレスを使用しますTRY_PER_HOUR,TRY_PER_DAY,TRY_GLOBAL_PER_HOUR,TRY_LINKS_PER_HOURオプション:上記の制限 set -a; . ./.env; set +a npm start -
PUBLIC_URLを開いてリンクを取得し、エージェントのタブに表示されるコマンドを実行します。
テスト
npm run lint
npm test # unit tests; needs WAKESHIFT_TEST_DATABASE_URL, a Postgres URL for a role that can create databases
エンドツーエンドテストと負荷テストでは、Wakeshift サーバーに対して Webhooks を実行するため、Wakeshift 自体のリポジトリ内で実行します。
コントリビュート
このリポジトリは Wakeshift のメインリポジトリから生成されています。プルリクエストを歓迎します。変更はそちらに適用し、結果を公開します。CONTRIBUTING を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。