This repository captures the hardened deployment of the open-source m365-mcp-server project. The objective is to evolve the experimental Cloudflare Worker into an enterprise-grade agent with clear ingress controls, governed egress, and auditable operations.
Looking for feature-level behaviour, tool definitions, or local development instructions? See the upstream repository documentation:
- Source code mirrors the upstream worker while introducing AI Gateway bindings, hardened environment typings, and security-centric defaults.
- Documentation in this repository focuses exclusively on production-readiness and the transformation steps required to land inside a secured Cloudflare estate.
- Operations material provides deterministic procedures for deployment, validation, logging, and change management.
- Perimeter Enforcement – Protect the worker with Cloudflare Access (SSO, MFA, device posture, service tokens) before any MCP handshake occurs.
- Application Authorisation – Preserve Microsoft OAuth 2.1 + PKCE flows while
storing secrets exclusively through
wrangler secret. - Egress Governance – Route all outbound API calls (Microsoft Graph, LLMs, webhooks) through Cloudflare AI Gateway with metadata for logging and policy enforcement.
- Operational Guardrails – Maintain reproducible deployment, observability, and incident response checklists suitable for regulated environments.
- Auditable Graph Egress – All Microsoft Graph calls run through Cloudflare AI
Gateway with enriched metadata (
userId,userEmail,mcpTool,requestId) and expose the gateway log identifier so investigations can pivot between Workers logs and gateway analytics.
| Area | Description | Reasoning | Cloudflare components | Example lines |
|---|---|---|---|---|
| Worker environment bindings | Drops local testing flags and adds the AI binding plus optional Cloudflare Access headers so runtime configuration is supplied exclusively via secrets. |
Keep production deployments secret-driven and expose Access context to downstream handlers. | AI Gateway, Access, Durable Objects | src/index.ts#L30-L63 |
| Graph client transport | Introduces GatewayMetadata, proxies requests through env.AI.run("dynamic/microsoft-graph-handler", …), and captures aiGatewayLogId after each call. |
Ensure every Microsoft Graph request traverses Cloudflare AI Gateway with audit metadata available for incident response. | AI Gateway | src/microsoft-graph.ts#L66-L639 |
| Durable Object metadata + logging | Builds per-tool metadata from Access/Microsoft identities, forwards it to the Graph client, and logs the resulting gateway correlation ID. | Provide traceability between MCP tool executions, Access identities, and AI Gateway analytics without exposing raw tokens. | Access, AI Gateway, Durable Objects | src/microsoft-mcp-agent.ts#L109-L218 |
| Worker configuration | wrangler.example.toml provides placeholder bindings, mandatory [[ai]] configuration, and explicit instructions for Cloudflare secrets. |
Prevent accidental disclosure of tenant-specific identifiers and guide operators toward Cloudflare secret storage. | AI Gateway, Workers KV | wrangler.example.toml |
| Secret | Purpose | Required | Provisioning |
|---|---|---|---|
MICROSOFT_CLIENT_ID |
Microsoft Entra application (client) ID used during OAuth flows. | ✅ | wrangler secret put MICROSOFT_CLIENT_ID |
MICROSOFT_TENANT_ID |
Microsoft Entra tenant identifier for token endpoints. | ✅ | wrangler secret put MICROSOFT_TENANT_ID |
GRAPH_API_VERSION |
Microsoft Graph API version (e.g., v1.0) used when constructing routes. |
✅ | wrangler secret put GRAPH_API_VERSION |
MICROSOFT_CLIENT_SECRET |
Microsoft Entra application secret used for code/refresh exchanges. Must never live in wrangler.toml or environment variables. |
✅ | wrangler secret put MICROSOFT_CLIENT_SECRET |
ENCRYPTION_KEY |
32-byte hex key for encrypting Durable Object state and OAuth props. | ✅ | wrangler secret put ENCRYPTION_KEY |
COOKIE_ENCRYPTION_KEY |
32-byte hex key for Access approval cookie encryption. | ✅ | wrangler secret put COOKIE_ENCRYPTION_KEY |
COOKIE_SECRET |
HMAC secret for signing Access approval cookies. | ✅ | wrangler secret put COOKIE_SECRET |
AI_GATEWAY_SERVICE_TOKEN |
Service token for AI Gateway if policies require authenticated Worker access. | Optional | wrangler secret put AI_GATEWAY_SERVICE_TOKEN |
OPERATIONS.md– Phase-by-phase migration playbook, secret strategy, validation checklist, and maintenance tasks.TECHNICAL.md– Architectural deep dive covering Access, Durable Objects, AI Gateway invocation patterns, environment contract, and logging strategy.src/– Worker source aligned with the hardened environment.wrangler.toml– Production configuration (AI binding, Durable Object, Access-friendly routes).
- Provision Cloudflare Access – create a self-hosted application guarding
mcp.<domain>and authorise relevant identities (human + automation). - Deploy AI Gateway – create
m365-egress-gateway, enable logging/rate limiting/DLP, and define the required dynamic routes (e.g.,dynamic/microsoft-graph-handler). - Refactor Configuration & Secrets – bind the gateway via
[[ai]], remove[vars], populate the placeholder IDs inwrangler.toml, and push all credentials usingwrangler secret put. - Update Source Code – replace direct
fetchinvocations withenv.AI.run(...), attachgateway.metadata(user identifiers, MCP tool name, correlation IDs), and centralise error handling for Access or gateway denials. - Deploy & Validate – run
wrangler deploy --env production, complete the Access SSO, Microsoft consent, and tool execution flow; confirm AI Gateway/Access telemetry.
flowchart LR
A[Early MCP Worker<br>Direct fetch + inline secrets] --> B[Phase 1<br>Cloudflare Access App]
B --> C[Phase 2<br>MCP Portal + Linked Apps]
C --> D[Phase 3<br>AI Gateway Dynamic Routes]
D --> E[Phase 4<br>Code Refactor<br>env.AI.run + metadata]
E --> F[Phase 5<br>Deploy & Validate<br>Access SSO • Gateway logs]
- Change vs upstream: Access now fronts
/sse, every outbound channel (Graph API, MCP responses, streamed prompts) passes through AI Gateway for inspection/routing/DLP, and Durable Objects logaiGatewayLogIdvalues for audit trails. Upstream timeline: https://github.com/nikolanovoselec/m365-mcp-server/blob/main/README.md#why-did-i-build-this
Around 260 lines of worker code (spread across src/index.ts, src/microsoft-graph.ts, and
src/microsoft-mcp-agent.ts) were adjusted, alongside a handful of Cloudflare console changes, to
turn the open prototype into an enterprise-hardened Microsoft 365 Remote MCP Server. Security controls added:
- Cloudflare Access perimeter –
/ssenow sits behind SSO/MFA/device posture, and Access headers reach the Durable Object for auditing. - Cloudflare AI Gateway egress – Every outbound channel (Graph calls, MCP responses, prompt streaming) flows through dynamic routes with policy enforcement, logging, and DLP.
- Secret lifecycle via wrangler – No credentials in
[vars]; secrets are stored/rotated withwrangler secret put. - Durable Object correlation – Tool executions log the Cloudflare
aiGatewayLogId, linking MCP activity to Gateway telemetry. - Configuration hygiene – Example configs rely on placeholders and current compatibility dates; production
wrangler.tomlconsumes secrets exclusively.
- Cloudflare docs – AI Gateway binding methods
- Cloudflare docs – Universal endpoint
- Cloudflare docs – Dynamic routing
- Cloudflare docs – Access linked apps for MCP servers
- Cloudflare docs – Durable Objects (stateful session management)
- Cloudflare GitHub – AI Gateway MCP server (log tooling & OAuth patterns)
All feature work, tool enhancements, or general documentation improvements should originate in m365-mcp-server. Contributions here should focus on production-hardening, deployment automation, and operational playbooks. When updating source code, keep both repositories in sync to ensure transformation guidance remains accurate.