MCP server
exonaut hosts a Model Context Protocol server inside the API process at /mcp. An agent connected
to it administers Exchange Online through the same REST routes, roles, plan gate, allowlist and
dryRun handling a REST caller gets; the MCP layer adds discovery, bounded results and a
preview-then-apply rule for changes. It ships as v1.2.0, a Pro feature.
What it is
Section titled “What it is”- One endpoint,
POST /mcp, on the API host. Stateless Streamable HTTP (protocol 2026-07-28, with the 2025-11-25initializehandshake served on the same endpoint for older clients). No SSE legacy endpoint, no sessions, no CORS (there are no browser clients). - Eight tools in four families. The names are
exonaut_<verb>_<noun>; every tool is annotated (read-only, idempotent, destructive, open-world) and described within the clients’ limits.
| Family | Tools | What they do |
|---|---|---|
| Discovery | exonaut_status, exonaut_search_entities, exonaut_describe |
what this host is, which entity set a word or cmdlet maps to, what a route takes and needs |
| Read | exonaut_query, exonaut_get |
a collection with OData options, one entity by key |
| Change | exonaut_preview_change, exonaut_apply_change |
a dry run that mints a confirmation token, then the one replay of that exact change |
| Help | exonaut_explain_error |
an error envelope turned into next actions |
The full tool reference, generated from the server’s own tools/list, is in tools.md.
How a call runs
Section titled “How a call runs”MCP client ──bearer──▶ /mcp ──tool──▶ loopback HTTP ──▶ /exchange/v1.0/... ──▶ cmdlet │ │ │ plan gate, write gate │ scope or role, plan gate, allowlist, │ result bounds │ dryRun, FilterPushdown, error envelopeThe tools never call the executor directly. They call the API’s own routes over a loopback
HttpClient with the caller’s bearer forwarded, so one set of checks exists and it is the REST
route’s. The loopback accepts only targets under /exchange/v1.0/, /readyz and /explorer/examples/
and outlasts the cmdlet timeout. A route’s failure comes back as a tool error (isError: true)
carrying the API envelope.
Plans and the write switch
Section titled “Plans and the write switch”| Plan | What the MCP server answers |
|---|---|
| Community | exonaut_status only; every other tool answers PlanRequired |
| Pro | all eight tools; exonaut_apply_change applies Pro-tier routes (per-object writes and mail flow) |
| Enterprise | the same; Enterprise-tier routes (compliance, org config, RBAC, threat policy, Purview) answer RestOnly with the REST path to use |
Writes are off until the host operator sets Mcp:AllowWrites=true (env Mcp__AllowWrites).
Until then exonaut_apply_change answers WritesDisabled; previews still work because a preview
is a dry run.
Authentication
Section titled “Authentication”The MCP endpoint is an OAuth 2.1 protected resource. An unauthenticated call answers
401 with WWW-Authenticate: Bearer resource_metadata="<host>/.well-known/oauth-protected-resource/mcp";
that document names the canonical URL (Mcp:PublicUrl), the Entra v2.0 issuer of the host’s tenant
and the delegated scopes. Clients sign in to Entra; the API validates the token it already validates
for REST (same app registration, same audiences, plus the MCP URL as an audience for clients that
request a token for the resource). Details and the per-client steps are in clients.md;
the threat model is in safety.md.
Configuration
Section titled “Configuration”| Key | Default | Meaning |
|---|---|---|
Mcp:Enabled |
true |
map /mcp at all |
Mcp:AllowWrites |
false |
let exonaut_apply_change replay previewed changes |
Mcp:PublicUrl |
first listening URL + /mcp |
the canonical MCP URL, the OAuth resource identifier; set it in production |
Mcp:MaxTop |
200 |
upper bound of top on exonaut_query (default page 50) |
Mcp:ScopesSupported |
Read |
scopes_supported in the metadata: the sixteen read scopes, or All |
Mcp:AuthorizationServer |
the tenant’s v2.0 issuer | override for the metadata |
Mcp:ScopePrefix |
api://<AzureAd:ClientId> |
prefix of the advertised scopes |
Mcp:ProgressIntervalSeconds |
8 |
how often a waiting tool reports progress |
Mcp:LoopbackBaseUrl |
first listening URL | where the tools call the API back |
What the server does not do
Section titled “What the server does not do”It caches no tenant data (the manifests it reads describe the build, not the tenant). It has no tool that runs an arbitrary cmdlet. It cannot apply a change that was not previewed by the same caller within the last 20 minutes, and it cannot apply Enterprise-tier changes at all.

