A FastMCP server that provides authenticated access to Microsoft Graph API, deployable to Azure App Service using Azure Developer CLI (azd).
This MCP server enables AI assistants to interact with Microsoft 365 services on behalf of users through a secure, token-based authentication flow using Azure AD.
- Azure AD Authentication: Secure OAuth2 authentication with On-Behalf-Of (OBO) flow
- Microsoft Graph Integration: Access user profiles, emails, and other Microsoft 365 resources
- FastMCP Framework: Built on FastMCP for easy MCP server development
- Azure Deployment Ready: Includes complete infrastructure-as-code with Bicep templates
The server exposes the following MCP tools:
get_user_info: Returns information about the authenticated Azure user from the access token claimsgreet_user: Retrieves the user's profile from Microsoft Graph and returns a personalized greetingdisplay_access_token: Returns the user's Graph API access token for direct API callslist_email_messages: Placeholder for email message retrieval (implementation in progress)
The server uses:
- FastMCP with Azure authentication provider for OAuth2 flows
- On-Behalf-Of Flow: Exchanges the MCP connection token for a Microsoft Graph token
- Microsoft Graph SDK: For type-safe Graph API interactions
- Graph Helper: Custom wrapper (
src/graph_helpers/graph.py) for Graph client management
- Client authenticates with Azure AD and gets an access token
- Client connects to MCP server with the access token
- Server validates token using
AzureProvider - For Graph API calls, server uses OBO flow to exchange token for Graph access token
- Server makes authenticated Graph API calls on behalf of the user
- Azure Developer CLI (azd)
- Python 3.12 or higher
- An Azure subscription
- An Azure AD app registration with appropriate Microsoft Graph permissions
Create a .env file or set the following environment variables:
AZURE_CLIENT_ID=<your-azure-ad-app-client-id>
AZURE_CLIENT_SECRET=<your-azure-ad-app-client-secret>
AZURE_TENANT_ID=<your-azure-ad-tenant-id>
AZURE_GRAPH_USER_SCOPES="User.Read Mail.Read" # Space-separated scopesYour Azure AD app registration needs:
-
API Permissions:
- Microsoft Graph > Delegated Permissions >
User.Read - Microsoft Graph > Delegated Permissions >
Mail.Read(if using email features)
- Microsoft Graph > Delegated Permissions >
-
Authentication:
- Configure redirect URIs as needed for your deployment
- Enable "Access tokens" and "ID tokens" in Authentication settings
-
Expose an API:
- Add an Application ID URI (e.g.,
api://<client-id>) - Define scopes (e.g.,
read) that match therequired_scopesinapp.py
- Add an Application ID URI (e.g.,
-
Certificates & secrets:
- Create a client secret and store it securely
- Clone the repository
git clone <your-repo-url>
cd graph_mcp- Install dependencies
pip install -e .-
Configure environment variables in
.env -
Run the server locally
python src/app.pyThe server will start on http://localhost:8000
-
Clone the repo and install AZD
-
Login to your Azure account.
azd auth loginNOTE: if using a government cloud, you will need to configure azd to use that cloud before logging in
azd config set cloud.name AzureUSGovernment
azd auth login- Run the following command to build a deployable copy of your application, provision the template's infrastructure to Azure and also deploy the applciation code to those newly provisioned resources.
azd upNOTE: the first run will prompt you
Enter a unique environment name:This will be used as a prefix for the resource group that will be created to hold all Azure resources. This name should be unique within your Azure subscription.
This command will prompt you for the following information:
Azure Location: The Azure location where your resources will be deployed.Azure Subscription: The Azure Subscription where your resources will be deployed.
NOTE: This may take a while to complete as it executes three commands:
azd package(builds a deployable copy of your application),azd provision(provisions Azure resources), andazd deploy(deploys application code). You will see a progress indicator as it packages, provisions and deploys your application.
- Then make changes to app.py and run
azd deployagain to update your changes.
graph_mcp/
├── src/
│ ├── app.py # Main FastMCP server with authentication
│ ├── requirements.txt # Python dependencies
│ └── graph_helpers/
│ └── graph.py # Microsoft Graph client wrapper
├── infra/
│ ├── main.bicep # Main Bicep infrastructure template
│ ├── main.parameters.json # Infrastructure parameters
│ └── resources.bicep # Azure resources definition
├── azure.yaml # Azure Developer CLI configuration
├── pyproject.toml # Python project configuration
└── README.md
The template uses Azure App Service. You can choose different pricing tiers by editing /infra/resources.bicep:
- Free Tier (F1): Up to 10 apps, limited CPU/RAM - Change line 58 to
"F1" - Basic Tier (B1): Default, suitable for development -
"B1"(current setting) - Developer Tier (D1): Discounted rate for more apps -
"D1"
See the App Service pricing guide for details.
To extend the server with additional Microsoft Graph capabilities:
- Add new tool functions in
src/app.pyusing the@mcp.tool()decorator - Use
get_access_token()to retrieve the authenticated user's token - Call
_get_graph_client(token)to get an authenticated Graph client - Use the Graph SDK methods to interact with Microsoft 365 services
Example:
@mcp.tool()
async def get_calendar_events() -> dict:
"""Get the user's calendar events."""
token = get_access_token()
graph = await _get_graph_client(user_token=token)
# Use graph.user_client.me.calendar.events.get() etc.
...- Store secrets securely (use Azure Key Vault in production)
- Implement proper scope validation for Graph API access
- Use HTTPS for all production deployments
- Follow the principle of least privilege for Graph API permissions
- Regularly rotate client secrets
Authentication Errors: Verify your Azure AD app registration settings and ensure the client ID, secret, and tenant ID are correct.
Graph API Permission Errors: Check that your app registration has the required delegated permissions and admin consent if needed.
OBO Flow Issues: Ensure the identifier_uri in app.py matches your Azure AD app's Application ID URI.
- FastMCP Documentation
- Microsoft Graph Documentation
- Azure Developer CLI Documentation
- Model Context Protocol Specification
See LICENSE file for details.