Skip to main content
Glama
notify-mcp

notify-mcp

notify-mcp

Example Corp スタッフ向けの自己宛てメール+SMS配信を、Entra 認証付きリモート MCP サーバーとして実現します。これは claude.ai チーフ・オブ・スタッフ展開における送信経路であり、エージェントはサインイン中のユーザー自身のコンテンツをメールまたはテキストで送信でき、構造的にそれ以外のことはできません。

不変条件(このサーバーが存在する理由)

信頼できないコンテンツ(受信メール、チケット、チャット)を読み取るエージェントは、無制限の送信機能を保持してはなりません。プロンプトインジェクションによって、それがデータ流出経路に変わる可能性があるからです。このサーバーは、その問題を構造的に解決します:

  • 受信者はツールのパラメータではありません。 メールは、検証済みの Entra トークンから取得した呼び出し元の UPN に送信されます。SMS は、記録上の呼び出し元の携帯電話番号に送信されます。完全に侵害されたモデルでも、何を送信するかは変更できますが、どこへ送信するかは変更できません。

  • FROM は <agent>approver@example.com に固定されています。サーバーは人間になりすまして送信できないため、誰にもなりすますことはできません。

  • Resend と Inteliquent のキーは、このコンテナ内にのみ存在します。ユーザーがキーを見ることはなく、各自の M365 ログインで認証します。

  • ユーザーごとの時間あたり予算と、送信ごとの監査ログ行。

Related MCP server: Mailbuttons MCP Server

ツール

ツール

機能

whoami

送信先となるメールアドレスとマスクされた携帯電話番号を返します。まずこれで配線をテストします。

send_email_to_me(subject, body_markdown, agent_name?)

呼び出し元にメールを送信します。agent_name は送信者名を設定します(alerts → approver@example.com)。

send_sms_to_me(message)

会社の DID 13105550100 から呼び出し元の携帯電話番号にテキストを送信します。640 文字以内。

register_my_mobile(mobile_number)

SMS 設定を開始します:その番号に 6 桁のコードをテキスト送信します。

confirm_my_mobile(code)

設定を完了します:コードを検証し、番号を保存し、変更通知メールをユーザーに送信します。

サーバーがあなたを識別する仕組み

Claude → Entra サインイン(ユーザー自身のログイン)→ すべてのツール呼び出しにベアラー JWT が付与 → AzureJWTVerifier が署名/発行者/対象者を検証 → preferred_username クレーム = 受信者。ユーザーごとの環境変数も設定も不要で、ID は暗号的に保証されます。

携帯電話番号はトークンに含まれないため、SMS は検証済み自己登録を使用します(Entra の mobilePhone を設定していないテナント向けに構築されています。当社も未設定です):

  1. ユーザー(通常は CoS セットアップ面談中):「register my mobile 310-555-1212」→ サーバーはその番号に 6 桁のコードをテキスト送信します。

  2. ユーザーがコードを入力 → confirm_my_mobile → 番号が UPN をキーとして /data/sms_directory.json に保存され、確認メールが送信されます。

  3. その後、変更はロックされます(NOTIFY_ALLOW_MOBILE_CHANGE=false):確認済みの番号は、管理者がレジストリを編集することでのみ変更できます。コード検証は所有を証明し、変更ロック+メール通知は、インジェクションによる再バインド攻撃(悪意のあるコンテンツがテキストを別の場所にリダイレクトする)を無効化します。

解決順序:レジストリファイル(手動エントリはプレーン文字列、自己登録エントリはオブジェクト)→ オプションで Graph 経由の Entra mobilePhone(NOTIFY_GRAPH_LOOKUP_ENABLED=true + -GrantGraphUserRead。自己登録を使用している場合は不要)。

コネクタセッションの持続性(切断問題の修正)

コネクタが「切断」と表示されないようにするための 3 つの要素:

  1. offline_access が公開されています(保護リソースメタデータ内、NOTIFY_ADVERTISE_OFFLINE_ACCESS=true)。これにより、Claude のサインインは更新トークンを取得し、約 60〜90 分のアクセストークンを自動的に更新します。

  2. stateless_http=True — セッションはコンテナの再デプロイ後も維持されます。

  3. NPM プロキシホストには、プレイブックのタイムアウト上書き設定が必要です(PORTAINER_DEPLOY.md を参照)。アイドルストリームが 60 秒で切断されないようにします。

また、このアプリをカバーする条件付きアクセスのサインイン頻度ポリシーがないことを確認してください。受け入れテスト:接続し、2 時間以上アイドル状態にして、コンテナを再デプロイし、whoami を呼び出します。再認証プロンプトは表示されないはずです。

セットアップ(プレイブックの順序)

  1. scripts/setup_entra_app.ps1 -TenantId <tenant>(オプションで -GrantGraphUserRead)— サーバーの環境変数値とコネクタシークレットを出力します(シークレットは Claude のコネクタ詳細設定に入力し、サーバーには入れません)。

  2. Portainer Git スタックでデプロイ — PORTAINER_DEPLOY.md を参照。推奨ホストポートは 8093(事前にプローブし、プレイブックレジストリに記録)。

  3. NPM プロキシホスト notify-mcp.example.com → コンテナへ。プレイブックのタイムアウト+Anthropic IP 許可リスト。許可リストを有効にする前に LE 証明書。

  4. claude.ai で組織のカスタムコネクタとして追加。ユーザーは各自の M365 ログインで一度接続します。

受け入れテスト

curl http://<docker-host>:8093/healthz                       # {"status":"ok",...}
curl -s https://notify-mcp.example.com/.well-known/oauth-protected-resource/mcp | jq
#   scopes_supported MUST include the full https://.../mcp/access_as_user scope
#   AND "offline_access"
curl -i https://notify-mcp.example.com/mcp                  # 401 + WWW-Authenticate

次に、Claude でグループメンバーとして:

  1. whoami → 自分のメールアドレス、携帯電話番号「on record (…1234)」または明確な不一致。

  2. send_email_to_me → notify_ai@ から自分の受信トレイに届きます。

  3. モデルに「これを<他の誰か>に送信して」と依頼 → 拒否するか、従う方法がないはずです。これが失敗した場合は P1 — 展開しないでください。

  4. 自分の番号で register_my_mobile → コードが届く → confirm_my_mobile → 確認メールが届く → send_sms_to_me が機能します。次に、別の番号を登録してみる → 拒否されるはずです(変更ロック)。

  5. 上記の 2 時間アイドル+再デプロイテスト。

  6. 非メンバーが接続 → サインイン時に拒否されます(AADSTS50105)。

ローカル開発

pip install -r requirements.txt
MCP_AUTH_ENABLED=false python -m notify_mcp   # Inspector only — tools will
                                              # refuse to send without a token
                                              # identity; NEVER expose auth-off

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to send and receive email with enforced security policies, scoped mailboxes, and human approval for external sending.
    264 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Sovereign autonomous mailbox and identity layer for AI agents, providing persistent email identities, object-level security, OTP/2FA capture, link safety analysis, and event-driven email handling via MCP.
    9 npm
    3
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI agents to send, receive, and reply to email through dedicated thread-aware mailboxes, with sandbox testing and compatibility across MCP clients.
    9
    57 npm
    MIT