Microsoft 365 MCP Server for Cloudflare Workers - Provides AI-accessible tools for Office 365 operations including email, calendar, Teams, and contact management via Microsoft Graph API
The server has 11 tools with generally present but uneven quality. All tools have descriptions and input schemas visible in the source code (microsoft-mcp-agent.ts), which is a positive baseline. However, descriptions are terse (averaging ~30-50 chars, well below the 194-char baseline for production tools), lack WHEN-to-use context, and omit error recovery guidance. Parameter descriptions are minimal. Output schemas are not documented. Most tools lack the verb-noun clarity expected by production LLM agents. No tool annotations (readonly, destructive) are present despite 4 destructive tools (sendEmail, createCalendarEvent, sendTeamsMessage, createTeamsMeeting). Error handling is mentioned as present but not visible in the schema excerpts provided, preventing full assessment.
Descriptions are critically sparse (avg 30-50 chars vs 194-char production baseline). All descriptions fail to include WHEN-to-use context, dependencies, or error recovery guidance. E.g. 'Get recent emails' omits: what sorting order? What happens if folder is invalid? When should getEmails vs searchEmails be used?
Output schemas are completely undocumented. No visible specification of what fields are returned, what types they have, or what IDs/references are included for downstream tool chaining. This violates the '100% of A+ tools have documented return types' baseline.
Expand all descriptions to 100-200 characters minimum. Include: WHAT the tool does, WHEN to use it (vs similar tools), any prerequisites, and what the agent should do with the result. E.g. for getEmails: 'Retrieve up to N recent emails from the specified folder (inbox, sent, drafts, etc.). Use this to review communication history or find email IDs for forwarding. Returns headers and preview. For full search across all folders, call searchEmails instead.'
Document output schemas explicitly for every tool. Specify the JSON structure, field types, and, critically, what IDs/references are returned for downstream tool chaining. E.g. getEmails should document that it returns email_id (for forward_email), sender_email, recipients, timestamp.
Add tool annotations: mark sendEmail, createCalendarEvent, sendTeamsMessage, createTeamsMeeting with 'destructiveHint: true' and consider adding confirmationRequired: true. Mark all get_*/list_*/search_* tools with 'readOnlyHint: true'.
Add parameter type suffixes for clarity. Rename 'teamId' → 'team_id', 'channelId' → 'channel_id'. Where opaque IDs are unavoidable, add a companion parameter accepting human-readable names (team_name, channel_name) and resolve inside the tool.
Implement and document error recovery in tool descriptions. E.g. for sendEmail: 'If the recipient is not found, try using searchContacts to find the correct email address. If subject or body is too long, the server will return a specific length violation message; trim and retry.'
Add a confirmation/dry-run pattern for destructive operations. E.g. sendEmail could accept an optional 'draft_mode: true' parameter that logs the action without sending, allowing the agent to preview.
No tool annotations present for destructive operations. sendEmail, createCalendarEvent, sendTeamsMessage, createTeamsMeeting are all write/destructive tools but lack destructiveHint or confirmationRequired guidance. Agents cannot distinguish safe-to-retry reads from irreversible writes.
Parameter descriptions are minimal or missing context. E.g. 'folder' in getEmails defaults to 'inbox' but lacks description of valid folder names, whether custom folders are supported, or error behavior if folder is invalid. 'contentType' in sendEmail has an enum but no guidance on when to use 'text' vs 'html'.
No confirmation step or dry-run pattern for destructive operations. sendEmail, createCalendarEvent, sendTeamsMessage, createTeamsMeeting can modify state irreversibly but provide no way for agents to preview or confirm before execution. Per pattern:confirmation-request, 'Agents make mistakes, a confirm_before_execute pattern prevents catastrophic errors.'
No error recovery guidance in tool descriptions. If sendEmail fails due to invalid recipient, searchEmails returns no results, or getCalendarEvents times out, agents have no documented guidance on how to recover. Per pattern:recovery-guide, 'Error responses must tell the LLM what to do next.'
Tool chaining references not documented. E.g. does getEmails return a message_id that sendEmail can reference? Does searchEmails return attendee IDs for use in createTeamsMeeting? Without documented response schemas including chaining IDs, agents cannot compose tools effectively.
No rate limiting, pagination, or result limits documented. getContacts accepts 'count' up to 100, getEmails/searchEmails up to 50, but no max_results enforcement or pagination guidance is visible.
Parameter naming inconsistency for IDs. getContacts has a 'search' parameter (natural language friendly) but getCalendarEvents, sendTeamsMessage use bare 'teamId', 'channelId' (opaque IDs).
sendTeamsMessagecreateTeamsMeeting
Document pagination and result limits. Update getContacts, getEmails, searchEmails descriptions to state: 'Returns up to N results (default 10-50). If results are truncated, use offset/cursor parameters to fetch next page.' Then add offset and limit/page_size parameters if not already present.
Ensure tool names follow verb_noun convention consistently. 'sendEmail', 'getEmails', 'searchEmails', 'createCalendarEvent' are good; but 'getCalendars', 'getTeams', 'getContacts' are generic. Consider 'listCalendars', 'listTeams', 'listContacts' or 'describeAvailableCalendars' to clarify intent.
Add parameter constraints and examples in descriptions. E.g. for contentType: 'Use "text" for plain text emails, "html" for formatted content with links and images. Default is html.' For folder: 'Valid values: inbox (default), sent, drafts, archive, or any custom folder name you have created.'
Document when to use similar tools. Add to getEmails: 'For keyword-based search across all folders, use searchEmails instead. For retrieving a specific email by ID, call getEmailById (if available).' This guides agent choice and prevents redundant calls.