outlook-mcp-limited
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@outlook-mcp-limitedSearch my mailbox for invoices from last month and list the senders."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
outlook-mcp-limited
A local Model Context Protocol (MCP) server that gives an AI assistant
(Claude Desktop, Claude Code, Cursor, …) read + draft-only access to one personal Microsoft mailbox
(@live.nl, @outlook.com, @hotmail.com). It can search, list and read mail, list folders, save
attachments to a jailed folder, and create drafts. It cannot send, delete, move or mark mail, and it
never touches calendar, contacts or files.
This is a cut-down fork of xdarkoy/outlook-mcp (MIT). The fork removes six tools and one OAuth scope, and adds two hard-coded allowlists that make the server refuse to start if anyone widens them. See docs/decision-note.md for why this base was chosen.
It runs in two modes: stdio on your own machine (default, 6 tools), or hosted over Streamable HTTP behind a bearer token for cloud agents such as Cursor's Grok Bot (5 tools, no attachment saving). Hosted mode puts your refresh token and your mail content on other people's servers; read docs/hosting.md before you use it.
What it can and cannot do
Allowed (tool) | Forbidden (no tool, and no OAuth scope for it) |
| Send mail ( |
| Send an existing draft |
| Delete mail |
| Move or mark mail |
| Calendar, contacts, OneDrive, shared mailboxes |
| Anything as an application (no client secret, no app-only permissions) |
Related MCP server: mcp-outlook-desktop
Security model
1. The OAuth token cannot send. The server requests exactly four delegated scopes, hard-coded in
src/auth/scopes.ts:
Scope | What Microsoft says it allows | Why we need it |
| Refresh tokens | Sign in once, not every hour. Refresh tokens last 90 days by default [9]. |
| Sign in and read the user's profile | Identify the signed-in account (MSA vs work) |
| "Read user mail" [5] | search, list, read, list folders, save attachments |
| "Create, read, update and delete email in user mailboxes" [5] |
|
Mail.Send is the only permission that lets a token call POST /me/sendMail [6] or
POST /me/messages/{id}/send [7]. It is not requested, so both calls fail with HTTP 403. The consent
screen you see at first login therefore never says "send mail as you". npm run smoke:live proves this
against your real mailbox (see Acceptance checklist).
2. The tool list cannot grow by accident. src/tools/registry.ts holds the
six allowed tool names. At startup main() runs both guards; on any extra, missing or duplicate tool, or
any scope outside the allowlist, the process prints refusing to start and exits 1 before it serves a
single request. The tests in scripts/test-policy.mjs and scripts/test-mail-trust-boundary.mjs pin
both lists a third time.
3. Residual risk you should know about. Mail.ReadWrite also covers update and delete [5]. This
server exposes no tool for that, but the token could do it. Anyone who steals
~/.outlook-mcp/cache.json can read your mail and edit or delete messages until you revoke consent.
Treat that file like a password.
4. Token cache. MSAL writes ~/.outlook-mcp/cache.json (override: OUTLOOK_MCP_CACHE_DIR) with
mode 0600, via atomic write-to-temp-and-rename. No cloud, no keychain, no telemetry. To wipe it:
rm -rf ~/.outlook-mcp5. Revoke. Go to https://microsoft.com/consent, sign in with the mailbox account, open the app and choose Remove these permissions [10]. Then delete the cache as above. Deleting the app registration in Entra also kills every token issued for it.
6. No client secret. The app registration is a public client using the device code flow [2]. Nothing secret is stored in this repo or on disk except the token cache itself.
7. Attachments are jailed. save_attachment only writes inside OUTLOOK_MCP_ALLOWED_DIR
(default ~/Downloads/outlook-mcp/), never overwrites, and rejects path traversal.
8. Hosted mode is locked and stateless. In http mode, initialize, ping and tools/list are
public metadata (tool names and descriptions, nothing else) so a hosting platform can register the
server. Every other request to /mcp must carry Authorization: Bearer <MCP_AUTH_TOKEN> (32+
characters, compared in constant time) and is rate limited (default 60/min). Each request gets a fresh
MCP server; nothing is kept between requests. The signed-in session comes from the
OUTLOOK_MCP_TOKEN_CACHE variable, which you create locally with npm run export-token. Without a
usable MCP_AUTH_TOKEN the server runs locked: mail calls answer 503 and GET /healthz reports
"status":"locked" plus which settings are present (never their values). Full runbook and the risks
you accept: docs/hosting.md.
Quick start (about 30 minutes, once)
Register the app in Microsoft Entra — follow docs/entra-setup.md. You end with an Application (client) ID. Personal accounts only, public client flows on, four delegated permissions, no secret.
Install and build (Node 20 or newer; this repo was built with Node 26):
cd /path/to/outlook-mcp npm install npm run buildSign in once (device code flow; prints a URL and a code):
OUTLOOK_MCP_CLIENT_ID=<your-client-id> npm run loginOpen the URL, enter the code, sign in with
you@live.nl, and read the consent screen: it must list only read/write mail, profile and offline access — not "send mail as you". Accept.Smoke test against the real mailbox:
OUTLOOK_MCP_CLIENT_ID=<your-client-id> npm run smoke:liveExpected: every line
PASS, including the twoAC5 … refusedlines withHTTP 403. The script leaves one draft addressed to yourself in Drafts; check it in Outlook web, then delete it by hand.Connect a client — see docs/wire-up-notes.md. Short version for Claude Desktop (
~/Library/Application Support/Claude/claude_desktop_config.jsonon macOS [13]):{ "mcpServers": { "outlook": { "command": "node", "args": ["/path/to/outlook-mcp/dist/index.js"], "env": { "OUTLOOK_MCP_CLIENT_ID": "<your-client-id>" } } } }
Configuration
Variable | Required | Default | Purpose |
| yes | — | Application (client) ID of your Entra app registration. Not a secret, but keep it out of git. |
| no |
| Authority tenant. |
| no |
| Where |
| no |
| Token cache location. |
| no |
| Hard cap before |
| http mode: yes | — | Shared secret clients must send as |
| http mode: yes | — | Base64 of the local token cache, from |
| no |
| Where http mode listens. Setting |
| no |
| Accepted requests per minute in http mode. |
| no | — | Set to |
Copy .env.example to .env if you prefer a file; nothing in this repo reads .env
automatically, so pass the values through your MCP client's env block or your shell.
Commands
node dist/index.js # MCP stdio server (what your local client launches)
node dist/index.js http # hosted Streamable HTTP server on $PORT (alias: npm run start:http)
node dist/index.js login # one-time device-code sign-in (alias: npm run login)
node dist/index.js export-token # token cache as base64 for hosting (alias: npm run export-token)
node dist/index.js help # help
npm test # build + all offline tests (no account needed)
npm run smoke:live # acceptance checks against the real mailbox (local)
npm run smoke:remote # acceptance checks against a deployed URL (MCP_URL + MCP_AUTH_TOKEN)dist/ is committed on purpose, so a host that only runs npm install && npm start works without a
build step. After changing src/, run npm run build and commit dist/ too (npm run check:dist
fails if you forget).
Acceptance checklist
# | Criterion | How to verify |
AC1 | No |
|
AC2 | No send tool in the MCP tool list |
|
AC3 | Search + read work on real mail |
|
AC4 |
|
|
AC5 | Graph send endpoints refuse this token |
|
AC6 | Non-expert finishes Entra + local run in ≤30 min | Follow Quick start; the runbook has one click per line |
AC7 | Calendar/contact/send tools absent |
|
AC8 |
| This file, |
H1 | Hosted |
|
H2 | Hosted tool list is five tools, no |
|
H3 | Hosted server stays locked (503 on |
|
Troubleshooting
Symptom | Cause / fix |
| "Allow public client flows" is off. Entra → your app → Authentication → Advanced settings → Yes → Save [3]. |
| Wrong authority. Keep |
| Device code rejected for the tenant alias. Try |
| The cache is empty or expired (90 days [9]). Run |
HTTP 403 on | A delegated permission is missing in the app registration, or consent was declined. Re-check API permissions, then |
| Someone edited the scope list or tool registry. That is the guard doing its job. |
Search returns hits from any year despite | Known MSA backend limitation; use |
Claude Desktop shows no tools | Quit and restart the app fully; check |
Development
npm run build # tsc → dist/
npm test # build + scripts/test-*.mjs + offline MCP smoke testTrust boundaries and the rules for changing them are in AGENTS.md. Upstream history and the fork changes are in CHANGELOG.md.
Sources
Configure desktop apps that call web APIs — enable public client flow
Using device code flow in MSAL.NET — Microsoft personal accounts
Managing apps and services connected to our Microsoft Accounts
License
MIT, same as upstream. See LICENSE.
Available Tools
6 toolscreate_draftA
Create a draft email in the user's Drafts folder — NEVER sends. If replyToMessageId is set, the draft is created as a threaded reply; if body is provided it replaces Graph's quoted original so the caller fully controls the outgoing text. Otherwise a new standalone draft is created. The user must review and send manually in Outlook; this server has no ability to send.
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | CC recipients. | |
| to | Yes | Recipient email addresses (To:). | |
| bcc | No | BCC recipients. | |
| body | Yes | Email body. Plain text by default. | |
| subject | Yes | Email subject. | |
| bodyFormat | No | Body format. Default 'text'. | |
| replyToMessageId | No | If set, create the draft as a reply to this message (preserves thread, quotes original). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses that the tool never sends, that sending is manual in Outlook, that body replaces Graph's quoted original, and that the draft lands in Drafts. It omits failure/permission behavior and what happens to existing settings, but the safety profile is unusually well disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and the critical 'NEVER sends' constraint before the conditional detail. Three sentences, each earning its place, though 'Otherwise a new standalone draft is created' is mildly redundant given the opening.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a create tool with no output schema and no annotations, the description covers the important behavioral and branching facts. It stops short of indicating what the call returns (e.g., a draft identifier), which no structured field supplies, but otherwise an agent has enough to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description goes beyond the schema by explaining the semantics of replyToMessageId (threaded reply, quotes original) and the interaction where a provided body overrides that quoted original — meaning that is genuinely additive, not a restatement.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create a draft email in the user's Drafts folder') and immediately constrains scope with 'NEVER sends', making it unmistakably distinct from the read-only siblings (read_email, list_emails, search_emails). An agent can differentiate it from every sibling without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description sets a clear context (composing a draft the user will send manually) and spells out two conditional branches: reply-to threading when replyToMessageId is set, standalone otherwise. It does not name an alternative tool, but no sibling performs a comparable write, so there is little to exclude against.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_emailsA
List emails from a mail folder with optional filters (sender substring, date range, unread-only). Returns a compact JSON array of message summaries. Use read_email with a returned id to fetch full content.
| Name | Required | Description | Default |
|---|---|---|---|
| from | No | Filter: only emails whose sender address STARTS WITH this value (case-sensitive, Graph OData limitation). For a full domain match use 'user@acme.com' or 'acme.com'. For fuzzy / case-insensitive matching use the search_emails tool instead. | |
| limit | No | Maximum number of emails to return. Default 25, max 100. | |
| since | No | Filter: only emails received at or after this ISO-8601 timestamp (e.g. 2026-04-15T00:00:00Z). | |
| until | No | Filter: only emails received strictly before this ISO-8601 timestamp. | |
| folder | No | Mail folder to list. Defaults to 'inbox'. Either a well-known name (inbox, drafts, sentitems, deleteditems, junkemail, archive, outbox, conversationhistory) or a folder ID returned by list_folders. Unknown names produce a 404 from Graph — use list_folders to discover custom folders. | |
| unreadOnly | No | If true, return only unread messages. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses the return shape ('compact JSON array of message summaries'), but omits pagination behavior, permission/auth requirements, and whether an empty folder returns an empty array or an error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the primary action, then filters, then the return format and follow-up call. Every sentence earns its place with no padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter, filter-based list tool with no output schema and no annotations, the description covers purpose, filtering scope, return shape, and the next step in the workflow. Remaining gaps (pagination, auth, empty-result behavior) are modest for a read-only lister.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all six parameters thoroughly (defaults, max, ISO-8601 format, folder names, 404 behavior). The description's paraphrase ('sender substring') is actually looser than the schema's precise 'STARTS WITH' semantics, adding no meaning beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List emails from a mail folder') plus the scope of optional filters, and names the sibling tool (read_email) that handles full content. An agent can distinguish it from read_email and search_emails without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes in the retrieval workflow: use read_email with a returned id to fetch full content, which clarifies that this tool yields summaries, not bodies. It stops short of an explicit when-to-use-this vs search_emails rule (that guidance only lives in the schema for the 'from' parameter).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_foldersA
List mail folders. With no parentFolderId, returns top-level folders. With parentFolderId set, returns immediate child folders (one level deep). Use the returned 'id' as a folder reference for list_emails. For Outlook's standard folders you can also pass their well-known names directly (inbox, drafts, sentitems, deleteditems, junkemail, archive, outbox, conversationhistory) without calling this tool first.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of folders to return. Default 100, max 200. | |
| parentFolderId | No | If set, list the immediate children of this folder (subfolders). If omitted, list top-level folders in the user's mailbox. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden, and it does disclose real behavioral traits: recursion is limited to one level deep, the scoping depends on whether parentFolderId is present, and the 'id' field in the response is the folder reference. It stops short of covering permissions, pagination behavior against the limit parameter, or response shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four compact sentences, front-loaded with the core behavior, then the id-for-list_emails tip, then the well-known-names shortcut. Every sentence carries information; slight redundancy between the descriptions of parentFolderId here and in the schema keeps it from being maximally tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the necessary work of noting that the returned 'id' is the folder reference to reuse, and with no annotations it covers scoping and depth. It does not address the limit parameter's interaction (e.g., truncation of results in large mailboxes), which is the main remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3 and the schema already documents both parameters. The description still adds meaning: it clarifies the depth semantics ('immediate child folders, one level deep') rather than just 'children', and it enumerates the valid well-known folder name values, which the schema does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List mail folders') and immediately splits the behavior by input: no parentFolderId returns top-level folders, parentFolderId returns immediate children. It also distinguishes itself from siblings by naming list_emails as the consumer of the returned id.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent when NOT to call it: Outlook's well-known folder names (inbox, drafts, sentitems, etc.) can be passed directly to other tools without calling list_folders first. This is a genuine routing rule against an alternative path, not just a use-case hint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_emailA
Fetch the full content of one email message by id, plus a list of its attachments (metadata only — use save_attachment to write an attachment to disk). Returns JSON with body as plain text.
| Name | Required | Description | Default |
|---|---|---|---|
| messageId | Yes | The Graph message ID (returned by list_emails or search_emails). | |
| includeBody | No | If true, include the full body (text preferred over HTML). Default true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It usefully discloses output behavior (JSON, body as plain text, attachments returned as metadata only, implying save_attachment is needed to get file bytes), but says nothing about permissions, size/truncation limits, or error behavior for invalid ids.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tightly written sentence with a parenthetical that carries real information (attachment metadata vs. disk write, plain-text body). No filler, and the core action is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description covers the essentials: what is returned, that attachments are metadata-only, and where to go for file content. It is a bit thin on failure modes and whether the body can be omitted via includeBody, but nothing critical is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the messageId provenance ('returned by list_emails or search_emails') and includeBody's default and text-over-HTML preference. The description adds the 'plain text' return hint but no new parameter detail, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Fetch) and resource (one email message) with the identifier (id) and an additional scope note about attachments. It is clearly distinguishable from siblings list_emails and search_emails, which enumerate rather than fetch a single message.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context (a single message, found via an id from list_emails/search_emails per the schema) and routes attachment retrieval to save_attachment, an explicit alternative. It stops short of stating when to prefer this over searching or when not to use it, so it is strong but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_attachmentA
Download one attachment from a message and save it to the local filesystem. Writes are confined to the server's allowed directory (default ~/Downloads/outlook-mcp/). Existing files are never overwritten — the tool appends ' (2)', ' (3)', … to the filename. Returns the absolute path of the saved file.
| Name | Required | Description | Default |
|---|---|---|---|
| messageId | Yes | The Graph message ID that contains the attachment. | |
| attachmentId | Yes | The Graph attachment ID (from read_email's 'attachments' list). | |
| targetFilename | No | Optional filename override. If omitted, the original attachment filename is used. Must be a bare filename — no path separators, no parent traversal. The destination directory is fixed by the server's OUTLOOK_MCP_ALLOWED_DIR setting and is not LLM-controllable. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With zero annotations, the description carries the full behavior burden and handles it well: it discloses the filesystem write side effect, the confinement to the server's allowed directory, the non-overwrite policy with the ' (2)', ' (3)' renaming scheme, and the return value. What is missing is auth/permission requirements and failure modes (oversized attachments, missing IDs).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the action and resource, then side effects, then return value. No filler, and the overwrite-avoidance detail is stated before the return contract where an agent would want it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter mutation tool with no output schema and no annotations, the description covers what an agent needs: the write target directory, the collision-handling rule, and the return value (absolute path). The only omission — error behavior — is minor for this operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% — all three parameters, including the targetFilename constraints and the non-LLM-controllable destination directory, are fully documented in the schema. The description adds only marginal framing ("one attachment", "default ~/Downloads/outlook-mcp/"), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ("Download one attachment from a message and save it to the local filesystem") with clear scope — exactly one attachment per call, written to disk. This is cleanly distinguishable from the read-only siblings (read_email, list_emails, search_emails), which retrieve content but do not persist it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the phrasing (extract an attachment to disk), and the schema notes that attachmentId comes from read_email's attachments list, which hints at the workflow. However, the description itself names no alternatives and states no when-not conditions — e.g. whether it works for inline images or whether read_email is sufficient when you don't need the bytes on disk.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_emailsA
Full-text search across the user's ENTIRE mailbox (all folders, all years). Supports KQL-like operators: 'from:acme.com', 'subject:contract', 'hasAttachment:true', 'body:Pantheon', plus quoted phrases and AND/OR. Works on both personal (hotmail.com / outlook.com) and work/school accounts — the tool picks the correct backend automatically. IMPORTANT: results are ranked by relevance, NOT sorted by date. Date filters like 'received:this-week' are honored on AAD (work/school) but are IGNORED by the personal-account search backend, which returns matches from any time period. If you need strict date filtering, use list_emails (folder-scoped) with since/until instead. Returns a compact JSON array of hits with message IDs usable by read_email.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results. Default 25, max 250. | |
| query | Yes | Full-text search query using Microsoft Graph search syntax. Examples: 'invoice from:acme.com', 'subject:contract received:this week', 'hasAttachment:true Q4 report'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses relevance-based ranking (not date-sorted), that received: filters are honored on AAD but IGNORED on the personal backend, automatic backend selection, and the return shape. These are non-obvious behavioral quirks an agent must know to call correctly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first clause and each sentence carries useful information (operators, account behavior, ranking, alternative). The single dense paragraph of intertwined caveats is slightly heavy but nearly all of it earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description explains the return format (compact JSON array of hits with message IDs usable by read_email), and it covers the query syntax and cross-account pitfalls. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds query semantics beyond the schema: additional operators (hasAttachment:true, body:, quoted phrases, AND/OR) and the critical caveat about date-operator behavior per backend. It does not, however, add anything for the limit parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Full-text search across the user's ENTIRE mailbox') and scopes it explicitly (all folders, all years), which separates it from the folder-scoped list_emails sibling. An agent can identify the tool's job without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative ('use list_emails (folder-scoped) with since/until') and the exact condition that selects it (need for strict date filtering). It also clarifies cross-account behavior so the agent knows when results may be date-unreliable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v0.4.2- First observed
create_draft - First observed
list_emails - First observed
list_folders - First observed
read_email - First observed
save_attachment - First observed
search_emails
TDQS
Scored across 6 tools
Each tool has a clearly distinct purpose: reading, listing, searching, folder browsing, downloading attachments, and drafting. Descriptions explicitly clarify boundaries, such as search_emails vs list_emails for date filtering, and save_attachment being separated from read_email's metadata-only attachment list.
All tools follow a consistent verb_noun snake_case pattern: read_email, list_emails, search_emails, list_folders, save_attachment, create_draft. No deviations or mixed conventions.
Six tools provide a focused, well-scoped set for a read-oriented email MCP server. Each tool earns its place, and the count is appropriate given the deliberate limitation of not sending emails.
The surface covers reading, listing, searching, folder navigation, attachment saving, and draft creation, but lacks delete, move, mark-as-read, or reply-draft updates. These are reasonable omissions for a limited server, but agents may hit dead ends for basic mailbox management.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Read email/chat conversations, messages, contacts and teams; draft, send and update threads.
- PO6 MailboxOAuthcom.po6
Give AI agents secure access to your email via private aliases with dedicated mailbox storage.
Connect any mailbox to Claude, ChatGPT & AI: read, send, reply, schedule & search emails.
Read, send, file and search email in any Gmail, Microsoft 365 or IMAP mailbox, plus its calendar.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides programmatic access to Microsoft Outlook mailboxes, enabling AI assistants to search, analyze, and extract insights from emails in personal and shared mailboxes.-
- AlicenseAqualityBmaintenanceEnables AI assistants to securely read, search, draft, and send Outlook emails, manage calendar events, and access mailbox folders through a local MAPI connection to Windows Outlook, with human-in-the-loop safeguards.91MIT
- AlicenseBqualityBmaintenanceEnables controlled Microsoft 365 mail workflows including search, read, thread, attachment, and managed draft operations through Microsoft Graph, without sending or modifying messages.9MIT
- AlicenseNot gradedqualityAmaintenanceEnables MCP-compatible AI assistants to securely search multiple mailboxes, reconstruct email threads, and inspect attachments through read-only tools without altering mailbox state.Apache 2.0