Ein Entwickler hat auf LinkedIn seinen MCP-Server für Microsoft 365 vorgestellt: .NET 10, ein getrennter API-Server für Microsoft Graph, Entra ID mit eigener OAuth-Fassade, Terraform und GitHub Actions. Der Code ist nicht öffentlich. Dieser Artikel erklärt die Bausteine mit den offiziellen Quellen: was die MCP-Spezifikation verlangt, welche Graph-Schnittstellen Service Health, Message Center und Nutzungsberichte liefern, warum Entra ID eine Sonderbehandlung braucht und welche Sicherheitsregeln für so einen Server gelten.

Elf Werkzeuge und ein Katalog mit 92 Berichten: So beschreibt ein Entwickler auf LinkedIn seinen MCP-Server für Microsoft 365. Damit sollen Claude, ChatGPT und Copilot Studio aktuelle Daten aus dem eigenen Tenant abfragen. Der Code ist nicht öffentlich, die Bausteine dahinter sind es. Ich habe sie in den Primärquellen nachgeschlagen.
Das Wichtigste in Kürze
- Ein Server bedient mehrere Assistenten. Claude, ChatGPT und Copilot Studio binden entfernte MCP-Server über Streamable HTTP an.
- Die Daten kommen aus Microsoft Graph. Service Health, Message Center und Nutzungsberichte haben eigene Leserechte, die ein Administrator freigibt.
- Die Anmeldung ist der heikle Teil. Entra ID kennt keine dynamische Registrierung von Clients, deshalb braucht es eine feste Client-ID oder eine Fassade.
- .NET 10 wird bis November 2028 gepflegt. Die Version ist ein Long-Term-Support-Release von 2025.
Der Aufbau aus dem Beitrag
Der Beitrag beschreibt eine Kette aus vier Gliedern. Das Sprachmodell spricht mit dem MCP-Server, dieser mit einem eigenen API-Server, und erst der greift auf Microsoft Graph zu.
| Glied | Aufgabe | Technik laut Beitrag |
|---|---|---|
| Sprachmodell | stellt Fragen, wertet aus | Claude, ChatGPT, Copilot Studio |
| MCP-Server | bietet Werkzeuge an, prüft die Anmeldung | .NET 10, ASP.NET Core, Streamable HTTP |
| API-Server | ruft Graph mit eigenen Rechten ab | Managed Identity, Key Vault |
| Microsoft Graph | liefert die Tenant-Daten | Service Health, Message Center, Berichte |
Angaben aus dem LinkedIn-Beitrag. Ein öffentliches Repository dazu habe ich nicht gefunden, die Zahlen lassen sich deshalb nicht prüfen.
Dabei trennt die Kette zwei Dinge sauber: Wer mit dem Sprachmodell redet, bekommt nie die Graph-Rechte zu sehen. Diese Trennung verlangt die MCP-Spezifikation sogar, wie weiter unten deutlich wird.
Was MCP verlangt
MCP steht für Model Context Protocol. Es legt fest, wie ein Assistent Werkzeuge auf einem Server findet und aufruft. Die aktuelle Fassung der Spezifikation stammt vom 28. Juli 2026.
Seither ist das Protokoll zustandslos. Den früheren Handshake zum Start einer Sitzung gibt es nicht mehr, und auch keine Sitzungskennung. Ein neuer Aufruf server/discover verrät, was er kann.
Der Transport heisst Streamable HTTP. Er löste 2025 die ältere Variante mit Server-Sent Events ab. Heute hat ein Server genau einen Endpunkt, etwa /mcp, und jede Nachricht ist ein eigener POST-Aufruf. Die Antwort kommt als JSON oder als kurzer Datenstrom nur für diese Anfrage. Zudem muss er den Origin-Kopf prüfen, damit fremde Webseiten ihn nicht über DNS-Rebinding erreichen.
Für .NET gibt es ein offizielles SDK, das in Zusammenarbeit mit Microsoft gepflegt wird. Die Fassung 2.0 erschien am selben Tag wie die neue Spezifikation. Ein geschützter Server ist damit wenige Zeilen lang:
builder.Services.AddMcpServer()
.WithTools<ServiceHealthTools>()
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateless);
app.MapMcp().RequireAuthorization();
So werden Methoden mit [McpServerTool] zu Werkzeugen, die jeder MCP-Client sieht. Wie das im Alltag aussieht, habe ich im Artikel über KI-Monitoring mit Claude MCP beschrieben.
Microsoft Graph als Datenquelle
Drei Bereiche von Microsoft Graph decken ab, was der Beitrag nennt. Jeder braucht ein eigenes Recht, das ein Administrator freigibt.
- Service Health und Störungen:
/admin/serviceAnnouncement/healthOverviewsund/issues, freigegeben überServiceHealth.Read.All. - Message Center:
…/messagesim selben Bereich, mitServiceMessage.Read.All. - Nutzungsberichte für Teams, SharePoint, OneDrive und weitere Dienste: dafür steht
Reports.Read.All, die Zeiträume reichen von 7 bis 180 Tagen.
Dazu kommen seit kurzem vier Berichte zu Microsoft 365 Copilot unter /copilot/reports/. Sie zählen nur Personen mit Copilot-Lizenz. Ein Abruf sieht so aus:
GET https://graph.microsoft.com/v1.0/reports/getTeamsUserActivityUserDetail(period='D30')
Authorization: Bearer <Token des API-Servers>
Allerdings liefert die stabile Fassung v1.0 diese Berichte als CSV-Datei. JSON gibt es nur in der Beta-Schnittstelle. Ein Server, der Sprachmodelle füttert, muss also umwandeln oder bewusst auf Beta setzen.
Zudem kann der Administrator Namen in allen Berichten verschleiern. Die Einstellung heisst displayConcealedNames. Für Auswertungen über Schulungsbedarf reicht das oft, und es schützt die Mitarbeitenden.
Zwei Werkzeuge statt 92
Die Methodenliste von reportRoot in Graph v1.0 zählt 75 Funktionen, mit den Copilot-Berichten sind es 79. Die 92 aus dem Beitrag sind mit Beta-Funktionen denkbar, nachzählen konnte ich sie nicht.
Spannender ist der Entwurf dahinter. Statt jeden Bericht als eigenes Werkzeug anzubieten, gibt es zwei: eines listet die verfügbaren Berichte, das andere holt einen davon. Damit bleibt die Werkzeugliste kurz, die das Sprachmodell bei jeder Anfrage mitliest. Neue Berichte kommen über den Katalog dazu, ohne dass sich die Schnittstelle ändert.
Die Anmeldung mit Entra ID
Die MCP-Spezifikation baut auf OAuth 2.1 auf. Der MCP-Dienst tritt dabei als Resource Server auf und veröffentlicht, welcher Anmeldedienst für ihn zuständig ist. Clients müssen PKCE mit S256 nutzen und den Parameter resource mitschicken, damit das Token nur für genau diesen Dienst gilt.
Für die Registrierung der Clients nennt die Spezifikation drei Wege: vorab eingetragen, über ein Client-ID-Metadatendokument oder dynamisch. Die dynamische Registrierung gilt seit Juli 2026 als veraltet.
Genau hier liegt der Haken. Microsoft schreibt selbst, dass Entra ID keine dynamische Registrierung anbietet. Ein Client braucht also eine vorher eingetragene Client-ID. Dazu verlangt Entra beim Parameter resource Tokens der Version 2 und als Application ID URI exakt dessen Adresse.
Deshalb baute der Entwickler eine eigene OAuth-Fassade. Sie spricht mit den Clients so, wie MCP es erwartet, und mit Entra so, wie Entra es kann. Inzwischen bieten Claude, ChatGPT und Copilot Studio aber auch das Eintragen einer festen Client-ID an. Für diese drei Clients geht es also auch ohne Fassade.
Wer trotzdem eine Fassade baut, betreibt laut Spezifikation einen „MCP Proxy Server“ und hat Pflichten. Er muss für jeden Client eine eigene Zustimmung einholen, Rücksprungadressen exakt prüfen und Cookies streng setzen. Sonst droht ein Confused-Deputy-Angriff: Ein fremder Client nutzt die Zustimmung, die eigentlich einem anderen galt.
Graph-Zugriff ohne Passwort
Der API-Server ruft Graph mit einer Managed Identity auf. Azure verwaltet diese Identität selbst, im Code steht kein Geheimnis. Die Graph-Rechte bekommt sie als App-Rolle.
Dafür gibt es keinen Knopf im Entra-Portal. Microsoft dokumentiert die Zuweisung per PowerShell oder Azure CLI, und sie wirkt wegen zwischengespeicherter Tokens erst mit Verzögerung. Für die übrigen Geheimnisse dient Azure Key Vault mit der Rolle „Key Vault Secrets User“.
Dabei passt die Trennung in zwei Server zu einer harten Regel der Spezifikation. Ein MCP-Server darf das Token des Clients nicht an andere Dienste weiterreichen. Für Graph braucht er ein eigenes Token, zum Beispiel aus der Managed Identity.
Terraform und GitHub Actions
Infrastruktur und Entra-Einträge lassen sich als Code beschreiben. Der Terraform-Provider azurerm legt die Azure-Ressourcen an, azuread die App-Registrierungen. Die Graph-Rolle für die Managed Identity setzt die Ressource azuread_app_role_assignment, damit entfällt auch das Skript von oben.
Das Deployment läuft über GitHub Actions mit OpenID Connect. Azure vertraut dem Workflow über eine Federated Identity Credential, ein gespeichertes Passwort gibt es nicht:
permissions:
id-token: write
steps:
- uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
Wo die Grenzen liegen
Ein Sprachmodell mit echten Tenant-Daten ist nützlich, etwa für ein Briefing zu aktuellen Störungen oder für Schulungsthemen aus den Teams-Zahlen. Trotzdem bleibt es ein Sprachmodell.
Zum einen gelangt fremder Text in seinen Kontext. Meldungen aus dem Message Center und Beschreibungen von Störungen stammen von Microsoft, nicht vom eigenen Team. Die Spezifikation empfiehlt deshalb, Ergebnisse von Werkzeugen zu prüfen, bevor sie zum Modell gehen, und einen Menschen über Aufrufe entscheiden zu lassen.
Zum anderen gilt das Prinzip der geringsten Rechte. Der Dienst sollte nur lesen und nur die drei genannten Freigaben haben. Was das Modell daraus folgert, ist eine Deutung und muss als solche erkennbar bleiben.
Fazit
Ein MCP-Server für Microsoft 365 ist mit .NET 10 und dem offiziellen SDK schnell gebaut. Die eigentliche Arbeit steckt in der Anmeldung über Entra ID und in sauber getrennten Rechten. Der Report-Katalog mit zwei Werkzeugen ist ein Entwurf, den ich mir merke. Wer so etwas baut, sollte zuerst die Sicherheitsregeln der Spezifikation lesen.
Quellen: MCP-Spezifikation 2026-07-28, Streamable HTTP, MCP-Autorisierung, MCP Security Best Practices, C#-SDK für MCP, .NET-Supportrichtlinie, Graph Service Communications API, Graph reportRoot, Copilot-Berichte in Graph, Berichtseinstellungen, App Service: MCP-Authentifizierung, MCP-Server mit Entra ID absichern, Managed Identity und Graph, Key Vault RBAC, azuread_app_role_assignment, GitHub Actions mit OIDC nach Azure, Claude: Authentifizierung für Connectors, OpenAI Apps SDK: Authentifizierung, Copilot Studio: MCP-Server anbinden. Foto: bsdrouin / Pixabay. Stand: 11. Oktober 2026.
Recherche und Entwurf KI-gestützt, geprüft und freigegeben von Andreas Brauckmann · So arbeitet die Redaktion
Änderungshistorie
- — Artikel veröffentlicht.