ms365-mcp
Click on "Deploy 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., "@ms365-mcpCreate a draft email to Jane about the quarterly report."
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.
ms365-mcp
A Microsoft 365 MCP server sized for small local models.
Most MCP servers are built for frontier models with large context windows, so they expose everything the vendor API offers and let the model sort it out. The reference Microsoft 365 server exposes 326 tools generated from Microsoft's Graph OpenAPI spec.
That does not work for an 8B model at 8k context, where the entire tool list sits in the system prompt and the model starts choosing at random somewhere past twenty-five tools. This server takes the opposite approach:
Fourteen hand-written tools, with a hard ceiling of twenty. The tool list is a budget, not a feature list.
Descriptions written for a small model, not salvaged from API metadata.
Draft-first. Exactly one tool can transmit to another person, it takes a draft id rather than a recipient, and it is annotated destructive.
Every tool declares its own effect through MCP
readOnlyHintanddestructiveHintannotations, so a host can classify it without guessing from the tool's name.
Built for the Edge Harness, and useful to any MCP client.
Status
Feature complete, not yet run against a real account. All fourteen tools are implemented and 171 tests pass, none of which touch the network. What has not happened is the part only a real tenant can prove: a live sign-in and a Graph call that gets answered. See docs/PLAN.md for the ten commits and the reasoning behind each decision.
Scaffold, licence, CI | done |
MCP protocol over stdio | done |
The fourteen-tool surface | done, all fourteen implemented |
Sign-in | done, untested against a live tenant |
Microsoft Graph | done, tested against recorded shapes only |
Retries and circuit breaker | done |
Related MCP server: google-nice-mcp
Seeing the tool surface
--list-tools starts nothing and needs no account, so it answers "what would
a host be offered?" before any of it is wired up:
.venv/bin/python -m ms365_mcp --list-toolsAdd --json for a machine-readable version.
read whoami Return the display name, email address and timezone…
read resolve_person Look up a person by name or partial name and return…
read list_messages List messages in a mail folder, newest first, as se…
write create_draft Create a draft message. This does NOT send anything…
! write send_draft Send a draft that already exists, by its id. This r…
...
14 tools, 6 that change something, 4 marked destructive (!)Handlers are stubs today: a call returns a sentence saying the tool is declared but not implemented. The surface is deliberately fixed before any of it is built, because the tool names, descriptions and effect classes are what a host classifies and a model is prompted against, and those are expensive to change later.
Signing in
Sign-in is the Microsoft device code flow, so there is no redirect URL to host and no secret to store. You need one thing first: the application id of an Azure app registration that has the delegated Graph permissions this server's tools declare.
export MS365_MCP_CLIENT_ID=<your app registration's application id>
export MS365_MCP_TENANT_ID=organizations # 'consumers' for outlook.com
.venv/bin/python -m ms365_mcp --loginThen check it, before wiring anything into a host:
.venv/bin/python -m ms365_mcp --verify-login--verify-login prints the client id, tenant, authority, scopes and cache
location, and if an account is cached it calls Graph once. That last part is
the point. A cached token can look completely healthy and still be refused,
because a work or school tenant can withhold consent for a scope the surface
needs, and that only ever shows up as a 403 on a real request. --logout
forgets the account and removes the cache.
The token cache lives in the operating system's config directory, never in this repository. It is created with mode 0600 rather than written and then made private, since the gap between those two is a window where a refresh token is readable by every account on the machine. It is replaced by an atomic rename, so an interrupted write costs nothing.
Using it from the Edge Harness
The harness launches this server as a subprocess over stdio, so it runs under
its own interpreter and shares no dependencies with the host. That is not
incidental: the harness has a local package called mcp/ and the official SDK
on PyPI is also called mcp, so installing this server into the harness's
virtualenv shadows the harness's own package.
Its registry entry there is ms365-own, and pressing Check in the Agent
Lab run options lists every tool with its effect class. All fourteen classify
as declared, meaning the harness took them from this server's annotations
rather than guessing from tool names, and the entry needs no overrides.
In the harness's default draft mode, send_draft is withheld and the other
thirteen are available, so a run cannot reach a person.
Errors are raised as the SDK's ToolError rather than allowed to propagate.
That is worth knowing if you are writing a handler here: the SDK treats any
other exception as a crash and replaces its message with a generic one, so a
sentence like "No signed-in account, run --login" is discarded before it ever
reaches the model. ToolError is the deliberate-failure channel and its text
survives, while the result is still flagged as an error.
Security
This repository is public and holds no credential of any kind.
Authentication uses the Microsoft device-code flow. The resulting token cache
is written to the operating system's config directory with owner-only
permissions, never into this repository or its working tree. .gitignore
covers token and cache filenames anyway, and a pre-commit hook scans staged
changes for credential-shaped strings, so committing one takes deliberate
effort rather than a slip.
A line ending in # pragma: allowlist secret is skipped by the hook. That
exists so this repository's own tests can contain fake credentials, and it
leaves a marker a reviewer can see in the diff, which --no-verify does not.
Use it only for data that is provably fake.
Development
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest -qEnable the secret-scan hook once per clone:
git config core.hooksPath .githooksLicence
MIT. See LICENSE.
Available Tools
14 toolscancel_eventCancel an eventADestructive
Cancel an event and notify every attendee. This CANNOT be undone. Read the event with get_event first and be sure it is the right one.
| Name | Required | Description | Default |
|---|---|---|---|
| message | No | optional note to attendees | |
| event_id | Yes | id from list_events |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already include destructiveHint=true, but the description adds specific behavioral consequences: every attendee is notified and the action cannot be undone. This tells the agent exactly what destructive means in this context and encourages a verification step. No contradiction with annotations.
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, each carrying distinct information: purpose and effect, irreversibility, and a safety precondition. No wasted words and the most critical information 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?
The tool has only one required parameter, no output schema, and annotations covering safety. The description covers the action, side effects, irreversibility, and a verification step, which is sufficient for an agent to call it correctly. Without an output schema, return-value detail is not required.
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% — both event_id and message have descriptions. The description does not add parameter-level detail beyond the schema, though it reinforces that event_id should be verified via get_event. This meets the baseline for full schema coverage.
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?
The description states a specific action ('Cancel an event') and its immediate effect ('notify every attendee'). This clearly distinguishes it from siblings like update_event, get_event, and create_event, and there is no delete_event competing tool. The title reinforces but does not carry the description.
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?
It gives a concrete precondition: read the event with get_event first and verify it is the right one. This tells the agent when to use the tool and the necessary safety step. It does not explicitly contrast with update_event or state when not to use, but the instruction is clear enough for correct invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_draftDraft a messageA
Create a draft message. This does NOT send anything: it leaves a draft a person can read and change. Get every recipient address from resolve_person first. Returns a draft id, which send_draft takes if the message is later approved.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | recipient addresses from resolve_person | |
| body | Yes | plain text | |
| subject | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses that the operation only leaves a draft, does not transmit anything, can be read and changed later, and returns a draft id. These are non-obvious behaviors that materially affect how an agent plans its work.
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-load the core purpose and non-sending behavior, then give the prerequisite and return-value handoff. No filler or repetition.
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 simple 3-parameter tool with no output schema, the description covers the key context: what is created, what is not done, the prerequisite address resolution, and the returned draft id. It does not cover every possible edge case, but it is sufficient for correct selection and 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?
The schema already documents 'to' as 'recipient addresses from resolve_person' and body as 'plain text'. The description does not add much beyond that, and the subject parameter has no useful schema description and no additional explanation in the description. Parameter semantics are adequate but not expanded.
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?
The description states a specific action ('Create a draft message') and immediately clarifies what it is not: it does NOT send anything, so it cannot be confused with send_draft or reply_draft. This clearly differentiates the tool from its siblings.
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?
It gives an explicit precondition ('Get every recipient address from resolve_person first') and explains the downstream handoff ('send_draft takes if the message is later approved'). This tells an agent exactly when and in what sequence to use the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_eventCreate an eventADestructive
Create a calendar event. If it has attendees, they are invited, which reaches real people, so get their addresses from resolve_person and check the slot with find_free_time first.
| Name | Required | Description | Default |
|---|---|---|---|
| end | Yes | YYYY-MM-DDTHH:MM | |
| start | Yes | YYYY-MM-DDTHH:MM | |
| subject | Yes | ||
| location | No | ||
| attendees | No | addresses from resolve_person |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that attendees are actually invited and that this reaches real people, which is valuable behavioral context beyond the annotations. It does not contradict the openWorldHint or destructiveHint annotations, and it makes the real-world side effect concrete.
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?
Two tight sentences with no wasted words. The most important caveat—inviting real people—is front-loaded, and the required setup steps are placed right after the core purpose.
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, it covers the critical safety and precondition context well. It does not describe the return value or what happens after creation, but the essential usage guidance is present and sufficient 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 coverage is 60%, and the description mainly reinforces the attendees parameter with 'addresses from resolve_person', which is already in the schema. It does add indirect context about start/end by advising a free-time check, but it adds little beyond the schema for subject and location.
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?
The description states 'Create a calendar event' with a specific verb and resource, clearly distinguishing it from sibling tools like update_event and cancel_event. The additional note about inviting attendees makes the scope even clearer.
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 gives explicit preconditions: get attendee addresses from resolve_person and check availability with find_free_time before creating the event. It lacks an explicit 'when not to use' or alternative routing, but the usage context is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_free_timeFind a free slotARead-only
Find open slots of a given length on a date, respecting existing events and working hours. Use this instead of reading the calendar and working out the gaps yourself, which is where arithmetic mistakes turn into double bookings.
| Name | Required | Description | Default |
|---|---|---|---|
| date | Yes | YYYY-MM-DD | |
| minutes | No | how long a slot, default 30 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds behavioral context beyond the schema by noting that the search respects existing events and working hours, which helps the agent understand what influences the returned slots.
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?
Two short, purposeful sentences. The first states the function and constraints; the second explains why to use the tool over manual calculation. No filler or redundant repetition of schema fields.
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 two-parameter read-only tool, the description provides sufficient context to call it correctly: what it finds, what it respects, and why it should be preferred over manual gap calculation. It does not describe the return format, but the absence of an output schema is partly mitigated by the clear 'open slots' result implied in the description.
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 both parameters are already documented plainly: date expects YYYY-MM-DD and minutes has a default of 30. The description's phrase 'given length' only echoes the minutes parameter without adding new semantic detail, so the schema carries the load.
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?
The description names the action ('find'), the resource ('open slots of a given length on a date'), and the constraints ('respecting existing events and working hours'). It also distinguishes itself from the manual approach of reading the calendar, making its purpose easy to separate from sibling calendar tools.
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 explicitly recommends using this tool instead of reading the calendar and computing gaps manually, which gives clear when-to-use guidance and a rationale. It does not name sibling alternatives directly, but the contrast with 'reading the calendar' is enough to orient an agent among the calendar-related siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_eventRead an eventARead-only
Read one calendar event in full, including its body and the response status of each attendee, by the id list_events returned.
| Name | Required | Description | Default |
|---|---|---|---|
| event_id | Yes | id from list_events |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds useful detail about the response contents (body and attendee response status), but does not go further into error or edge cases. This is acceptable given the simple read-only nature.
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, front-loaded sentence that communicates the action, resource, result contents, and ID provenance with no wasted words.
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 one-parameter read-only tool with safety annotations, the description is complete: it names the source of the identifier and the key contents returned. No critical information for invoking it correctly 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%, with event_id already documented as 'id from list_events'. The description repeats this same guidance, so it adds no new semantic value beyond the schema.
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 ('Read'), a specific resource ('one calendar event'), and the distinguishing scope ('in full, including its body and the response status of each attendee'). It clearly differentiates from sibling tools like list_events and get_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?
The description indicates the correct input source ('by the id list_events returned'), which implies the prerequisite workflow of listing events first. It does not explicitly exclude alternatives, but the context is clear for a single-event read.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_messageRead a messageARead-only
Read one message in full, including its body, by the id that list_messages returned. Read the message before replying to it or summarising it; a reply written from the subject line alone invents its own content.
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes | id from list_messages |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds that the full message including its body is returned, which is useful behavioral context. It also explains why reading the full message matters before replying or summarising. No contradiction with annotations exists.
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?
The description is two compact sentences with no filler. The core action is front-loaded in the first sentence, and the second sentence provides essential usage guidance and rationale. Every clause 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?
For a single-parameter read-only tool with readOnlyHint and destructiveHint annotations, the description covers what is returned ('in full, including its body'), where the id comes from, and when to call it. With no output schema, the description sufficiently sets expectations for the response without needing a field-by-field breakdown.
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?
The input schema already documents message_id with the description 'id from list_messages', giving 100% parameter coverage. The description repeats this provenance but does not add format, type nuance, or additional meaning beyond the schema. Baseline 3 is appropriate given high schema coverage.
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?
The description states a specific verb and resource: 'Read one message in full, including its body.' It also distinguishes itself from list_messages by clarifying that this tool retrieves the full body by an id returned from list_messages, and from get_event by focusing on messages. This makes the tool's purpose unambiguous.
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 explicitly instructs when to use the tool: 'Read the message before replying to it or summarising it.' It also establishes the expected workflow by tying message_id to 'list_messages' and warns about the consequence of skipping this step: 'a reply written from the subject line alone invents its own content.' This gives clear context and rationale for use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_eventsList calendar eventsARead-only
List calendar events between two dates, with subject, start, end, location, attendees and id. Dates are YYYY-MM-DD in the account's own timezone. Check the calendar before booking anything, so a new event does not land on top of an existing one.
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | Yes | YYYY-MM-DD, inclusive | |
| start_date | Yes | YYYY-MM-DD |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds useful behavioral detail: the date range filtering, the account timezone handling, and the exact fields that will be returned. This goes beyond the annotations without contradicting them.
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?
The description is three sentences, front-loaded with the primary behavior, then date format, then usage guidance. Every sentence earns its place and there is no unnecessary verbosity.
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 compensates by listing the returned fields. It also covers date format, timezone, and the key usage scenario. It does not mention ordering, pagination, or how to handle a single event, but for a list operation with simple parameters this is reasonably complete.
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 baseline is 3. The description adds meaningful context beyond the schema by noting that dates are YYYY-MM-DD in the account's own timezone, which is not in the schema's parameter descriptions. It also clarifies the inclusive nature of the range through the end_date schema description and the returned fields.
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?
The description clearly states the tool lists calendar events between two dates, identifies the specific resource (calendar events), and enumerates the returned fields (subject, start, end, location, attendees, id). This distinguishes it from related tools like get_event, which targets a single event, and find_free_time, which searches availability.
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 gives clear contextual usage: 'Check the calendar before booking anything, so a new event does not land on top of an existing one.' This implies the tool should be used to avoid conflicts before creating events. It does not explicitly state when not to use it or name alternatives, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_foldersList mail foldersARead-only
List the mail folders on this account with their names and message counts. Use it when a task names a folder you have not seen, rather than guessing that it exists.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark it read-only and non-destructive. The description adds useful behavioral context by stating the scope ('on this account') and the return contents (names and message counts). No contradictions with annotations.
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?
Two sentences, no wasted words: the first states exactly what the tool returns and the second gives a practical usage rule. It is front-loaded and easy to parse.
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 zero-parameter read-only listing tool, this description is complete: it names the output fields, the account scope, and the condition under which an agent should invoke it. No output schema exists, but the described return content is sufficient.
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?
The tool takes zero parameters, so the empty schema fully covers parameter semantics. The description adds the only relevant contextual scope, 'on this account,' which warrants the baseline-4 score.
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?
The description opens with a specific verb and object: 'List the mail folders on this account with their names and message counts.' This clearly identifies the resource and output, and distinguishes it from sibling tools like list_messages or list_events.
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?
It gives a clear trigger: use it when a task names a folder you have not seen, rather than assuming it exists. It does not name specific sibling alternatives or explicit when-not-to-use cases, but the context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_messagesList mailARead-only
List messages in a mail folder, newest first, as sender, subject, date and id. Bodies are not included; use get_message with an id to read one. Defaults to the inbox and to 10 messages.
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | how many, 1 to 50, default 10 | |
| folder | No | inbox, drafts, sentitems or deleteditems, or an id from list_folders. A folder's display name will not work. Defaults to inbox. | |
| search | No | optional words to match |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds meaningful behavioral context: newest-first ordering, body exclusion, and defaults for folder and count. This is useful value beyond the structured annotations.
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?
Two compact sentences front-load the action, resource, and return shape, then give the important body caveat and defaults. There is no filler or unnecessary repetition.
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 supplies the returned fields and the no-body caveat, while the schema covers folder values, search, and top limits. An agent has enough context to call the tool and interpret its results 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 description coverage is 100%, so all three parameters are already documented with defaults and allowed values. The description mostly restates the inbox and 10-message defaults rather than adding new parameter-level meaning.
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?
The description states a specific verb and resource ('List messages in a mail folder'), names the returned fields, and distinguishes itself from get_message by explicitly saying bodies are not included. This is enough for an agent to tell it apart from related mail tools.
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 gives clear guidance for the main alternative: 'Bodies are not included; use get_message with an id to read one.' It also explains the default folder and result count. It does not explicitly contrast with list_folders, but the essential routing decision is covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reply_draftDraft a replyA
Create a draft reply to an existing message, keeping its thread and recipients. Does NOT send. Read the message with get_message first, so the reply answers what was actually asked.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | plain text | |
| reply_all | No | default false | |
| message_id | Yes | the message to reply to |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations mark readOnlyHint=false and destructiveHint=false, so creating a draft is already implied as a mutating but non-destructive operation. The description adds genuinely useful behavior beyond the annotations: it preserves 'thread and recipients,' explicitly states it does not send, and recommends reading the original message first for correctness. This provides valuable behavioral context without contradicting the annotations.
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?
The description is only two sentences, front-loads the primary action, then states the critical caveat ('Does NOT send') and a useful workflow recommendation. Every sentence earns its place with no fluff or repetition.
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 tool with 3 simple parameters, no output schema, and no nested objects, the description covers the essential points: what it does, what it does not do, and the recommended prerequisite. It is complete enough for correct invocation. A minor gap is not explicitly distinguishing reply_draft from the sibling create_draft, but the 'existing message' framing largely handles this.
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 parameters are already documented: message_id is 'the message to reply to,' body is 'plain text,' and reply_all has a default of false. The tool description adds no extra per-parameter detail beyond the schema, so the baseline of 3 is appropriate. The 'keeping its thread and recipients' phrase hints at reply behavior but doesn't add parameter-level semantics.
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?
The description states a specific verb and resource: 'Create a draft reply to an existing message, keeping its thread and recipients.' It also adds the key exclusion 'Does NOT send,' which distinguishes it from send_draft and clarifies its scope relative to generic create_draft.
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 gives clear context: use this when replying to an existing message, and it explicitly warns 'Does NOT send' so agents know not to expect sending to occur. It also gives a concrete pre-step: 'Read the message with get_message first.' However, it does not explicitly name alternative tools like create_draft or send_draft for comparison, so it falls just short of full guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_personFind someone's addressARead-only
Look up a person by name or partial name and return their real email address. ALWAYS use this before addressing a message or inviting someone. Never type an email address you were not given. If this returns more than one person, ask which one rather than picking.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | a name, or part of one |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint/openWorldHint/destructiveHint, and the description adds useful behavioral context: results may contain multiple people, the returned email is a 'real' address, and the agent must not guess addresses. This goes beyond the structured annotations without contradicting them.
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 sentences, each earning its place: the first defines the core operation, the second gives an imperative usage rule, and the third resolves ambiguity. The description is front-loaded and concise with no filler.
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 simple one-parameter read-only lookup with no output schema, the description covers invocation, the return value (email address), and the multi-result scenario. It does not detail the full response structure, but that is not necessary for the tool's stated purpose.
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% and the only parameter 'name' is described as 'a name, or part of one.' The description reiterates this by saying 'by name or partial name,' but it adds no additional semantic detail such as matching rules, case sensitivity, or input constraints. Baseline 3 is appropriate.
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?
The description states a specific action ('Look up a person by name or partial name') and the expected outcome ('return their real email address'). It clearly distinguishes this tool from its siblings, none of which perform person resolution.
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 explicitly states when to use the tool: 'ALWAYS use this before addressing a message or inviting someone.' It also provides a behavioral rule for ambiguous results ('ask which one rather than picking') and a strong safety directive ('Never type an email address you were not given').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_draftSend a draftADestructive
Send a draft that already exists, by its id. This reaches a real person and CANNOT be undone. There is deliberately no way to write and send in one step: create the draft, check it is right, then send it.
| Name | Required | Description | Default |
|---|---|---|---|
| draft_id | Yes | id from create_draft |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (destructiveHint=true, readOnlyHint=false), the description explains the real consequence: it reaches a real person and cannot be undone. It also warns that there is deliberately no combined write-and-send path, which helps the agent plan the multi-step workflow.
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?
Two direct sentences front-load the core action and consequence, then add a brief workflow note. Every sentence earns its place with no padding or repetition.
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 one-parameter, irreversible send operation, the description provides complete context: what is sent, by what identifier, what the consequence is, and the expected workflow. No return value is required because the behavior itself is clearly a fire-and-forget mutation.
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?
The input schema already fully describes the single parameter draft_id as 'id from create_draft', so schema coverage is 100%. The description adds only that the draft must already exist and be sent by id, which is useful but not a significant addition beyond the schema.
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?
The description states a specific verb and resource: send an existing draft identified by its id. It also distinguishes itself from message-creation tools by emphasizing that this is the final send step for an already-created draft.
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?
It clearly tells the agent when to use the tool: after creating and checking a draft, use this to send it. It does not explicitly name alternatives like create_draft or reply_draft, but the workflow description effectively routes the agent away from using this tool for writing or replying.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_eventChange an eventADestructive
Change the time, subject or location of an existing event. Attendees are notified. Only the fields you pass are changed. Read the event with get_event first, so you are not overwriting something you have not seen.
| Name | Required | Description | Default |
|---|---|---|---|
| end | No | YYYY-MM-DDTHH:MM | |
| start | No | YYYY-MM-DDTHH:MM | |
| subject | No | ||
| event_id | Yes | id from list_events | |
| location | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations mark this as destructive and non-read-only; the description adds valuable context by stating that attendees are notified, only passed fields are changed, and reading first avoids overwriting unseen data. This expands on the annotation without contradicting it.
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 sentences with no filler: the action, the side effect, and the critical precondition are each stated in one tight sentence. Every sentence 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?
For a destructive mutation tool with no output schema and moderate complexity, the description covers the essential behaviors: partial updates, attendee notification, and the get_event precondition. It does not describe return values or null-clearing semantics, but those are not strictly required for safe invocation given the other guidance.
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?
The schema documents start/end formats and event_id source, but subject and location descriptions are empty. The description clarifies partial-update semantics by saying only passed fields are changed, which adds real value. However, it does not clarify how passing null interacts with 'only the fields you pass are changed'—whether null clears a field or is ignored—leaving ambiguity.
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?
The description uses a specific verb ('Change') with a concrete resource ('existing event') and enumerates the mutable fields (time, subject, location). This clearly separates it from create_event and cancel_event in the sibling tool list.
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 explicitly instructs the agent to read the event with get_event first, preventing blind overwrites. It implies the tool is for modifying existing events rather than creating or canceling, though it does not explicitly name alternative tools or exclusion conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
whoamiWho am IARead-only
Return the display name, email address and timezone of the signed-in account. Call this when the task says 'me', 'my' or 'I' and you need the actual address, rather than guessing it.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds context by specifying the signed-in account scope and the return fields, which goes beyond what the annotations alone disclose.
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?
Two concise sentences with no filler. The first sentence defines the action and output, and the second provides the practical trigger condition. Every word 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?
For a parameterless tool with no output schema, the description fully covers what the agent needs: what will be returned, who it applies to, and when to call it. No important context 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?
The tool takes zero parameters, so there are no parameter semantics to document. The description correctly focuses on the return value and usage trigger, which is sufficient for a parameterless tool.
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?
The description states a specific action ('Return...') and names the exact resource ('the signed-in account' and its display name, email address, timezone). This clearly distinguishes it from sibling tools like resolve_person or list_messages.
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 explicitly tells the agent when to use this tool: when the task says 'me', 'my', or 'I' and the actual address is needed. It also warns against guessing, giving clear practical guidance, though it does not explicitly name an alternative tool.
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.
14 tool updates
v0.1.0- First observed
cancel_event - First observed
create_draft - First observed
create_event - First observed
find_free_time - First observed
get_event - First observed
get_message - First observed
list_events - First observed
list_folders - First observed
list_messages - First observed
reply_draft - First observed
resolve_person - First observed
send_draft - First observed
update_event - First observed
whoami
TDQS
Scored across 14 tools
Each tool targets a distinct resource and action: identity, people lookup, mail read/draft/send, and calendar read/find/write. The only close pair, create_draft and reply_draft, is clearly separated by new-vs-reply intent.
Almost all tools follow a consistent verb_noun pattern (list_messages, create_draft, cancel_event). The lone exception is whoami, which is a conventional single-word command but breaks the otherwise uniform pattern.
14 tools is a well-scoped size for a mail-plus-calendar server. Each tool covers a necessary step in reading, creating, and sending mail or managing calendar events, with no redundant utilities.
Calendar coverage is complete with list/get/find/create/update/cancel, and mail covers read, draft, reply-draft, and send. Minor gaps such as updating/deleting drafts or searching messages exist, but agents can work around them with the provided tools.
Maintenance
Related MCP Connectors
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Hosted MCP endpoint with realistic fake data for prototyping agents. 12 tools, no setup.
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceA production-ready MCP server that provides secure, delegated access to Microsoft 365 services including Email, SharePoint, OneDrive, and Calendar. It enables AI models to search messages, browse files, manage calendar events, and parse document contents using OAuth 2.1 authentication.MIT
- AlicenseAqualityDmaintenanceA read-only MCP server for Gmail and Drive with only 5 tools, designed to be friendly to small local LLMs by minimizing context usage and simplifying inputs.5MIT
- AlicenseBqualityDmaintenanceLightweight MCP server that enables AI agents to manage Microsoft Outlook email, calendar, and files using PKCE authentication with only a Client ID.46MIT
- AlicenseNot gradedqualityBmaintenanceMCP server that exposes a Microsoft 365 mailbox via the Model Context Protocol, enabling AI assistants to search, read, and download emails and attachments, and optionally send mail.8 npmMIT