Unofficial agent-friendly Microsoft 365 CLI
mogcli is a Microsoft Graph CLI for personal Microsoft accounts (MSA) and enterprise Microsoft Entra ID accounts. It provides scriptable commands for Mail, Calendar, Contacts, Groups, Tasks, and OneDrive.
- Multiple profiles with exactly one active profile at a time.
- Consumer and enterprise audiences.
- Delegated user auth and enterprise app-only auth.
- Stable scripting output modes:
--jsonand--plain. - Interactive delegated wizard (
mog auth), advanced app-only wizard (mog auth app), settings editor (mog auth update), and non-interactive login (mog auth login). - Per-command scope requests in delegated mode (progressive consent).
--dry-runpreviews for write operations in Mail, Calendar, and OneDrive.
| Workload | Delegated | App-only |
|---|---|---|
| Yes | Yes (enterprise, requires target user) | |
| Calendar | Yes | No |
| Contacts | Yes | Yes (enterprise, requires target user) |
| Groups | Enterprise only | Enterprise only |
| Tasks (Microsoft To Do) | Yes | No |
| OneDrive | Yes | Yes (enterprise, requires target user) |
Notes:
- App-only mode is enterprise-only.
- Calendar and tasks are intentionally blocked in app-only mode.
- Groups are intentionally blocked for consumer profiles.
git clone https://github.com/jaredpalmer/mogcli.git
cd mogcli
go build -o bin/mog ./cmd/mog
./bin/mog --helpgo install github.com/jaredpalmer/mogcli/cmd/mog@latest
mog --helpbrew tap jaredpalmer/tap
brew install jaredpalmer/tap/mogcli
mog --helpBefore login, create app registrations in Microsoft Entra:
- Consumer app registration (for MSA audience).
- Enterprise app registration (for work/school audience).
For delegated login:
- Enable public client flow in app Authentication settings.
- Add delegated Graph permissions for the workloads you plan to use.
For app-only login:
- Use an enterprise app registration.
- Add required application permissions.
- Grant admin consent.
- Create a client secret.
mog authThis wizard configures the profile and starts delegated device-code login.
Advanced app-only interactive setup (enterprise only):
mog auth appConsumer profile:
mog auth login \
--profile personal \
--audience consumer \
--client-id <consumer-client-id> \
--scope-workloads mail,calendar,contacts,tasks,onedriveEnterprise delegated profile:
mog auth login \
--profile work \
--audience enterprise \
--client-id <enterprise-client-id> \
--tenant <tenant-id-or-domain> \
--scope-workloads mail,calendar,contacts,tasks,onedrive,groupsexport MOG_CLIENT_SECRET="<client-secret-value>"
mog auth login \
--profile work-app \
--audience enterprise \
--mode app-only \
--client-id <enterprise-client-id> \
--tenant <tenant-id-or-domain> \
--app-only-user user@contoso.com \
--client-secret-env MOG_CLIENT_SECRETmog auth accounts
mog auth use work
mog auth whoamiFor one-off command routing without switching active profile:
mog --use-profile work mail list --max 10mog auth update
mog auth update --profile workThe update flow shows current settings, lets you choose one field at a time to edit, and saves only selected changes.
mog authmog auth appmog auth login|update|logout|accounts|use|whoamimog mail list|get|sendmog calendar list|get|create|update|deletemog contacts list|get|create|update|deletemog groups list|get|membersmog tasks lists|list|get|create|update|complete|deletemog onedrive ls|get|put|mkdir|rmmog config get|keys|set|unset|list|pathmog completion <shell>
Mail:
mog mail list --max 50 --query "from:alerts@example.com"
mog mail get <message-id>
mog mail send --to dev@contoso.com --subject "Deploy complete" --body "Finished."
mog mail send --to dev@contoso.com --subject "Re: Deploy complete" --quote <message-id>
mog mail send --to dev@contoso.com --subject "Deploy complete" --body "Finished." --dry-runCalendar:
mog calendar list --from 2026-02-12 --to 2026-02-19 --max 100
mog calendar create \
--subject "Planning" \
--start "2026-02-13T16:00:00-08:00" \
--end "2026-02-13T16:30:00-08:00" \
--body "Weekly sync"
mog calendar delete <event-id> --dry-runContacts:
mog contacts list --max 100
mog contacts create --display-name "Jane Doe" --email "jane@contoso.com"
mog contacts create \
--display-name "Jane Doe" \
--email "jane@contoso.com" \
--org "Contoso" \
--title "Program Manager" \
--url "https://contoso.example/jane" \
--note "Customer success lead" \
--custom region=NA \
--custom team=platform
mog contacts update <contact-id> --title "Director" --custom region=EMEAGroups:
mog groups list --max 100
mog groups members <group-id> --max 100Tasks:
mog tasks lists
mog tasks list --list <list-id> --max 100
mog tasks create --list <list-id> --title "Follow up"
mog tasks complete --list <list-id> --task <task-id>OneDrive:
mog onedrive ls --path / --max 100
mog onedrive put ./report.pdf --path /Reports/report.pdf
mog onedrive get /Reports/report.pdf --out ./report.pdf
mog onedrive mkdir --path /Reports/Archive
mog onedrive rm --path /Reports/old-report.pdf
mog onedrive rm --path /Reports/old-report.pdf --dry-runIf mog onedrive get is run without --out, files are saved under the local onedrive-downloads directory in your mogcli config path.
App-only target user override (mail/contacts/onedrive):
mog mail list --user user@contoso.com --max 20
mog onedrive ls --user user@contoso.com --path /Most list commands support --page to resume from a next-page token.
mog groups list --max 50 --json
mog groups list --page "<next-token-url>"--next-token is also accepted as an alias for pagination resume flags where supported.
Output modes:
--json: structured output for tooling.--plain: stable tab-separated output for shell scripts.
Examples:
mog mail list --json | jq '.messages[0]'
mog tasks list --list <list-id> --plainShow config path:
mog config pathShow editable config keys:
mog config keysCurrent keys:
timezonekeyring_backend
Profile metadata is stored in config. Tokens and secrets are stored via keychain/keyring backends.
keyring_backend supports auto, keychain, and file.
auto: use native OS keychain when available, otherwise file backend.keychain: require native OS keychain support.file: store under the local mogcli keyring directory.
MOG_KEYRING_PASSWORD is treated as explicitly configured even when empty, so headless runs do not implicitly prompt for keyring passwords.
No active profile:
mog auth accounts
mog auth use <profile>Refresh delegated login:
mog auth login --profile <profile> --audience enterprise --client-id <id> --scope-workloads mail,calendar,contacts,tasks,onedriveLogout and reset profile auth state:
mog auth logout --profile <profile>Verbose mode:
mog --verbose mail listgo test ./...
go run ./cmd/mog --helpAdditional project docs are in docs/.
MIT