UNPKG

@softeria/ms-365-mcp-server

Version:

A Model Context Protocol (MCP) server for interacting with Microsoft 365 and Office services through the Graph API

918 lines 117 kB
[ { "pathPattern": "/$batch", "method": "post", "toolName": "graph-batch", "scopes": [], "llmTip": "Combine up to 20 Graph requests into a single HTTP call. Body: { requests: [{ id: '1', method: 'GET'|'POST'|'PATCH'|'DELETE', url: '/me/messages?$top=5', headers?: {...}, body?: {...}, dependsOn?: ['1'] }, ...] }. Returns { responses: [{ id, status, body, headers }] } in arbitrary order — match by id. Use cases: (1) parallelize many small reads (e.g. fetch 15 mail messages by id in one round-trip); (2) sequence dependent writes via dependsOn; (3) batch many Excel range writes into one call to dramatically reduce latency on large workbook builds. Note: each sub-request URL is relative to the Graph version root (/me/..., /drives/..., NOT https://graph.microsoft.com/v1.0/...)." }, { "pathPattern": "/me/messages", "method": "get", "toolName": "list-mail-messages", "scopes": ["Mail.Read"], "llmTip": "CRITICAL: When searching emails, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'from:', 'subject:', 'body:', 'to:', 'cc:', 'bcc:', 'attachment:', 'hasAttachments:', 'importance:', 'received:', 'sent:'. Examples: $search=\"from:john@example.com\" | $search=\"subject:meeting AND hasAttachments:true\" | $search=\"body:urgent AND received>=2024-01-01\" | $search=\"from:john AND importance:high\". Remember: ALWAYS wrap the entire search expression in double quotes! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter IMPORTANT: Always use $select to limit returned fields and reduce response size. Recommended default: $select=id,subject,from,toRecipients,receivedDateTime,bodyPreview,isRead,hasAttachments. Use bodyPreview instead of body for listings. To read the full email body, use get-mail-message with the specific message id." }, { "pathPattern": "/me/mailFolders", "method": "get", "toolName": "list-mail-folders", "scopes": ["Mail.Read"] }, { "pathPattern": "/me/mailFolders/{mailFolder-id}/childFolders", "method": "get", "toolName": "list-mail-child-folders", "scopes": ["Mail.Read"] }, { "pathPattern": "/me/mailFolders", "method": "post", "toolName": "create-mail-folder", "scopes": ["Mail.ReadWrite"], "llmTip": "Creates a top-level mail folder. Use create-mail-child-folder to create a subfolder inside an existing folder. Use list-mail-folders to find existing folder IDs." }, { "pathPattern": "/me/mailFolders/{mailFolder-id}/childFolders", "method": "post", "toolName": "create-mail-child-folder", "scopes": ["Mail.ReadWrite"], "llmTip": "Creates a subfolder inside an existing mail folder. Use list-mail-folders or list-mail-child-folders to find the parent folder ID." }, { "pathPattern": "/me/mailFolders/{mailFolder-id}", "method": "patch", "toolName": "update-mail-folder", "scopes": ["Mail.ReadWrite"], "llmTip": "Renames a mail folder by updating its displayName. Use list-mail-folders to find the folder ID." }, { "pathPattern": "/me/mailFolders/{mailFolder-id}", "method": "delete", "toolName": "delete-mail-folder", "scopes": ["Mail.ReadWrite"], "llmTip": "Deletes a mail folder and all its contents. This action is irreversible. Use list-mail-folders to find the folder ID." }, { "pathPattern": "/me/mailFolders/{mailFolder-id}/messages", "method": "get", "toolName": "list-mail-folder-messages", "scopes": ["Mail.Read"], "llmTip": "CRITICAL: When searching emails, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'from:', 'subject:', 'body:', 'to:', 'cc:', 'bcc:', 'attachment:', 'hasAttachments:', 'importance:', 'received:', 'sent:'. Examples: $search=\"from:john@example.com\" | $search=\"subject:meeting AND hasAttachments:true\" | $search=\"body:urgent AND received>=2024-01-01\" | $search=\"from:alice AND importance:high\". Remember: ALWAYS wrap the entire search expression in double quotes! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter IMPORTANT: Always use $select to limit returned fields and reduce response size. Recommended default: $select=id,subject,from,toRecipients,receivedDateTime,bodyPreview,isRead,hasAttachments. Use bodyPreview instead of body for listings. To read the full email body, use get-mail-message with the specific message id." }, { "pathPattern": "/me/messages/{message-id}", "method": "get", "toolName": "get-mail-message", "scopes": ["Mail.Read"] }, { "pathPattern": "/me/sendMail", "method": "post", "toolName": "send-mail", "scopes": ["Mail.Send"], "llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients." }, { "pathPattern": "/users/{user-id}/messages", "method": "get", "toolName": "list-shared-mailbox-messages", "workScopes": ["Mail.Read.Shared"], "llmTip": "CRITICAL: When searching emails, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'from:', 'subject:', 'body:', 'to:', 'cc:', 'bcc:', 'attachment:', 'hasAttachments:', 'importance:', 'received:', 'sent:'. Examples: $search=\"from:john@example.com\" | $search=\"subject:meeting AND hasAttachments:true\" | $search=\"body:urgent AND received>=2024-01-01\" | $search=\"from:alice AND importance:high\". Remember: ALWAYS wrap the entire search expression in double quotes! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter IMPORTANT: Always use $select to limit returned fields and reduce response size. Recommended default: $select=id,subject,from,toRecipients,receivedDateTime,bodyPreview,isRead,hasAttachments. Use bodyPreview instead of body for listings. To read the full email body, use get-shared-mailbox-message with the specific message id." }, { "pathPattern": "/users/{user-id}/mailFolders/{mailFolder-id}/messages", "method": "get", "toolName": "list-shared-mailbox-folder-messages", "workScopes": ["Mail.Read.Shared"], "llmTip": "CRITICAL: When searching emails, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'from:', 'subject:', 'body:', 'to:', 'cc:', 'bcc:', 'attachment:', 'hasAttachments:', 'importance:', 'received:', 'sent:'. Examples: $search=\"from:john@example.com\" | $search=\"subject:meeting AND hasAttachments:true\" | $search=\"body:urgent AND received>=2024-01-01\" | $search=\"from:alice AND importance:high\". Remember: ALWAYS wrap the entire search expression in double quotes! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter IMPORTANT: Always use $select to limit returned fields and reduce response size. Recommended default: $select=id,subject,from,toRecipients,receivedDateTime,bodyPreview,isRead,hasAttachments. Use bodyPreview instead of body for listings. To read the full email body, use get-shared-mailbox-message with the specific message id." }, { "pathPattern": "/users/{user-id}/messages/{message-id}", "method": "get", "toolName": "get-shared-mailbox-message", "workScopes": ["Mail.Read.Shared"] }, { "pathPattern": "/users/{user-id}/sendMail", "method": "post", "toolName": "send-shared-mailbox-mail", "workScopes": ["Mail.Send.Shared"], "llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients." }, { "pathPattern": "/users/{user-id}/messages", "method": "post", "toolName": "create-shared-mailbox-draft", "workScopes": ["Mail.ReadWrite.Shared"] }, { "pathPattern": "/users/{user-id}/messages/{message-id}/reply", "method": "post", "toolName": "reply-shared-mailbox-mail", "workScopes": ["Mail.Send.Shared"], "llmTip": "Reply to a message from a shared mailbox preserving full HTML formatting and conversation thread. The 'user-id' is the shared mailbox email address (e.g. support@contoso.com). The 'comment' field is your reply text. Do NOT reconstruct the email manually. Requires Send As permission on the shared mailbox in Exchange." }, { "pathPattern": "/users/{user-id}/messages/{message-id}/replyAll", "method": "post", "toolName": "reply-all-shared-mailbox-mail", "workScopes": ["Mail.Send.Shared"], "llmTip": "Reply-all to a message from a shared mailbox preserving full HTML formatting and conversation thread. The 'user-id' is the shared mailbox email address. The 'comment' field is your reply text. Requires Send As permission on the shared mailbox in Exchange." }, { "pathPattern": "/users/{user-id}/messages/{message-id}/forward", "method": "post", "toolName": "forward-shared-mailbox-mail", "workScopes": ["Mail.Send.Shared"], "llmTip": "Forward a message from a shared mailbox preserving full HTML formatting and attachments. The 'user-id' is the shared mailbox email address. 'toRecipients' is required. The 'comment' field adds text above the forwarded content. Requires Send As permission on the shared mailbox in Exchange." }, { "pathPattern": "/users", "method": "get", "toolName": "list-users", "workScopes": ["User.Read.All"], "llmTip": "CRITICAL: This request requires the ConsistencyLevel header set to eventual. When searching users, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'displayName:'. Examples: $search=\"displayName:john\" | $search=\"displayName:john\" OR \"displayName:jane\". Remember: ALWAYS wrap the entire search expression in double quotes and set the ConsistencyLevel header to eventual! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter" }, { "pathPattern": "/me/messages", "method": "post", "toolName": "create-draft-email", "scopes": ["Mail.ReadWrite"] }, { "pathPattern": "/me/messages/{message-id}", "method": "delete", "toolName": "delete-mail-message", "scopes": ["Mail.ReadWrite"], "llmTip": "Soft delete — moves to Deleted Items. To permanently delete, delete again from Deleted Items." }, { "pathPattern": "/me/messages/{message-id}/move", "method": "post", "toolName": "move-mail-message", "scopes": ["Mail.ReadWrite"], "llmTip": "destinationId accepts folder ID or well-known name (inbox, drafts, sentitems, deleteditems, junkemail, archive)." }, { "pathPattern": "/me/messages/{message-id}", "method": "patch", "toolName": "update-mail-message", "scopes": ["Mail.ReadWrite"] }, { "pathPattern": "/me/messages/{message-id}/attachments", "method": "post", "toolName": "add-mail-attachment", "scopes": ["Mail.ReadWrite"], "llmTip": "Max 3MB. Body requires @odata.type: {\"@odata.type\": \"#microsoft.graph.fileAttachment\", \"name\": \"file.pdf\", \"contentBytes\": \"<base64>\"}." }, { "pathPattern": "/me/messages/{message-id}/attachments/createUploadSession", "method": "post", "toolName": "create-mail-attachment-upload-session", "scopes": ["Mail.ReadWrite"], "llmTip": "For large attachments (3-150MB). Body: { AttachmentItem: { attachmentType: 'file', name: 'report.pdf', size: 5000000 } }. Returns a pre-authenticated uploadUrl for direct PUT of file bytes." }, { "pathPattern": "/me/messages/{message-id}/attachments", "method": "get", "toolName": "list-mail-attachments", "scopes": ["Mail.Read"], "llmTip": "Lists attachments on a message: id, name, contentType, size, isInline. To download the bytes, call download-bytes with target=/me/messages/{message-id}/attachments/{attachment-id}/$value (the /$value suffix returns raw bytes; the bare attachment URL embeds contentBytes in JSON which can truncate large files)." }, { "pathPattern": "/me/messages/{message-id}/attachments/{attachment-id}", "method": "delete", "toolName": "delete-mail-attachment", "scopes": ["Mail.ReadWrite"] }, { "pathPattern": "/me/messages/{message-id}/forward", "method": "post", "toolName": "forward-mail-message", "scopes": ["Mail.Send"], "llmTip": "Forward an email preserving full HTML formatting and attachments. The 'comment' field adds text above the forwarded content. toRecipients is required. Do NOT reconstruct the email manually - this endpoint handles everything server-side." }, { "pathPattern": "/me/messages/{message-id}/reply", "method": "post", "toolName": "reply-mail-message", "scopes": ["Mail.Send"], "llmTip": "Reply to an email preserving full HTML formatting. The 'comment' field is your reply text. Do NOT reconstruct the email manually." }, { "pathPattern": "/me/messages/{message-id}/replyAll", "method": "post", "toolName": "reply-all-mail-message", "scopes": ["Mail.Send"], "llmTip": "Reply-all preserving full HTML formatting. The 'comment' field is your reply text." }, { "pathPattern": "/me/messages/{message-id}/createForward", "method": "post", "toolName": "create-forward-draft", "scopes": ["Mail.ReadWrite"], "llmTip": "Create a forward draft (does not send). Useful when user wants to review before sending." }, { "pathPattern": "/me/messages/{message-id}/createReply", "method": "post", "toolName": "create-reply-draft", "scopes": ["Mail.ReadWrite"], "llmTip": "For HTML replies pass Message.body.contentType: 'html' with Message.body.content as HTML. Note: supplying Message.body replaces the whole draft body, so the original quoted history is not included. Specifying both 'comment' and Message.body returns 400. Signatures are added by the Outlook client only, not via Graph." }, { "pathPattern": "/me/messages/{message-id}/createReplyAll", "method": "post", "toolName": "create-reply-all-draft", "scopes": ["Mail.ReadWrite"], "llmTip": "For HTML replies pass Message.body.contentType: 'html' with Message.body.content as HTML. Note: supplying Message.body replaces the whole draft body, so the original quoted history is not included. Specifying both 'comment' and Message.body returns 400. Signatures are added by the Outlook client only, not via Graph." }, { "pathPattern": "/me/messages/{message-id}/send", "method": "post", "toolName": "send-draft-message", "scopes": ["Mail.Send"], "llmTip": "No request body needed — just call with the message ID. Draft must exist in Drafts folder." }, { "pathPattern": "/me/mailFolders/{mailFolder-id}/messageRules", "method": "get", "toolName": "list-mail-rules", "scopes": ["MailboxSettings.Read"], "llmTip": "Lists all message rules for a mail folder. Use the Inbox folder ID (get it from list-mail-folders) for inbox rules. Each rule has displayName, sequence, isEnabled, conditions (fromAddresses, subjectContains, etc.), actions (moveToFolder, forwardTo, delete, etc.), and exceptions." }, { "pathPattern": "/me/mailFolders/{mailFolder-id}/messageRules", "method": "post", "toolName": "create-mail-rule", "scopes": ["MailboxSettings.ReadWrite"], "llmTip": "Creates a message rule for a mail folder. Use the Inbox folder ID (get it from list-mail-folders) for inbox rules. Body: { displayName: 'Rule name', sequence: 1, isEnabled: true, conditions: { fromAddresses: [{ emailAddress: { address: 'user@example.com' } }] }, actions: { moveToFolder: 'folder-id' } }. Actions: moveToFolder, copyToFolder, forwardTo, forwardAsAttachmentTo, delete, markAsRead, markImportance, stopProcessingRules." }, { "pathPattern": "/me/mailFolders/{mailFolder-id}/messageRules/{messageRule-id}", "method": "patch", "toolName": "update-mail-rule", "scopes": ["MailboxSettings.ReadWrite"], "llmTip": "Updates an existing message rule. Use the Inbox folder ID (get it from list-mail-folders) for inbox rules. Send only the properties to change. Common use: { isEnabled: false } to disable a rule, or update conditions/actions." }, { "pathPattern": "/me/mailFolders/{mailFolder-id}/messageRules/{messageRule-id}", "method": "delete", "toolName": "delete-mail-rule", "scopes": ["MailboxSettings.ReadWrite"], "llmTip": "Deletes a message rule permanently. Use the Inbox folder ID (get it from list-mail-folders) for inbox rules." }, { "pathPattern": "/me/inferenceClassification/overrides", "method": "get", "toolName": "list-focused-inbox-overrides", "scopes": ["Mail.Read"], "llmTip": "Lists Focused Inbox classification overrides — explicit rules that force messages from a given sender (by SMTP address) into either the Focused or Other tab, regardless of what the Outlook ML classifier would predict. Each override has id, classifyAs ('focused' or 'other'), and senderEmailAddress {name, address}. Returns an empty collection if the user has never set an override." }, { "pathPattern": "/me/inferenceClassification/overrides", "method": "post", "toolName": "create-focused-inbox-override", "scopes": ["Mail.ReadWrite"], "llmTip": "Creates a Focused Inbox override for a sender. Body: { classifyAs: 'focused', senderEmailAddress: { name: 'Display Name', address: 'sender@example.com' } }. classifyAs must be 'focused' or 'other'. If an override already exists for that SMTP address, POST updates the existing override's name and classifyAs (use this to rename a sender). Resolve the sender's address with list-users or by reading a recent mail header — do not invent SMTP addresses." }, { "pathPattern": "/me/inferenceClassification/overrides/{inferenceClassificationOverride-id}", "method": "patch", "toolName": "update-focused-inbox-override", "scopes": ["Mail.ReadWrite"], "llmTip": "Updates the classifyAs field of an existing override. Body: { classifyAs: 'focused' } or { classifyAs: 'other' }. Per Graph API, PATCH cannot change senderEmailAddress — to change the SMTP address, delete and recreate the override. To rename the display name only, POST a new override with the same SMTP address (it will overwrite the name)." }, { "pathPattern": "/me/inferenceClassification/overrides/{inferenceClassificationOverride-id}", "method": "delete", "toolName": "delete-focused-inbox-override", "scopes": ["Mail.ReadWrite"], "llmTip": "Deletes a Focused Inbox override. Future messages from that sender revert to the Outlook ML classifier's default behavior. Use list-focused-inbox-overrides to find the ID first." }, { "pathPattern": "/me/events", "method": "get", "toolName": "list-calendar-events", "scopes": ["Calendars.Read"], "supportsTimezone": true, "supportsExpandExtendedProperties": true, "llmTip": "WARNING: Does NOT expand recurring events — only returns seriesMaster. Use get-calendar-view instead to see individual occurrences within a date range." }, { "pathPattern": "/me/events/{event-id}", "method": "get", "toolName": "get-calendar-event", "scopes": ["Calendars.Read"], "supportsTimezone": true, "supportsExpandExtendedProperties": true }, { "pathPattern": "/me/events", "method": "post", "toolName": "create-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients." }, { "pathPattern": "/me/events/{event-id}", "method": "patch", "toolName": "update-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients. WARNING: Setting attendees replaces the entire attendee list — include all attendees, not just new ones." }, { "pathPattern": "/me/events/{event-id}", "method": "delete", "toolName": "delete-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "Deleting a seriesMaster deletes ALL occurrences of the recurring event. To cancel a single occurrence, delete that specific instance ID from list-calendar-event-instances." }, { "pathPattern": "/me/events/{event-id}/accept", "method": "post", "toolName": "accept-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "Accepts a meeting invitation. Optional body: { sendResponse: true, comment: 'I will attend.' }. Set sendResponse to false to accept silently without notifying the organizer." }, { "pathPattern": "/me/events/{event-id}/decline", "method": "post", "toolName": "decline-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "Declines a meeting invitation. Optional body: { sendResponse: true, comment: 'Cannot attend, conflict.' }. The event remains in the calendar as declined unless the user deletes it." }, { "pathPattern": "/me/events/{event-id}/tentativelyAccept", "method": "post", "toolName": "tentatively-accept-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "Tentatively accepts a meeting invitation. Optional body: { sendResponse: true, comment: 'I might be able to attend.' }. Use proposedNewTime to suggest an alternative: { proposedNewTime: { start: { dateTime, timeZone }, end: { dateTime, timeZone } } }." }, { "pathPattern": "/me/calendars/{calendar-id}/events", "method": "get", "toolName": "list-specific-calendar-events", "scopes": ["Calendars.Read"], "supportsTimezone": true, "supportsExpandExtendedProperties": true, "llmTip": "WARNING: Does NOT expand recurring events — only returns seriesMaster. Use get-specific-calendar-view instead." }, { "pathPattern": "/me/calendars/{calendar-id}/events/{event-id}", "method": "get", "toolName": "get-specific-calendar-event", "scopes": ["Calendars.Read"], "supportsTimezone": true, "supportsExpandExtendedProperties": true }, { "pathPattern": "/me/calendars/{calendar-id}/events", "method": "post", "toolName": "create-specific-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients." }, { "pathPattern": "/me/calendars/{calendar-id}/events/{event-id}", "method": "patch", "toolName": "update-specific-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients. WARNING: Setting attendees replaces the entire attendee list — include all attendees, not just new ones." }, { "pathPattern": "/me/calendars/{calendar-id}/events/{event-id}", "method": "delete", "toolName": "delete-specific-calendar-event", "scopes": ["Calendars.ReadWrite"], "llmTip": "Deleting a seriesMaster deletes ALL occurrences. To cancel a single occurrence, use the specific instance ID." }, { "pathPattern": "/me/calendarView", "method": "get", "toolName": "get-calendar-view", "scopes": ["Calendars.Read"], "supportsTimezone": true, "supportsExpandExtendedProperties": true, "llmTip": "Returns expanded recurring event instances (not just seriesMaster) within a date range for the default calendar. Requires startDateTime and endDateTime query parameters in ISO 8601 format (e.g., 2024-01-01T00:00:00Z). Use get-specific-calendar-view if you need a non-default calendar. To find Teams meetings, use $filter=isOnlineMeeting eq true. To search by subject, use $filter=contains(subject,'keyword'). Teams meetings include a joinWebUrl property needed for transcript access via list-online-meetings." }, { "pathPattern": "/me/calendars/{calendar-id}/calendarView", "method": "get", "toolName": "get-specific-calendar-view", "scopes": ["Calendars.Read"], "supportsTimezone": true, "supportsExpandExtendedProperties": true, "llmTip": "Returns expanded recurring event instances (not just seriesMaster) within a date range for a specific calendar. Requires startDateTime and endDateTime query parameters in ISO 8601 format (e.g., 2024-01-01T00:00:00Z). Each instance includes seriesMasterId and type (occurrence/exception) fields for recurring event linkage. Use fetchAllPages=true to retrieve all results when there are many events. To find Teams meetings, use $filter=isOnlineMeeting eq true. Teams meetings include a joinWebUrl property needed for transcript access via list-online-meetings." }, { "pathPattern": "/me/calendar/getSchedule", "method": "post", "toolName": "get-schedule", "readOnly": true, "workScopes": ["Calendars.Read"] }, { "pathPattern": "/users/{user-id}/calendar/events", "method": "get", "toolName": "list-shared-calendar-events", "workScopes": ["Calendars.Read.Shared"] }, { "pathPattern": "/users/{user-id}/calendarView", "method": "get", "toolName": "get-shared-calendar-view", "workScopes": ["Calendars.Read.Shared"], "supportsTimezone": true }, { "pathPattern": "/me/calendars/{calendar-id}/events/{event-id}/instances", "method": "get", "toolName": "list-calendar-event-instances", "scopes": ["Calendars.Read"], "supportsTimezone": true, "supportsExpandExtendedProperties": true, "llmTip": "Expand a recurring event into individual instances within a date range. Requires startDateTime and endDateTime query parameters in ISO 8601 format (e.g., 2024-01-01T00:00:00Z). Use this to see all occurrences of a recurring event." }, { "pathPattern": "/me/calendars", "method": "get", "toolName": "list-calendars", "scopes": ["Calendars.Read"] }, { "pathPattern": "/me/calendars", "method": "post", "toolName": "create-calendar", "scopes": ["Calendars.ReadWrite"], "llmTip": "Creates a new personal calendar. Body: { name: 'My Calendar', color: 'auto' }. Available colors: auto, lightBlue, lightGreen, lightOrange, lightGray, lightYellow, lightTeal, lightPink, lightBrown, lightRed, maxColor." }, { "pathPattern": "/me/calendars/{calendar-id}", "method": "patch", "toolName": "update-calendar", "scopes": ["Calendars.ReadWrite"], "llmTip": "Updates a calendar's properties. Body: { name: 'New Name', color: 'lightBlue' }. Cannot update the default calendar's name." }, { "pathPattern": "/me/calendars/{calendar-id}", "method": "delete", "toolName": "delete-calendar", "scopes": ["Calendars.ReadWrite"], "llmTip": "Deletes a calendar and all its events. The default calendar cannot be deleted. This action cannot be undone." }, { "pathPattern": "/me/findMeetingTimes", "method": "post", "toolName": "find-meeting-times", "readOnly": true, "workScopes": ["Calendars.Read.Shared"] }, { "pathPattern": "/me/drives", "method": "get", "toolName": "list-drives", "scopes": ["Files.Read"] }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/delta()", "method": "get", "toolName": "get-drive-delta", "scopes": ["Files.Read"], "llmTip": "Tracks changes to a driveItem and its children over time. Returns a collection of driveItems that have been created, modified, or deleted. Use get-drive-root-item first to get the root driveItem-id, then pass it here. Supports $select and delta tokens for incremental sync via @odata.deltaLink." }, { "pathPattern": "/drives/{drive-id}/root", "method": "get", "toolName": "get-drive-root-item", "scopes": ["Files.Read"] }, { "pathPattern": "/drives/{drive-id}/root", "method": "get", "toolName": "get-drive-root-item", "scopes": ["Files.Read"] }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/children", "method": "get", "toolName": "list-folder-files", "scopes": ["Files.Read"] }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}", "method": "delete", "toolName": "delete-onedrive-file", "scopes": ["Files.ReadWrite"] }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/content", "method": "put", "toolName": "upload-file-content", "scopes": ["Files.ReadWrite"], "llmTip": "Body is a base64-encoded string of the file bytes; the server decodes it before PUT. Max 4MB inline (use create-upload-session above 4MB). For new files use path format: /items/root:/path/to/file.txt:/content. Overwrites existing files without warning." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/createUploadSession", "method": "post", "toolName": "create-upload-session", "scopes": ["Files.ReadWrite"], "llmTip": "For large file uploads (no size limit). Returns a pre-authenticated uploadUrl for direct PUT of file bytes. For new files use path: /items/{parentId}:/{fileName}:/createUploadSession. Body (optional): { item: { '@microsoft.graph.conflictBehavior': 'rename' } }." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}", "method": "get", "toolName": "get-drive-item", "scopes": ["Files.Read"], "llmTip": "Gets metadata for a file or folder: name, size, lastModifiedDateTime, createdBy, webUrl, file (mimeType, hashes), folder (childCount), parentReference, and @microsoft.graph.downloadUrl. For the bytes, call download-bytes with target=/drives/{drive-id}/items/{driveItem-id}/content (Graph redirects to the same downloadUrl)." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}", "method": "patch", "toolName": "move-rename-onedrive-item", "scopes": ["Files.ReadWrite"], "llmTip": "Move and/or rename a file or folder. To move, provide parentReference with the target folder's id. To rename, provide a new name. Both can be done in a single request." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/children", "method": "post", "toolName": "create-onedrive-folder", "scopes": ["Files.ReadWrite"], "llmTip": "Creates a new folder inside the specified drive item. Body must include name (string) and folder ({}) fields. Use @microsoft.graph.conflictBehavior to control behavior on name conflict: 'rename' (default), 'replace', or 'fail'." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/invite", "method": "post", "toolName": "share-drive-item", "scopes": ["Files.ReadWrite"], "llmTip": "Shares a file or folder with specific users. Body: { recipients: [{ email: 'user@example.com' }], roles: ['read'], sendInvitation: true, message: 'Please review this file.' }. Roles: 'read', 'write', 'owner'. Set requireSignIn to true to require authentication." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/createLink", "method": "post", "toolName": "create-drive-item-share-link", "scopes": ["Files.ReadWrite"], "llmTip": "Create a shareable link for a file or folder WITHOUT sending an email invitation. Body: { type: 'view' | 'edit' | 'embed', scope: 'anonymous' | 'organization' | 'users', password?: string, expirationDateTime?: ISO-8601, retainInheritedPermissions?: boolean }. Returns a permission with link.webUrl. Pair with share-drive-item when you want to grant explicit access; use this when you only need a URL to paste into a doc/email/chat without triggering OneDrive notifications." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/copy", "method": "post", "toolName": "copy-drive-item", "scopes": ["Files.ReadWrite"], "llmTip": "Asynchronously copy a file or folder to a new location and/or name. Body: { parentReference: { driveId: '...', id: '...' }, name?: 'New Name.xlsx' }. Returns 202 Accepted with a Location header pointing at a monitor URL for the async job. Ideal for duplicating templates (e.g. clone an Armhr Census Template per prospect), bulk file provisioning, or preserving an immutable snapshot of a working file." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/preview", "method": "post", "toolName": "create-drive-item-preview", "scopes": ["Files.Read"], "llmTip": "Generate a short-lived embeddable preview URL for a file (Office docs, PDFs, images). Body: { page?: number | string, zoom?: number, viewer?: 'onedrive' | 'office' }. Returns getUrl (interactive) and postUrl (form-post). Useful for surfacing inline previews in summary emails or chat messages without needing the recipient to open the file." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/thumbnails", "method": "get", "toolName": "list-drive-item-thumbnails", "scopes": ["Files.Read"], "llmTip": "Lists thumbnail sets for a file. Each set contains small (96px), medium (176px), large (800px) thumbnails with url and dimensions. Returns empty for unsupported types (text docs). Use $select=small,medium,large or $expand=small($select=url) to fetch specific sizes. The returned URLs are short-lived — fetch the bytes immediately." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/permissions", "method": "get", "toolName": "list-drive-item-permissions", "scopes": ["Files.Read"], "llmTip": "Lists all permissions (sharing links, direct access, inherited) on a file or folder. Each permission has roles, grantedTo (user), link (sharing URL), and inheritedFrom." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/permissions/{permission-id}", "method": "delete", "toolName": "delete-drive-item-permission", "scopes": ["Files.ReadWrite"], "llmTip": "Removes a specific permission from a file or folder. Only permissions that are not inherited can be deleted. Use list-drive-item-permissions first to find the permission ID." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/versions", "method": "get", "toolName": "list-drive-item-versions", "scopes": ["Files.Read"], "llmTip": "Lists version history of a file. Each version has id, lastModifiedDateTime, lastModifiedBy, and size. Use the version id with /versions/{id}/content to download a specific version." }, { "pathPattern": "/drives/{drive-id}/search(q='{q}')", "method": "get", "toolName": "search-onedrive-files", "scopes": ["Files.Read"], "skipEncoding": ["q"], "llmTip": "Searches for files in a drive by name or content. The q parameter searches file names, metadata, and file content. Returns matching driveItems with id, name, webUrl, size, lastModifiedDateTime. Use list-drives first to get the drive-id." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/charts/add", "method": "post", "toolName": "create-excel-chart", "isExcelOp": true, "scopes": ["Files.ReadWrite"] }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format", "method": "patch", "toolName": "format-excel-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["address"], "llmTip": "Apply rangeFormat properties to a specific range. Required path param 'address' (e.g. 'A1:E5' or 'Sheet1!A1:E5'). Body: { horizontalAlignment, verticalAlignment, wrapText, columnWidth, rowHeight }. Note: font, fill, and borders are sub-resources on rangeFormat — set them via /format/font, /format/fill, and /format/borders/{sideIndex} respectively, not on this endpoint." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range()/sort", "method": "patch", "toolName": "sort-excel-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"] }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')", "method": "get", "toolName": "get-excel-range", "isExcelOp": true, "scopes": ["Files.Read"], "skipEncoding": ["address"] }, { "pathPattern": "/me/messages/{message-id}/$value", "method": "get", "toolName": "get-mail-message-mime", "scopes": ["Mail.Read"], "acceptType": "text/plain", "llmTip": "Download an email message as raw RFC 5322 MIME content (.eml format). Use this when archiving an email to disk preserving all original headers, body, and inline-encoded attachments. Returns the MIME stream as text. Find the message id with list-mail-messages first." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')", "method": "patch", "toolName": "update-excel-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["address"], "llmTip": "Set cell values, formulas, or number format on any range — does NOT require the worksheet to be a formal Excel table. Body: { values: [['v1','v2','v3']] } for a single row, or [['a','b'],['c','d']] for multi-row. Use this for append (target the next empty row's address, e.g. 'A172:H172'), update (target a single cell like 'H42'), or prepend-style edits (read existing, concatenate, write back). Number of inner-array values must match the column count of the address." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/insert", "method": "post", "toolName": "insert-excel-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["address"], "llmTip": "Insert blank cells at the given range, shifting existing content. Body: { shift: 'Down' } or { shift: 'Right' }. Use 'Down' to insert blank rows above existing data." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/delete", "method": "post", "toolName": "delete-excel-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["address"], "llmTip": "Delete cells at the given range, shifting remaining content. Body: { shift: 'Up' } or { shift: 'Left' }. Use 'Up' to delete entire rows." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/merge", "method": "post", "toolName": "merge-excel-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["address"], "llmTip": "Merge the cells in the given range into a single cell. Body: { across: false } merges the entire range into one cell; { across: true } merges each row separately. Useful for building styled headers, banner rows, and report layouts." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/unmerge", "method": "post", "toolName": "unmerge-excel-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["address"], "llmTip": "Unmerge any merged cells within the given range back into individual cells. No request body. Inverse of merge-excel-range." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/clear", "method": "post", "toolName": "clear-excel-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["address"], "llmTip": "Clear cell contents and/or formatting on the given range. Body: { applyTo: 'All' | 'Formats' | 'Contents' }. 'Contents' wipes values but keeps formatting; 'Formats' resets styling but keeps values; 'All' wipes both. Use this to reset a worksheet section before a fresh write rather than overwriting cell-by-cell." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/usedRange()", "method": "get", "toolName": "get-excel-used-range", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "llmTip": "Get the smallest range that encompasses any cells with values or formatting on the worksheet. Returns address, values, formulas, numberFormat, rowCount, columnCount. Use this to discover the populated bounds of a sheet before reading or appending — avoids guessing how far data extends. Optional $select to trim the response." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}/rows/itemAt(index={index})", "method": "patch", "toolName": "update-excel-table-row", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["index"], "llmTip": "Update a single row in a formal Excel table by zero-based row index. Body: { values: [[...]] } with one inner array matching the column count." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}/rows/itemAt(index={index})", "method": "delete", "toolName": "delete-excel-table-row", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "skipEncoding": ["index"], "llmTip": "Delete a single row from a formal Excel table by zero-based row index." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/tables/add", "method": "post", "toolName": "create-excel-table", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "llmTip": "Convert a worksheet range into a formal Excel table. Body: { address: 'A1:H171', hasHeaders: true }. Required before using add-excel-table-rows / update-excel-table-row / delete-excel-table-row on a plain-cells sheet." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets", "method": "get", "toolName": "list-excel-worksheets", "isExcelOp": true, "scopes": ["Files.Read"] }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables", "method": "get", "toolName": "list-excel-tables", "isExcelOp": true, "scopes": ["Files.Read"], "llmTip": "Lists all named tables in a workbook. Each table has id, name, showHeaders, showTotals, columns, and style. Use the table name or id with other table endpoints." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}", "method": "get", "toolName": "get-excel-table", "isExcelOp": true, "scopes": ["Files.Read"], "llmTip": "Gets a specific table by name or ID. Returns table properties including columns, showHeaders, showTotals, and style." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}/rows", "method": "get", "toolName": "list-excel-table-rows", "isExcelOp": true, "scopes": ["Files.Read"], "llmTip": "Lists all rows in a table. Each row has index and values (array of cell values). Use $top and $skip for pagination on large tables." }, { "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}/rows", "method": "post", "toolName": "add-excel-table-rows", "isExcelOp": true, "scopes": ["Files.ReadWrite"], "llmTip": "Adds rows to a table. Body: { values: [['col1val', 'col2val', 'col3val'], ['row2col1', 'row2col2', 'row2col3']] }. Each inner array is one row. Values must match the number of columns in the table." }, { "pathPattern": "/me/onenote/notebooks", "method": "get", "toolName": "list-onenote-notebooks", "scopes": ["Notes.Read"] }, { "pathPattern": "/me/onenote/notebooks", "method": "post", "toolName": "create-onenote-notebook", "scopes": ["Notes.Create"], "llmTip": "Creates a new OneNote notebook. Body: { displayName: 'Notebook Name' }. The name must be unique across the user's notebooks." }, { "pathPattern": "/me/onenote/notebooks/{notebook-id}/sections", "method": "get", "toolName": "list-onenote-notebook-sections", "scopes": ["Notes.Read"] }, { "pathPattern": "/me/onenote/notebooks/{notebook-id}/sections", "method": "post", "toolName": "create-onenote-section", "scopes": ["Notes.Create"], "llmTip": "Creates a new section in a notebook. Body: { displayName: 'Section Name' }." }, { "pathPattern": "/me/onenote/sections", "method": "get", "toolName": "list-all-onenote-sections", "scopes": ["Notes.Read"], "llmTip": "Lists all sections across all notebooks. Use list-onenote-notebook-sections to list sections within a specific notebook instead." }, { "pathPattern": "/me/onenote/sections/{onenoteSection-id}/pages", "method": "get", "toolName": "list-onenote-section-pages", "scopes": ["Notes.Read"] }, { "pathPattern": "/me/onenote/pages/{onenotePage-id}/content", "method": "get", "toolName": "get-onenote-page-content", "scopes": ["Notes.Read"] }, { "pathPattern": "/sites/{site-id}/onenote/notebooks", "method": "get", "toolName": "list-sharepoint-site-onenote-notebooks", "workScopes": ["Notes.Read"] }, { "pathPattern": "/sites/{site-id}/onenote/notebooks/{notebook-id}/sections", "method": "get", "toolName": "list-sharepoint-site-onenote-notebook-sections", "workScopes": ["Notes.Read"] }, { "pathPattern": "/sites/{site-id}/onenote/sections/{onenoteSection-id}/pages", "method": "get", "toolName": "list-sharepoint-site-onenote-section-pages", "workScopes": ["Notes.Read"] }, { "pathPattern": "/sites/{site-id}/onenote/pages/{onenotePage-id}/content", "method": "get", "toolName": "get-sharepoint-site-onenote-page-content", "workScopes": ["Notes.Read"] }, { "pathPattern": "/me/onenote/pages", "method": "post", "toolName": "create-onenote-page", "scopes": ["Notes.Create"], "contentType": "text/html", "llmTip": "Body must be a full HTML document (with <html><head><title>...</title></head><body>...</body></html>). Partial HTML or plain text fails silently or creates malformed pages." }, { "pathPattern": "/me/onenote/sections/{onenoteSection-id}/pages", "method": "post", "toolName": "create-onenote-section-page", "scopes": ["Notes.Create"], "contentType": "text/html", "llmTip": "Body must be a full HTML document (with <html><head><title>...</title></head><body>...</body></html>). Partial HTML fails silently." }, { "pathPattern": "/me/onenote/pages/{onenotePage-id}", "method": "delete", "toolName": "delete-onenote-page", "scopes": ["Notes.ReadWrite"], "llmTip": "Deletes a OneNote page permanently. This cannot be undone." }, { "pathPattern": "/me/todo/lists", "method": "get", "toolName": "list-todo-task-lists", "scopes": ["Tasks.Read"], "llmTip": "Lists all To Do task lists. Returns todoTaskList-id needed for all task operations. The default list is typically called 'Tasks'. NOTE: $select is NOT supported by this endpoint — do not pass select parameter, Graph returns 400." }, { "pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks", "method": "get", "toolName": "list-todo-tasks", "scopes": ["Tasks.Read"], "llmTip": "Lists tasks in a To Do list. Requires todoTaskList-id — use list-todo-task-lists to find it. NOTE: $select is NOT supported — do not pass select, Graph returns 400. Use $filter=status eq 'notStarted' or $filter=status eq 'completed' to filter by status. Use $top to limit results. Status values: 'notStarted', 'inProgress', 'completed', 'waitingOnOthers', 'deferred'." }, { "pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}", "method": "get", "toolName": "get-todo-task", "scopes": ["Tasks.Read"], "llmTip": "Returns a single To Do task. NOTE: $select is NOT supported — do not pass select parameter, Graph returns RequestBroker--ParseUri (400). Use $expand=linkedResources to include linked email/resource. Returns body content (HTML format), checklist items, and linked resources." }, { "pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks", "method": "post", "toolName": "create-todo-task", "scopes": ["Tasks.ReadWrite"] }, { "pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}", "method": "patch", "toolName": "update-todo-task", "scopes": ["Tasks.ReadWrite"] }, { "pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}", "method": "delete", "toolName": "delete-todo-task", "scopes": ["Tasks.ReadWrite"] }, { "pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}/linkedResources", "method": "get", "toolName": "list-todo-linked-resources", "scopes": ["Tasks.Read"], "llmTip": "Lists resources linked to a To Do task (emails, URLs, etc.). Each linked resource has displayName, webUrl, applicationName, and externalId." }, { "pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}/linkedResources", "method": "post", "toolName": "create-todo-linked-resource", "scopes": ["Tasks.ReadWrite"], "llmTip": "Links a resource to a To Do task. Body: { webUrl: 'https://...', applicationName: 'Mail', displayName: 'Related email', externalId: 'optional