Outlook MCP Server
by alopezch21
README.md
# Outlook MCP Server
This server uses Microsoft Entra's OAuth 2.0 On-Behalf-Of flow. The client
application sends an access token issued for this MCP API; the server validates
that token and exchanges it for a delegated Microsoft Graph access token.
## Entra application contract
- Client application ID: `9b544eca-bd87-4849-b7fb-e96c944cdca8`
- MCP/API application ID: `a7e86069-52f5-46b7-9a06-41d411c47410`
- Tenant ID: `46c98d88-e344-4ed4-8496-4ed7712e255d`
- MCP delegated scope: `api://a7e86069-52f5-46b7-9a06-41d411c47410/access_as_user`
- OBO Graph scope: `https://graph.microsoft.com/.default`
The bearer token sent to `/mcp` must be an access token for the MCP API, not
an ID token or a Graph access token. It must contain `access_as_user` in `scp`
and identify the client application in `azp` (v2 token) or `appid` (v1 token).
The MCP application registration must have delegated Microsoft Graph
permissions with admin consent and a confidential-client credential. In
Kubernetes, create the credential separately; never add its value to this
repository:
```powershell
kubectl create secret generic outlook-mcp-entra `
--namespace catalyst-prod `
--from-literal=client-secret='<secret-value>'
```
For local development, copy `.env.example` to `.env`, provide
`ENTRA_CLIENT_SECRET`, and export/load those variables before starting the
server. The production manifest reads the secret from `outlook-mcp-entra`.
A production-ready, forkable template for building MCP (Model Context Protocol) servers that deploy to the Catalyst Kubernetes platform.
This template uses the same proven SDK patterns running in production today (math-mcp-server, hsdes-mcp-server). Copy this folder, fill in your tools, and deploy in under 30 minutes.
Generated servers conform to the Intel IT MCP engineering standard (**IT-MCP-STD-001**): standardized naming, MCP-native tools tagged with `annotations` + governance `_meta`, risk tiers (R0-R3) with runtime enforcement of R2/R3 writes, data-freshness tags, and server-side telemetry (structured JSON logs with a correlation id and gateway-validated caller). A `registry.yaml` manifest records the server for the registry. (The deployed reference servers `math-mcp-server` and `hsdes-mcp-server` predate this convention.)
## Prerequisites
Before using this template, make sure you have:
- **Python 3.12+** installed locally
- **Podman** (for container builds) — [setup guide](../../docs/CATALYST-MCP-DEPLOYMENT-GUIDE.md#2-podman-vm-setup)
- **kubectl** configured with a Catalyst cluster kubeconfig
- **Harbor access** to push images to `amr-registry.caas.intel.com/catalyst/`
See the [full deployment guide](../../docs/CATALYST-MCP-DEPLOYMENT-GUIDE.md) for detailed prerequisites and access setup.
## Quick Start
### 1. Copy the template
```powershell
cp -r templates/mcp-server-template my-new-server
cd my-new-server
```
### 2. Find and replace all customization points
Search for `>>> CUSTOMIZE` across all files and replace the placeholders:
```powershell
# See all customization points
grep -rn "CUSTOMIZE" .
```
At minimum, replace:
- `your-server-name` → your actual server name (e.g., `jira-mcp-server`)
- `API_BASE_URL` → the upstream REST API you're wrapping
- Tool definitions in `server.py` → your actual tools
### 3. Define your tools
Edit `server.py` and replace the example tools (`core.greeting.get`, `core.item.get`, `core.item.update`) with your own. Tools are meaningful actions, not a 1:1 mirror of API endpoints — apply the test "would a user describe this action in natural language?".
1. Add a `types.Tool(...)` entry to the `TOOLS` list with:
- `name` as `<domain>.<capability>.<verb_object>` (the backing system never appears in a tool name)
- `description` + JSON Schema `inputSchema`
- `annotations=types.ToolAnnotations(...)` — map `side_effects` to hints: `none`/`read` => `readOnlyHint=True`, `write_irreversible` => `destructiveHint=True`, `idempotentHint` from `intel.it/idempotent`
- `_meta={...}` Intel governance tags: `risk_tier` (R0-R3), `side_effects`, `idempotent`, `data_classification`, plus (for data tools) `latency_class` / `answer_type` / `source_system`
2. Add a matching `case "<domain>.<capability>.<verb_object>":` block in `call_tool()`
3. Use `_api_request()` for upstream API calls, `_ok()` / `_err()` for responses
4. For R2 (reversible write) tools, require `reason`, `target_identifiers`, `idempotency_key`; for R3 (irreversible) require `reason`, `target_identifiers`, `approval_id`. The dispatcher enforces these before any upstream call and emits an AUDIT log
5. Update `registry.yaml` so the registry record matches the server's tools
### 4. Test locally
```powershell
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/macOS
pip install -r requirements.txt
python server.py
```
Verify the server is running:
```powershell
# Health check
curl http://localhost:8000/health
# List tools (MCP JSON-RPC)
curl -X POST http://localhost:8000/mcp/ ^
-H "Content-Type: application/json" ^
-H "Accept: application/json, text/event-stream" ^
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}"
# Call the greeting tool
curl -X POST http://localhost:8000/mcp/ ^
-H "Content-Type: application/json" ^
-H "Accept: application/json, text/event-stream" ^
-d "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"core.greeting.get\",\"arguments\":{\"name\":\"World\"}}}"
```
### 5. Build the container
```powershell
podman build -t your-server-name:1.0.0 .
```
### 6. Push to Harbor registry
```powershell
podman tag your-server-name:1.0.0 amr-registry.caas.intel.com/catalyst/your-server-name:1.0.0
podman push --tls-verify=false amr-registry.caas.intel.com/catalyst/your-server-name:1.0.0
```
### 7. Deploy to Kubernetes
```powershell
# Set kubeconfig for your cluster
$env:KUBECONFIG = "path/to/kube-configs/amr-its-compute-cluster.yaml"
kubectl apply -f k8s-deploy.yaml
kubectl apply -f ingress.yaml
# Watch pod status
kubectl get pods -n catalyst -l app=your-server-name -w
```
### 8. Verify the deployment
```powershell
curl https://api-suite-dev.catalyst.intel.com/your-server-name/health
```
## Auth Patterns
### No Auth (Default)
The template ships with no authentication — any client with network access can call your tools. This is appropriate for internal demo servers and tools that don't access sensitive APIs.
### Bearer Token Passthrough
If your upstream API requires a user-provided Bearer token (e.g., Intel SSO `id_token` for HSDES, ServiceNow, etc.), enable the auth middleware:
1. **In `server.py`:** Uncomment the `TokenExtractorASGI` class, the `ContextVar`, and the `get_bearer_token()` helper function (clearly marked in the file)
2. **In the ASGI wiring section:** Swap the `Mount` line to use `TokenExtractorASGI`:
```python
# Comment out this line:
# Mount("/mcp", app=session_manager.handle_request),
# Uncomment this line:
Mount("/mcp", app=TokenExtractorASGI(session_manager.handle_request)),
```
3. **In `_api_request()`:** Uncomment the token forwarding lines to attach the Bearer token to upstream requests
See `servers/hsdes-mcp-server/` for a complete working example of this pattern.
## VS Code MCP Client Configuration
### No-auth server
Add to your `.vscode/mcp.json` or VS Code settings:
```json
{
"servers": {
"your-server-name": {
"type": "http",
"url": "https://api-suite-dev.catalyst.intel.com/your-server-name/mcp/"
}
}
}
```
### Auth server (Bearer token)
```json
{
"servers": {
"your-server-name": {
"type": "http",
"url": "https://api-suite-dev.catalyst.intel.com/your-server-name/mcp/",
"headers": {
"Authorization": "Bearer ${input:your_server_token}"
}
}
},
"inputs": [
{
"id": "your_server_token",
"type": "promptString",
"description": "Bearer token (Intel SSO id_token) for your-server-name",
"password": true
}
]
}
```
## File Overview
| File | Purpose |
|------|---------|
| `server.py` | MCP server with tool definitions and ASGI wiring |
| `requirements.txt` | Python dependencies (pinned to tested versions) |
| `Dockerfile` | Multi-stage container build with non-root user |
| `k8s-deploy.yaml` | Kubernetes Deployment + Service |
| `ingress.yaml` | Traefik Ingress + Middleware for external HTTPS access |
| `registry.yaml` | IT-MCP-STD-001 registry manifest (server + tool metadata) |
| `.env.example` | Environment variable reference (copy to `.env`) |
| `.vscode/mcp.json` | VS Code MCP client configuration |
## Full Documentation
For the complete deployment pipeline including Podman VM proxy setup, Harbor authentication, kubeconfig management, and troubleshooting:
**[docs/CATALYST-MCP-DEPLOYMENT-GUIDE.md](../../docs/CATALYST-MCP-DEPLOYMENT-GUIDE.md)**
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues