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

@bold-tech-npm/graph-mcp

v0.6.0

Published

Microsoft Graph MCP server with device-code auth and smart inbox reads (unread + date filter, thread collapse by conversation or normalized subject). By Bold Tech.

Readme

@bold-tech-npm/graph-mcp

A small MCP server that exposes Microsoft Graph (Outlook) to an AI client, with two things most Graph connectors get wrong:

  • Device-code auth — no client secret, no redirect URI. The signed-in user consents in a browser; the server acts as that user (delegated, security-trimmed), so it only ever sees what they're permitted to see.
  • Smart inbox reads — an overnight burst of long, multi-message threads is collapsed to one item per thread (by conversationId or normalized subject), with unread and date-window filters, so the model gets a clean list instead of a confusing pile.

Configuration is entirely via environment variables, so one published package serves many tenants/clients.

Configure

| Env var | Required | Default | Notes | |---|---|---|---| | GRAPH_CLIENT_ID | ✅ | — | Entra app registration (public client, device-code enabled) | | GRAPH_TENANT_ID | ✅ | — | Tenant GUID for a single-tenant app, or organizations for a multi-tenant one (see below) | | GRAPH_SCOPES | | User.Read,Mail.Read | Add Mail.ReadWrite to enable draft tools | | GRAPH_TOKEN_CACHE | | ~/.bold-tech/graph-mcp/<tenant>/tokens.json | Token cache | | GRAPH_ACCOUNT | | — | Pin which signed-in account to run as, by username. Only needed when several are cached | | GRAPH_ACTIVE_ACCOUNT | | next to the cache | Pointer file recording the account connect last signed in as |

Multi-tenant: one app, many mailboxes

GRAPH_TENANT_ID is interpolated straight into the authority, so:

  • a tenant GUID → single-tenant. Only that directory's users can sign in.
  • organizations → multi-tenant. Any work/school account can sign in, provided the app registration is set to AzureADMultipleOrgs and the target tenant has consented. (common also works but additionally allows personal Microsoft accounts — usually not what you want.)

Multi-tenant makes "which mailbox am I?" a real question, because one cache directory now holds accounts from different tenants — a test mailbox and a customer's, say. Getting that wrong doesn't error; it produces confident output built on the wrong inbox. So account selection is explicit, in this order:

  1. GRAPH_ACCOUNT, if set — errors if that user isn't signed in.
  2. The account connect last signed in as (recorded in the pointer file).
  3. The only cached account, if there's exactly one.
  4. Otherwise it refuses and lists the candidates — it will not pick for you.

To switch accounts, call connect again and sign in as the other user; the pointer follows.

Note: the cache path contains <tenant>, so changing GRAPH_TENANT_ID (e.g. a GUID → organizations) points at a different directory and everyone signs in once more.

Sign in

Preferred — in-conversation (no terminal): the AI client calls the connect tool, which returns a verification URL + code; the user opens it, signs in, and auth_status confirms. Nothing to run in a shell. This is the flow to use inside a plugin.

Alternative — CLI (for scripts/CI):

GRAPH_CLIENT_ID=… GRAPH_TENANT_ID=… npx -y @bold-tech-npm/graph-mcp login

Either way, tokens cache per-tenant, so multiple clients coexist on one machine.

Use from an MCP client / plugin

{
  "mcpServers": {
    "graph": {
      "command": "npx",
      "args": ["-y", "@bold-tech-npm/graph-mcp"],
      "env": {
        "GRAPH_CLIENT_ID": "…",
        "GRAPH_TENANT_ID": "…",
        "GRAPH_SCOPES": "User.Read,Mail.ReadWrite"
      }
    }
  }
}

Tools

| Tool | Scope | Description | |---|---|---| | connect | — | Start/confirm sign-in; returns a verification URL + code (or "connected") | | auth_status | — | Sign-in status: connected / pending (URL + code) / not_connected | | whoami | User.Read | The signed-in user (proves the auth chain) | | inbox_list | Mail.Read | Inbox messages with unread/date filters and thread collapse | | create_draft | Mail.ReadWrite | Create an email draft (never sends) | | create_reply_draft | Mail.ReadWrite | Reply-draft into an existing thread (never sends) |

Draft tools require Mail.ReadWrite in GRAPH_SCOPES; with a read-only token they return a clear permission error rather than failing silently.