I have a Claude project set up as a standing assistant — it already holds the context for a task I do on a recurring weekly basis, and I wanted it to act on that context instead of just handing it back to me to act on manually. Two specific asks tripped me up.
Trip point one: I send a particular email every week, and the project already has everything it needs to draft that email. Having it draft the email itself, instead of me copying its output into a new message by hand, seemed like the obvious next step.
Trip point two: the same project processes information that should turn into calendar entries. Again — it already has the context. Having it create the event directly beat me transcribing its output into my calendar every time.
Both of those are writes. And that’s where I found out the Microsoft 365 connector, on my plan, doesn’t do writes at all.
The read-only wall
Anthropic’s Microsoft 365 connector setup docs lay out the connector’s permission model plainly: read and search tools work the same regardless of plan, but write tools — sending mail, managing drafts and calendar events, creating or updating OneDrive/SharePoint files — only activate after a Microsoft Entra admin consents to an updated permission set, and an org enables them under Organization settings → Connectors. That’s an admin surface. Team and Enterprise plans have one. Free, Pro, and Max plans don’t — individual users on those plans connect directly, with no organization settings to toggle anything in. The FAQ on that same page spells out the consequence directly: without an Entra admin granting write scopes, the integration is read-only.
I’m not the only one who ran into this. There’s an open feature request on the claude-code GitHub repo from a Max-plan subscriber asking for the same thing, pointing out that the connector already works and the restriction is a licensing gate, not a technical one — every other prebuilt connector (Asana, Linear, Sentry, Zapier, Cloudflare) is available on Pro and Max, but Microsoft 365 and Slack are carved out for Team/Enterprise only.
So: no self-service path to write access on an individual plan. Confirmed by the docs, confirmed by someone else hitting the same wall, and confirmed the hard way when I went looking for the toggle and it wasn’t there.
What I built instead
sapidus-writeback-mcp is a monorepo of narrow, write-only MCP servers, each self-hosted on Azure Functions in my own Azure subscription and my own Entra tenant. Nothing phones home; nothing is a hosted service I depend on someone else to keep running.
The design premise came out of thinking about what I was actually trying to avoid by not having admin-granted write access in the first place:
- Writes only. Read and search stay with Anthropic’s official connector and are never duplicated here. A server that can’t read your mailbox can’t leak it — that’s half the permission surface gone by construction, not by policy.
- Minimum scopes for the job, nothing else. The first server,
outlook-writeback, requestsMail.ReadWriteandCalendars.ReadWrite. It deliberately does not requestMail.Send. That’s not an oversight — it means the server is structurally incapable of sending mail on my behalf. It can draft; it can’t send. If someone found a way to fully compromise this server, the blast radius stops at “unsent drafts exist that I didn’t write,” which is a very different incident than “email went out.” - Independently deployable, independently revocable. Each server gets its own Entra app registration, resource group, Function App, and Key Vault secrets. Revoking one server’s access never touches another’s. I didn’t want one god-identity with every scope I might ever need bundled together.
The one destructive tool in the first server, delete_event, is two-step on purpose. The first call returns the event details plus an HMAC-signed confirmation token and does nothing else. The actual delete only happens on a second call that echoes the token back, and the token is bound to that specific event ID and expires in five minutes. A client can’t skip the round-trip by minting its own token.
One deliberate non-goal: this doesn’t reimplement read or search. Draft and event IDs are expected to come from the official M365 connector’s read tools in the same conversation — they share a Graph ID space, so there’s no translation layer needed. That’s the boundary that keeps this a narrow writeback layer instead of a second, competing connector.
Where this leaves things
Read access through Anthropic’s connector, scoped writes through something I control end to end, on infrastructure I can audit and kill independently. More setup than I’d have liked — Entra app registration, Azure Functions, Key Vault wiring — but the tradeoff is that “write access to my mailbox” isn’t gated behind a plan tier I can’t self-serve into.
One bug worth flagging if you go this route yourself: Claude’s OAuth token refresh doesn’t reliably work for connectors backed by an external IdP (tracked here). In practice the connector reports “Connected” but forwards an expired token, and you have to reconnect manually. Worth knowing before you’re debugging what looks like an auth failure on your own server
Open source, contributions welcome
sapidus-writeback-mcp is open source. If you’re hitting the same tier-gated wall, feel free to fork it, deploy your own instance, or open an issue or PR if you find a gap in the design above.