Skip to main content
Glama
JohnGilligan2

notify-mcp

notify-mcp

E-Mail- und SMS-Zustellung an sich selbst für Example Corp-Mitarbeiter als Entra-authentifizierter Remote-MCP-Server. Dies ist der Sendepfad für die Chief-of-Staff-Einführung von claude.ai: Agenten können dem angemeldeten Benutzer ihre eigenen Inhalte per E-Mail oder SMS senden, und strukturell nichts anderes.

Die Invariante (warum dieser Server existiert)

Agenten, die unvertrauenswürdige Inhalte lesen (eingehende E-Mails, Tickets, Chats), dürfen niemals eine uneingeschränkte Sendefähigkeit besitzen – eine Prompt-Injection könnte sie in einen Exfiltrationskanal verwandeln. Dieser Server löst das konstruktionsbedingt:

  • Empfänger sind keine Tool-Parameter. E-Mails gehen an die UPN des Aufrufers, die aus dem validierten Entra-Token stammt. SMS gehen an das hinterlegte Mobiltelefon des Aufrufers. Ein vollständig kompromittiertes Modell kann ändern, was gesendet wird, niemals wohin.

  • FROM ist gesperrt auf <agent>approver@example.com – der Server kann nicht als Mensch senden, also kann er niemanden impersonieren.

  • Die Resend- und Inteliquent-Schlüssel liegen nur in diesem Container. Benutzer sehen nie einen Schlüssel; sie authentifizieren sich mit ihrem eigenen M365-Login.

  • Stündliche Budgets pro Benutzer + eine Audit-Log-Zeile pro Sendung.

Related MCP server: Mailbuttons MCP Server

Tools

Tool

Was es tut

whoami

Gibt die E-Mail-Adresse und die maskierte Mobilnummer zurück, an die Sendungen zugestellt werden. Testen Sie die Verbindung zuerst damit.

send_email_to_me(subject, body_markdown, agent_name?)

Sendet eine E-Mail an den Aufrufer. agent_name markiert den Absender (alerts → approver@example.com).

send_sms_to_me(message)

Sendet eine SMS an das Mobiltelefon des Aufrufers von der Firmen-DID 13105550100. ≤640 Zeichen.

register_my_mobile(mobile_number)

Startet die SMS-Einrichtung: sendet einen 6-stelligen Code an die Nummer.

confirm_my_mobile(code)

Schließt die Einrichtung ab: verifiziert den Code, speichert die Nummer und sendet dem Benutzer eine Änderungsmitteilung per E-Mail.

Wie der Server weiß, wer Sie sind

Claude → Entra-Anmeldung (das eigene Login des Benutzers) → jeder Tool-Aufruf trägt ein Bearer-JWT → AzureJWTVerifier validiert Signatur/Aussteller/Zielgruppe → preferred_username-Anspruch = der Empfänger. Keine Umgebungsvariablen pro Benutzer, keine Konfiguration; die Identität ist kryptografisch.

Mobilnummern sind nicht im Token enthalten, daher verwendet SMS verifizierte Selbstregistrierung (entwickelt für Mandanten, die kein Entra-mobilePhone befüllen – unserer tut das nicht):

  1. Benutzer (typischerweise während des CoS-Einrichtungsinterviews): „register my mobile 310-555-1212" → der Server sendet einen 6-stelligen Code an diese Nummer.

  2. Benutzer gibt den Code ein → confirm_my_mobile → Nummer wird in /data/sms_directory.json gespeichert, verknüpft mit ihrer UPN + Bestätigungs-E-Mail wird gesendet.

  3. Änderungen sind dann gesperrt (NOTIFY_ALLOW_MOBILE_CHANGE=false): Eine bestätigte Nummer kann nur vom Administrator durch Bearbeiten des Registers geändert werden. Die Code-Verifizierung beweist den Besitz; die Änderungssperre + E-Mail-Benachrichtigung verhindern den Injection-Rebind-Angriff (feindlicher Inhalt, der SMS anderswohin umleitet).

Auflösungsreihenfolge: Registry-Datei (manuelle Einträge sind einfache Zeichenfolgen, selbstregistrierte Einträge sind Objekte) → optionales Entra-mobilePhone über Graph (NOTIFY_GRAPH_LOOKUP_ENABLED=true + -GrantGraphUserRead; unnötig, wenn Selbstregistrierung verwendet wird).

Langlebigkeit der Connector-Sitzung (die Lösung für Trennungen)

Drei Dinge verhindern, dass der Connector „getrennt" anzeigt:

  1. offline_access wird beworben in den Metadaten der geschützten Ressource (NOTIFY_ADVERTISE_OFFLINE_ACCESS=true), sodass die Anmeldung von Claude ein Aktualisierungstoken erhält und die ~60–90 Minuten gültigen Zugriffstokens stillschweigend erneuert.

  2. stateless_http=True – Sitzungen überleben Container-Neubereitstellungen.

  3. NPM-Proxy-Host muss die Timeout-Überschreibungen des Playbooks haben (siehe PORTAINER_DEPLOY.md), damit Leerlauf-Streams nicht nach 60 Sekunden abgeschnitten werden.

Überprüfen Sie außerdem, dass keine Conditional-Access-Richtlinie für Anmeldehäufigkeit diese App abdeckt. Abnahmetest: Verbinden, 2+ Stunden im Leerlauf warten, Container neu bereitstellen, dann whoami aufrufen – keine erneute Authentifizierungsaufforderung sollte erscheinen.

Einrichtung (Playbook-Reihenfolge)

  1. scripts/setup_entra_app.ps1 -TenantId <tenant> (optional -GrantGraphUserRead) – gibt die Server-Umgebungsvariablen und das Connector-Geheimnis aus (geht in die erweiterten Einstellungen des Claude-Connectors, niemals auf den Server).

  2. Bereitstellung über Portainer-Git-Stack – PORTAINER_DEPLOY.md. Empfohlener Host-Port 8093 (zuerst testen; im Playbook-Register dokumentiert).

  3. NPM-Proxy-Host notify-mcp.example.com → der Container; Playbook-Timeouts + Anthropic-IP-Whitelist; LE-Zertifikat vor Aktivierung der Whitelist.

  4. Als benutzerdefinierten Connector der Organisation in claude.ai hinzufügen; Benutzer verbinden sich einmal mit ihrem eigenen M365-Login.

Abnahmetests

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

Dann in Claude, als Gruppenmitglied:

  1. whoami → Ihre eigene E-Mail-Adresse, Mobilnummer „hinterlegt (…1234)" oder ein klarer Fehlschlag.

  2. send_email_to_me → kommt in IHREM Posteingang von notify_ai@ an.

  3. Bitten Sie das Modell, „dies an zu senden" → es muss ablehnen / keine Möglichkeit haben, dem nachzukommen. Wenn dies fehlschlägt, ist es ein P1 – nicht ausrollen.

  4. register_my_mobile mit Ihrer Nummer → Code kommt an → confirm_my_mobile → Bestätigungs-E-Mail kommt an → send_sms_to_me funktioniert. Dann versuchen Sie, eine ANDERE Nummer zu registrieren → muss abgelehnt werden (Änderungssperre).

  5. Der 2-Stunden-Leerlauf- und Neubereitstellungstest von oben.

  6. Ein Nicht-Mitglied verbindet sich → bei der Anmeldung abgelehnt (AADSTS50105).

Lokale Entwicklung

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
    D
    maintenance
    Enables AI agents to send and receive email with enforced security policies, scoped mailboxes, and human approval for external sending.
    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.
    8 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
    192 npm
    MIT