Microsoft 365 in Your Terminal.
Mail. Calendar. OneDrive. Contacts. 25 commands. Every one doubles as an MCP tool.
Google shipped their Workspace CLI. Half the enterprise world runs Microsoft. So we built ms365-cli — the missing CLI for agents on the Microsoft stack.

Why ms365-cli Exists
Without ms365-cli
- Agent needs a browser to check Outlook — impossible
- Microsoft Graph API requires OAuth boilerplate every time
- No way to wire M365 into an autonomous agent loop
- Google has a CLI. Microsoft doesn’t. Until now.
- Agents can’t send emails, book meetings, or search files
With ms365-cli
- 25 commands covering Mail, Calendar, OneDrive, Contacts
- MSAL device code auth — login once, tokens refresh silently
- Every command is also an MCP tool — plug into any AI agent
- JSON-first output — pipe to jq, save to files, feed to agents
- 5-minute setup, MIT licensed, zero dependencies beyond MSAL
Quick Start
1. Install
npm install -g ms365-cli2. Register an Azure AD App (one-time)
1. Go to portal.azure.com → App registrations → New registration
2. Redirect URI: Mobile and desktop → http://localhost
3. API permissions: Mail.ReadWrite, Mail.Send, Calendars.ReadWrite, Files.ReadWrite, Contacts.ReadWrite, User.Read
4. Authentication → Allow public client flows → Yes
3. Login
m365 login --client-id <your-app-id> --tenant-id <your-tenant-id>Opens a device code flow — sign in once, tokens are cached and silently refreshed.
4. Verify
m365 status --pretty
# {"authenticated":true,"account":"you@example.com"}
m365 mail unread-count
# {"folder":"Inbox","unread":4,"total":12}What ms365-cli Gives Your Agent
Mail Management
List inbox, read messages, send email, reply, search with KQL, move, delete, and track unread counts.
Calendar & Meetings
List events, create meetings with Teams links, update, delete, and filter by date range. Full scheduling control.
OneDrive Access
Browse files, search across drives, download documents, get metadata, and delete items. Full file system control.
Contacts
List, search, get, and create Outlook contacts programmatically. Perfect for CRM sync workflows.
Attachments
Send emails with file attachments, list attachments on messages, and download any attachment type to disk.
MCP Server
Every command is exposed as an MCP tool. Claude, Cursor, OpenClaw, and any MCP client can call all 25 commands.
Agent Workflows
Real prompts agents use to manage Microsoft 365 end-to-end.
Morning Inbox Triage
Agent Prompt
“Check my email for anything unread. Summarize the important ones, reply to the meeting request from Sarah, and archive the newsletters.”
Agent checks unread count, pulls unread messages, classifies by priority, replies to actionable items, and moves low-priority mail — fully autonomous inbox management.
m365 mail unread-countCheck if new mail exists
m365 mail list --unread --top 20 --prettyPull all unread messages
m365 mail get $MESSAGE_IDRead full message content
m365 mail reply $MESSAGE_ID --body "Confirmed, see you at 2pm."Reply to the meeting request
m365 mail move $NEWSLETTER_ID --destination "Archive"Archive low-priority mail
Schedule a Discovery Call
Agent Prompt
“Schedule a discovery call with prospect@acme.com next Tuesday at 2pm EST. Include a Teams link and send a confirmation email.”
Agent creates a calendar event with Teams meeting, adds the attendee, then sends a personalized confirmation email — booking + outreach in one autonomous flow.
m365 calendar create --subject "Discovery Call" --start 2026-03-10T14:00:00 --end 2026-03-10T15:00:00 --timezone "America/New_York" --attendees "prospect@acme.com" --online-meetingCreate meeting with Teams link
m365 mail send --to prospect@acme.com --subject "Discovery Call Confirmed" --body "Looking forward to connecting Tuesday at 2pm EST. Teams link: ..." --content-type htmlSend confirmation email
Find and Download a Document
Agent Prompt
“Search OneDrive for the Q1 quarterly report, download it, and email it to the finance team.”
Agent searches OneDrive, identifies the right file, downloads it locally, and sends it as an email attachment — document retrieval + distribution automated.
m365 drive search "Q1 quarterly report"Search OneDrive for the file
m365 drive download --id $FILE_ID --output-file ./q1-report.pdfDownload to local disk
m365 mail send --to finance@company.com --subject "Q1 Report" --body "Attached." --attachment ./q1-report.pdfEmail with attachment
Weekly Calendar Prep
Agent Prompt
“Pull my calendar for next week. Identify any double-bookings or gaps. List all external meetings with attendees.”
Agent pulls the full week of events, analyzes for conflicts, identifies external vs. internal meetings, and delivers a structured briefing — your weekly prep, automated.
m365 calendar list --start 2026-03-09T00:00:00Z --end 2026-03-13T23:59:59Z --prettyPull all events for the week
m365 calendar get $EVENT_IDGet details on flagged events
m365 contacts search "Sarah Johnson"Look up attendee details
Reply to Client Thread
Agent Prompt
“Find the latest email from client@bigco.com, read the full thread, and draft a reply addressing their pricing question.”
Agent searches mail by sender, reads the full conversation thread for context, and composes a contextual reply — your agent handles client communication.
m365 mail search "from:client@bigco.com"Find messages from this sender
m365 mail get $MESSAGE_IDRead the full thread
m365 mail reply $MESSAGE_ID --body "Thanks for your question on pricing..."Send contextual reply
New Contact from LinkedIn
Agent Prompt
“I just connected with Jane Smith, VP Sales at Acme Corp on LinkedIn. Add her to my Outlook contacts and send an intro email.”
Agent creates a structured contact record in Outlook and sends a personalized introduction email — LinkedIn connection to CRM pipeline in one step.
m365 contacts create --given "Jane" --surname "Smith" --email "jane.smith@acme.com" --company "Acme Corp" --phone "+1-555-0123"Create Outlook contact
m365 mail send --to jane.smith@acme.com --subject "Great connecting!" --body "Hi Jane, enjoyed connecting on LinkedIn..."Send intro email
Commands Reference
m365 auth login [--client-id <id>] [--tenant-id <id>]Authenticate via device code flowm365 auth logoutClear cached tokensm365 auth statusShow authentication statem365 mail list [--top <n>] [--folder <name>] [--filter <odata>] [--unread]List inbox messagesm365 mail get <id>Read a specific messagem365 mail send --to <emails> --subject <text> --body <text> [--attachment <files>]Send email with optional attachmentsm365 mail reply <id> --body <text> [--reply-all]Reply to a message threadm365 mail search <query>Search with KQL syntaxm365 mail move <id> --destination <folder>Move message between foldersm365 mail delete <id>Delete a messagem365 mail unread-count [--folder <name>]Get unread message countm365 calendar list [--start <iso>] [--end <iso>] [--top <n>]List events in a date rangem365 calendar get <id>Get event detailsm365 calendar create --subject <text> --start <iso> --end <iso> [--attendees] [--online-meeting]Create event with optional Teams linkm365 calendar update <id> [--subject] [--start] [--end]Update an existing eventm365 calendar delete <id>Delete an eventm365 drive list [--folder-id <id>] [--top <n>]Browse files and foldersm365 drive get <id> | --path <path>Get file metadatam365 drive search <query>Search across OneDrivem365 drive download [id] [--path] [--output-file]Download file to diskm365 drive delete <id>Delete a file or folderm365 contacts list [--top <n>] [--filter <odata>]List Outlook contactsm365 contacts get <id>Get contact detailsm365 contacts search <query>Search contactsm365 contacts create --given <name> [--surname] [--email] [--phone] [--company]Create a new contactMCP Server Setup
Every command is available as an MCP tool. Configure once and your agent has full Microsoft 365 access.
{
"mcpServers": {
"m365": {
"command": "npx",
"args": ["ms365-cli", "mcp"],
"env": {
"M365_CLIENT_ID": "your-azure-app-client-id"
}
}
}
}MCP tools registered:
OpenClaw Agent Setup
Give any OpenClaw agent full Microsoft 365 access. Install once, authenticate, and the agent handles everything via exec.
Architecture
Every API endpoint is a CommandDefinition — one source of truth powering both the CLI subcommand and the MCP tool. Adding a new endpoint is one new file.
src/
├── core/
│ ├── types.ts # CommandDefinition, GraphClient interfaces
│ ├── client.ts # Graph API HTTP client (retry, rate limit, pagination)
│ ├── auth.ts # MSAL device code flow + silent refresh
│ ├── config.ts # ~/.m365/ config and token cache
│ ├── errors.ts # Typed error classes
│ ├── output.ts # JSON output + field filtering
│ └── handler.ts # executeCommand (path/query/odata/body mapping)
├── commands/
│ ├── mail/ # 8 commands
│ ├── calendar/ # 5 commands
│ ├── drive/ # 5 commands
│ └── contacts/ # 4 commands
└── mcp/
└── server.ts # MCP server (auto-registers all commands as tools)Same pattern as instantly-cli + clay-gtm-cli
The CommandDefinition architecture is shared across all TOFU CLIs. One schema definition generates the Commander.js subcommand, the Zod schema, and the MCP tool — zero duplication.
MSAL authentication
Device code flow for initial login. Tokens cached at ~/.m365/token-cache.json and silently refreshed via MSAL’s acquireTokenSilent. No browser needed after first auth.
Ready to give your agent Microsoft 365 superpowers?
Install ms365-cli, authenticate in 5 minutes, and your agent can read email, book meetings, search OneDrive, and manage contacts.
Need agents wired into your Microsoft 365 stack? We deploy and manage the full setup.