mcp-server-dotnet-entra-id
A .NET starter for building secure MCP servers integrated with Microsoft Entra ID, tested with Claude AI.
Install / Use
claude mcp add Profility-be -- npx -y github:Profility-be/mcp-server-dotnet-entra-idIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
Development & EngineeringSupported Platforms
Tags
Skill content
View source on GitHubMCP Server using .Net and Microsoft Entra ID
A .NET boilerplate for building secure MCP servers integrated with Microsoft Entra ID.
This project provides a ready-to-use foundation for anyone who wants to quickly set up a Model Context Protocol (MCP) server that’s secured with Microsoft Entra ID (Azure AD). It includes all the core components needed to authenticate users from your organization, manage user identity securely, and expose MCP tools in a trusted enterprise environment.
Out of the box, it’s tested and compatible with Claude AI and ChatGPT, making it the fastest way to get your own Entra-protected MCP server running in minutes.
This project demonstrates how to bridge the authentication gap between MCP clients (Claude AI, ChatGPT) and Microsoft Entra ID, ensuring these systems can work together securely and seamlessly.
A .NET 8.0 example implementation showing how to build an OAuth 2.1 proxy that enables Claude AI to authenticate with Microsoft Entra ID for Model Context Protocol (MCP) servers.
Overview
This project demonstrates how to bridge the authentication gap between Claude AI and Microsoft Entra ID (Azure AD). Claude requires RFC 7591 Dynamic Client Registration, which Entra ID doesn't support. This proxy translates between these incompatible systems while maintaining enterprise security.
Built with the official Model Context Protocol C# SDK - This SDK was a game-changer for implementing MCP servers in .NET, providing strongly-typed interfaces and automatic protocol handling.
┌──────────┐ OAuth 2.1 ┌──────────────────────┐ OAuth 2.0 ┌────────────┐
│ │ (with Dynamic Reg) │ │ (Pre-registered) │ │
│ Claude ├─────────────────────►│ MCP (OAuth) Server ├────────────────────►│ Entra ID │
│ AI │◄─────────────────────┤ (this project) │◄────────────────────┤ │
└──────────┘ └──────────────────────┘ └────────────┘
Key Features
- ✅ Custom Login UI - Branded consent page before Entra ID authentication
- ✅ WhoAmI Tool - Example MCP tool that displays authenticated user information
- ✅ Dynamic Client Registration - Implements RFC 7591 for Claude compatibility
- ✅ Dual PKCE Flows - Secure authentication between all components (RFC 7636)
- ✅ Token Mapping - Opaque external tokens, JWT internal tokens with user claims
- ✅ User Claims Extraction - Name, email, OID, UPN from Entra ID tokens
- ✅ Production Ready - CORS, HTTPS, error handling, structured logging
Screenshots
<p align="center"> <img src="docs/screenshot-login.png" alt="Custom Login Page" width="500"/> <br> <em>OAuth login flow with custom branding before Entra ID authentication</em> </p> *OAuth login flow with custom branding before Entra ID authentication*Tested Platforms
✅ Claude AI - Fully tested and working with Claude Desktop and web interface
✅ ChatGPT - Tested and working; see Troubleshooting for notes about Dynamic Client Registration and persistent client storage requirements.
⚠️ Other MCP Clients - This proxy implements the MCP OAuth specification. While it may work with other MCP clients, it has primarily been tested with Claude AI and ChatGPT. VS Code's MCP integration typically uses direct OAuth with pre-configured client credentials and may not require this proxy
What's Included
MCP Server with OAuth
This project includes a complete MCP server implementation with:
-
WhoAmI Tool - Displays authenticated user information
✅ Authentication Status: Authenticated via Entra ID OAuth 📋 User Information: • Name: John Doe • Email: john.doe@company.com • User ID (OID): b9b8d416-d882-47f9-bb74-445d22ddd735 • UPN: john.doe@company.com -
OAuth Protected Endpoints - All MCP endpoints require valid Bearer tokens
-
User Context - Tools can access authenticated user claims for personalization
OAuth Proxy Components
- Dynamic Client Registration - Accepts Claude's registration requests
- Authorization Flow - Custom login page + Entra ID redirect
- Token Exchange - Maps Entra ID tokens to proxy tokens with correct audience
- Discovery Endpoints - RFC 9728 and RFC 8414 compliant metadata
Quick Start
Prerequisites
- ✅ .NET 8.0 SDK installed
- ✅ Azure subscription with Entra ID tenant
- ✅ Admin access to create App Registrations
- ✅ Visual Studio 2022, VS Code, or Rider
Note: This project uses the official MCP C# SDK which simplifies MCP server implementation significantly.
1. Clone and Build
git clone <your-repo-url>
cd MCP
dotnet build
2. Azure App Registration Setup
-
Go to Azure Portal > Entra ID > App registrations > New registration
-
Configure the app:
- Name:
MCP OAuth Proxy - Supported account types:
Accounts in this organizational directory only - Redirect URI:
Web-https://YOUR-DOMAIN/oauth/callback- For production: Use your deployed URL (e.g.,
https://your-app.azurewebsites.net/oauth/callback) - For DevTunnels: Use your tunnel URL (e.g.,
https://abc123-5248.euw.devtunnels.ms/oauth/callback)
- For production: Use your deployed URL (e.g.,
- Name:
-
After creation, note the following values:
- Application (client) ID
- Directory (tenant) ID
-
Create a client secret:
- Go to Certificates & secrets > New client secret
- Description:
MCP Proxy Secret - Expires: Choose appropriate duration
- Copy the secret value (shown only once)
-
Configure API permissions:
- Go to API permissions > Add a permission
- Select Microsoft Graph > Delegated permissions
- Add:
openid,profile,email,User.Read - Click Grant admin consent
Note:
User.Readis not strictly required for basic authentication, but is commonly used and enables future scenarios where you might need to call Microsoft Graph API (e.g., to fetch user photos, calendar data, etc.). -
Expose an API (for token audience):
- Go to Expose an API > Add a scope
- Application ID URI:
api://YOUR-CLIENT-ID(default is fine) - Scope name:
MCP.Access - Who can consent:
Admins and users - Admin consent display name:
Access MCP Server - Admin consent description:
Allows the application to access MCP tools on your behalf
3. Generate Security Keys
Run the key generation script:
.\GenerateKeys.ps1
Copy the generated values to your configuration.
4. Configure appsettings.json
{
"MCP": {
"ServerUrl": "https://YOUR-DOMAIN"
},
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "YOUR-TENANT-ID",
"ClientId": "YOUR-CLIENT-ID",
"ClientSecret": "YOUR-CLIENT-SECRET",
"Scope": "api://YOUR-CLIENT-ID/MCP.Access"
},
"Jwt": {
"SigningKey": "GENERATED-SIGNING-KEY",
"EncryptionKey": "GENERATED-ENCRYPTION-KEY",
"ExpirationMinutes": "60"
},
"TokenStore": {
"Provider": "InMemory",
"AzureTableStorage": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=YOUR_ACCOUNT;AccountKey=YOUR_KEY;EndpointSuffix=core.windows.net",
"TableName": "TokenMappings"
}
},
"ClientStore": {
"Provider": "InMemory",
"AzureTableStorage": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=YOUR_ACCOUNT;AccountKey=YOUR_KEY;EndpointSuffix=core.windows.net",
"TableName": "ClientRegistrations"
}
}
}
Important:
- Replace
YOUR-DOMAINwith your actual domain (e.g.,https://your-app.azurewebsites.net) - For local development with DevTunnels, use your tunnel URL (e.g.,
https://abc123-5248.euw.devtunnels.ms) - see step 6 below - Replace
YOUR-TENANT-ID,YOUR-CLIENT-ID,YOUR-CLIENT-SECRETwith values from Azure App Registration - Use the keys generated by
GenerateKeys.ps1forSigningKeyandEncryptionKey
Token Storage Options:
InMemory(default) - Uses in-memory storage, suitable for development and single-instance deploymentsAzureTableStorage- Uses Azure Table Storage for persistent, scalable token storage across multiple instances- Configure
ConnectionStringwith your Azure Storage account connection string TableNamedefaults toTokenMappingsif not specified- Automatically creates the table on startup
- Expired tokens (>90 days) are cleaned up on each application restart
- Configure
Client Storage Options:
InMemory(default) - Uses deterministic client IDs (SHA-256 hash), suitable for developmentAzureTableStorage- Uses Azure Table Storage for persistent client registrations- Configure
ConnectionStringwith your Azure Storage account connection string TableNamedefaults toClientRegistrationsif not specified- Uses random GUIDs for client IDs
- Required for ChatGPT - ChatGPT only registers once and expects persistent client IDs
- Configure
5. Run the Server
dotnet run
The server will start at https://localhost:5248 (or your configured port).
6. Local Development with DevTunnels (Optional)
For local testing with Claude AI, you can use Microsoft DevTunnels to expose your local server:
# 1. Install Dev Tunnels CLI (one-time setup)
winget install Microsoft.devtunnel
# 2. Verify installation
devtunnel --version
# 3. Log in (one-time setup for tunnel management)
devtunnel user login
# 4. Create a persistent tunnel with anonymous access
devtunnel create -a
# 5. Map your local HTTPS app on port 5248 to the tunnel
devtunnel port create -p 5248 --protocol https
# 6. Start the tunnel
devtunnel host
After starting the tunnel:
- Use the "Connect via browser:" URL as your
MCP:ServerUrlinappsettings.json - Add this URL as a redirect URI in your Entra ID app registration (
https://YOUR-TUNNEL-URL.devtunnels.ms/oauth/callback) - Use this URL when configuring Claude AI
- The "Inspect network activity:" URL can be used to monitor traffic between Claude and your MCP server
Example DevTunnel URL: https://abc123-5248.euw.devtunnels.ms
7. Configure Claude AI
- Open Claude Desktop or go to claude.ai
- Navigate to Settings > Connections (or equivalent)
- Click Add Integration or Add Custom Connector
- Enter your server URL:
https://YOUR-DOMAIN(or your DevTunnel URL for local testing) - Click Connect
- You'll be redirected to the login page, then Entra ID
- After authentication, you'll see ✅ Connected in Claude
8. Test the Connection
In Claude, try:
Use the WhoAmI tool to show my information
You should see your name, email, and other claims from Entra ID.
Project Structure
MCP/
├── Controllers/
│ ├── OAuthController.cs # OAuth endpoints (authorize, continue, cancel, callback, token, register)
│ └── WellKnownController.cs # Discovery endpoints
├── Services/
│ ├── PkceStateManager.cs # Encrypted state for PKCE flows
│ ├── InMemoryLoginTokenStore.cs # Short-lived login page tokens
│ ├── BrandingProvider.cs # Branding configuration provider
│ ├── ConfigurationHelper.cs # Configuration helper utilities
│ ├── ClientStore/
│ │ ├── AzureTableClientStore.cs # Azure Table Storage client store
│ │ ├── InMemoryClientStore.cs # In-memory client store for development
│ │ └── IClientStore.cs # Client store interface
│ ├── Jwt/
│ │ ├── DefaultClaimProvider.cs # Default JWT claim provider
│ │
Truncated for display — read the full file on GitHub.
Related Skills
momen-cursurrules-prompt-file
40.6kCursor rules for building custom frontends with Momen.app as headless BaaS with GraphQL API, actionflows, AI agents, and Stripe integration.
semiotic-react-dataviz-cursorrules-prompt-file
40.6kCursor rules for Semiotic data visualization library with 30+ chart types, MCP server, and AI-assisted chart generation.
Agent-Reach
73.0kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
ruflo
68.3k🌊 The original agent meta-harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
