npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ms365-cli

v0.2.0

Published

CLI and MCP server for Microsoft 365 — Mail, Calendar, OneDrive, Contacts. JSON-first, AI-agent ready.

Readme

ms365-cli

Microsoft 365 in your terminal. Read and send email, manage calendar events, browse OneDrive, and search contacts — from a single command line.

JSON-first output. Every command doubles as an MCP tool. Built for humans, scripts, CI/CD pipelines, and AI agents.

npm install -g ms365-cli

What This CLI Enables

Mail — list inbox, read messages, send email, reply, search with KQL, move, and delete.

Calendar — list events, create meetings (including Teams), update, delete, and filter by date range.

OneDrive — browse files, search, get metadata, and delete items.

Contacts — list, search, get, and create Outlook contacts.

MCP Server — every command is available as a structured AI tool for Claude, Cursor, OpenClaw, or any MCP-compatible client.


Setup (5 minutes)

Step 1 — Install

npm install -g ms365-cli

Step 2 — Register an Azure AD App

You need a free Azure AD app to authenticate. This is a one-time setup.

  1. Go to portal.azure.com → App registrations
  2. Click New registration
    • Name: anything (e.g. ms365-cli)
    • Supported account types: Accounts in any organizational directory and personal Microsoft accounts
    • Redirect URI: Select Mobile and desktop applications → enter http://localhost
  3. Click Register — copy the Application (client) ID and Directory (tenant) ID
  4. Go to API permissions → Add a permission → Microsoft Graph → Delegated permissions
    • Search and add each: Mail.ReadWrite, Mail.Send, Calendars.ReadWrite, Files.ReadWrite, Contacts.ReadWrite, User.Read
    • Click Add permissions
  5. Click Grant admin consent for [your org] — all permissions should show a green checkmark
  6. Go to Authentication → Advanced settings → set Allow public client flows to YesSave

Step 3 — Login

m365 login --client-id <your-application-client-id> --tenant-id <your-directory-tenant-id>

This prints a URL and a code:

To sign in, use a web browser to open https://microsoft.com/devicelogin
and enter the code XXXXXXXX to authenticate.

Open the URL in a browser, enter the code, sign in with your Microsoft account. Done — tokens are cached at ~/.m365/token-cache.json and silently refreshed from then on.

Tip: Set env vars to avoid passing flags every time:

export M365_CLIENT_ID="your-client-id"
export M365_TENANT_ID="your-tenant-id"
m365 login

Step 4 — Verify

m365 status --pretty
# → {"authenticated":true,"account":"[email protected]",...}

m365 mail unread-count
# → {"folder":"Inbox","unread":4,"total":12}

You're in. All commands are now available.


Quick Start

# Check unread email
m365 mail unread-count

# Read inbox
m365 mail list --pretty

# Search for a message
m365 mail search "from:[email protected] subject:proposal"

# Send an email
m365 mail send --to [email protected] --subject "Hello" --body "Looking forward to connecting"

# Today's calendar
m365 calendar list --start $(date -u +%Y-%m-%dT00:00:00Z) --pretty

# Create a meeting
m365 calendar create \
  --subject "Discovery Call" \
  --start 2026-03-15T13:00:00 \
  --end 2026-03-15T14:00:00 \
  --timezone "America/New_York" \
  --attendees "[email protected]" \
  --online-meeting

# Browse OneDrive
m365 drive list --pretty

# Search files
m365 drive search "quarterly report"

Commands

Auth

m365 auth login [--client-id <id>] [--tenant-id <id>]
m365 auth logout
m365 auth status

Mail (8 commands)

m365 mail list [--top <n>] [--folder <name>] [--filter <odata>] [--select <fields>]
m365 mail get <id>
m365 mail send --to <emails> --subject <text> --body <text> [--cc] [--bcc] [--content-type html]
m365 mail reply <id> --body <text> [--reply-all]
m365 mail search <query>
m365 mail move <id> --destination <folder>
m365 mail delete <id>
m365 mail unread-count [--folder <name>]

Calendar (5 commands)

m365 calendar list [--start <iso>] [--end <iso>] [--top <n>] [--filter <odata>]
m365 calendar get <id>
m365 calendar create --subject <text> --start <iso> --end <iso> [--attendees <emails>] [--online-meeting]
m365 calendar update <id> [--subject] [--start] [--end] [--location]
m365 calendar delete <id>

Drive (4 commands)

m365 drive list [--folder-id <id>] [--top <n>]
m365 drive get <id> | --path <path>
m365 drive search <query>
m365 drive delete <id>

Contacts (4 commands)

m365 contacts list [--top <n>] [--filter <odata>]
m365 contacts get <id>
m365 contacts search <query>
m365 contacts create --given <name> [--surname] [--email] [--phone] [--company]

Output

All commands output compact JSON by default — pipe to jq, save to files, or feed to other tools.

# Pretty print
m365 mail list --pretty

# Filter with jq
m365 mail list --filter "isRead eq false" | jq '.value[] | {id, subject, from: .from.emailAddress.address}'

# Select specific fields
m365 mail list --select "id,subject,from,receivedDateTime"

# Quiet mode (exit code only)
m365 mail send --to [email protected] --subject "Hi" --body "Hey" --quiet

MCP Server

Every command is available as an MCP (Model Context Protocol) tool for AI assistants.

m365 mcp

Configure in Claude Desktop / Cursor

{
  "mcpServers": {
    "m365": {
      "command": "npx",
      "args": ["ms365-cli", "mcp"],
      "env": {
        "M365_CLIENT_ID": "your-azure-app-client-id"
      }
    }
  }
}

Configure for OpenClaw agents

# Symlink skills
ln -s $(pwd)/skills/m365-* ~/.openclaw/skills/

# Or install all at once
npx skills add https://github.com/bcharleson/ms365-cli

Agent Skills

Skills are SKILL.md files that teach AI agents how to use this CLI:

| Skill | Covers | |-------|--------| | skills/m365-mail/ | Read inbox, send, search, reply | | skills/m365-calendar/ | List events, create meetings, update | | skills/m365-drive/ | Browse, search, download files | | skills/m365-contacts/ | List, search, create contacts |


OpenClaw Agent Setup

To give an OpenClaw agent access to Microsoft 365, install ms365-cli on the agent's droplet and authenticate once. The agent can then call all commands via its exec tool.

1 — Install on the agent's server

npm install -g ms365-cli

2 — Authenticate as the agent's email account

# Run as the tofu service user
su - tofu -c 'm365 login --client-id <client-id> --tenant-id <tenant-id>'

Follow the device code prompt — open the URL in a browser, sign in as the agent's email account. Tokens are cached at ~/.m365/token-cache.json for the tofu user.

3 — Install skills into OpenClaw

# Symlink all ms365 skills (stays in sync with repo updates)
ln -s /path/to/ms365-cli/skills/m365-* ~/.openclaw/skills/

# Or copy specific skills
cp -r /path/to/ms365-cli/skills/m365-mail ~/.openclaw/skills/
cp -r /path/to/ms365-cli/skills/m365-calendar ~/.openclaw/skills/

4 — Add email instructions to the agent's SOUL.md

Add a section like this to the agent's SOUL.md so it knows how to use email:

## Email Access

You have full access to your Outlook inbox via the `m365` CLI. Use the `exec` tool.

### Check inbox
m365 mail unread-count
m365 mail list --filter "isRead eq false" --top 20 --pretty

### Send email
m365 mail send --to [email protected] --subject "Subject" --body "Body"

### Reply
m365 mail reply <message-id> --body "Your reply here"

### Search
m365 mail search "from:[email protected]"

5 — Test from the agent's Slack channel

Ask the agent:

"Check my email and tell me what's unread"

The agent will call m365 mail list --filter "isRead eq false" via exec and report back.


Re-authentication

Tokens are long-lived but will eventually expire. If the agent reports auth errors:

# Re-run login from the server
ssh root@<droplet-ip> "su - tofu -c 'm365 login --client-id <id> --tenant-id <id>'"
# Follow device code flow again

Tip for MFA accounts: Add the agent's email to your Microsoft Authenticator app so you can approve re-auth prompts without needing the client's help.


Development

git clone https://github.com/bcharleson/ms365-cli.git
cd ms365-cli
npm install
npm run dev -- auth status
npm run build
npm test
npm run typecheck

Architecture

Every API endpoint is a CommandDefinition object — one source of truth that powers both the CLI subcommand and the MCP tool:

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/        # 4 commands
│   └── contacts/     # 4 commands
└── mcp/
    └── server.ts     # MCP server (auto-registers all commands as tools)

Adding a new endpoint = one new file. It's automatically available in both CLI and MCP.


License

MIT

Inspired by