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

@a1-x-tech/mcp-google-auth

v0.1.0

Published

Reusable Google OAuth onboarding for the mcp-google-* MCP server line: in-chat login tools (loopback + PKCE) and a per-request TokenProvider.

Readme

@a1-x-tech/mcp-google-auth

Reusable Google OAuth onboarding for the mcp-google-* MCP server line. One package gives every server the in-chat login of the Yandex line — adapted to Google's rules: a loopback listener on 127.0.0.1 + PKCE (S256) instead of the dead OOB flow, a user-owned Desktop OAuth client (personal-use exemption — no verification, no CASA), and a set_client path so the client_secret never passes through the chat.

This is a library, not a server: it registers six MCP tools on your McpServer and hands back a TokenProvider your API client calls per request.

Usage

import { registerGoogleAuth, unconfiguredPrefix } from "@a1-x-tech/mcp-google-auth";

const options = {
  serverName: "calendar",                 // → ~/.config/mcp-google-calendar/credentials.json
  envPrefix: "GOOGLE_CALENDAR",           // → GOOGLE_CALENDAR_REFRESH_TOKEN, …
  scopes: ["https://www.googleapis.com/auth/calendar.events"],
  // verifyIdentity?: async (accessToken) => ({ email }),  // default: OIDC userinfo
  // defaultClient?: { clientId, clientSecret? },           // built-in A1 client slot
};

const provider = registerGoogleAuth(server, options);

// In your API client, per request:
const token = await provider.getAccessToken();
// On a 401 from the API — one re-mint + replay:
const fresh = await provider.getAccessToken(true);
// Before a tool that needs a specific scope (partial grants are stored, not rejected):
provider.assertScopes(["https://www.googleapis.com/auth/calendar.events"]);

// At startup, when provider.hasToken() is false, prepend to the initialize instructions:
const instructions = unconfiguredPrefix(options) + REGULAR_BRIEFING;

The component always adds openid + userinfo.email (non-sensitive) to scopes — that is how finish_login names the account even for APIs without an identity call.

Registered tools

| Tool | Hint | Purpose | |---|---|---| | auth_status | read-only | Connection state, token source, expiry, granted/missing scopes, paths. No network, no token in the output. | | setup_instructions | read-only | GCP wizard checklist (project → API → consent screen → Publish app → Desktop client → Download JSON). Shortens when a client already exists. | | set_client | write | Reads the downloaded client_secret_*.json by path, validates type installed, stores it in the shared client.json (0600). The secret never enters the chat. | | start_login | write, deliberately not read-only | Mints PKCE + state, binds a one-shot listener on 127.0.0.1 (random port or <PREFIX>_OAUTH_PORT), returns authorizeUrl + nextStep. Does not open the browser. A read-only hint would let a prompt injection start an OAuth flow silently. | | finish_login | write | Awaits the local code exchange, saves tokens atomically, verifies identity (server callback or userinfo), reports accountEmail, grantedScopes, missingScopes, previousAccountEmail on account change. | | logout | destructive | Revokes at oauth2.googleapis.com/revoke, deletes the file, reports envTokenStillSet. |

Credential sources

OAuth client (shared by the whole line), priority order:

  1. <PREFIX>_CLIENT_ID / <PREFIX>_CLIENT_SECRET (env override, e.g. CI)
  2. ~/.config/mcp-google-auth/client.json — written by set_client
  3. options.defaultClient — the built-in slot for the verified A1 client

The code exchange first runs without client_secret; if Google answers "client_secret is missing", it retries with the secret when one is on file, otherwise fails with set_client advice.

Tokens (per server), priority order:

  1. <PREFIX>_REFRESH_TOKEN (+ client) — minted in memory, never written to disk; <PREFIX>_ACCESS_TOKEN as a static testing alternative
  2. ~/.config/mcp-google-<serverName>/credentials.json — written by finish_login, re-read on every call (a mid-session login needs no restart)

Paths honor $XDG_CONFIG_HOME; on Windows the base is %APPDATA% (profile ACLs replace the 0600/0700 modes, renames retry on antivirus EPERM). Writes are atomic (temp file + rename); a broken file reads as "not connected".

Refresh: 60 s leeway, concurrent refreshes deduplicated, a rotated refresh_token is persisted immediately.

Security invariants (each pinned by a test)

  • No tool output or error ever contains access_token / refresh_token / client_secret / id_token (sentinel grep over the full test transcript).
  • The PKCE verifier never leaves the process; state is compared exactly; the listener binds 127.0.0.1 only, is one-shot, and the pending login dies after 10 minutes. The success page is static — no reflection, no external resources.
  • Missing credentials raise AuthRequiredError before any fetch; the message names both fixes (start_login, env variables).
  • OAuth failures map to actionable advice (redirect_uri_mismatch, access_denied, accessNotConfigured, invalid_scope, invalid_grant, invalid_client, admin_policy_enforced).
  • A partial consent grant is stored and reported, never rejected; an account change revokes the old refresh token best-effort and names the previous account.

Development

npm install
npm run typecheck   # types for src + tests
npm test            # node:test, no external network (loopback only)
npm run build       # emit dist/

@modelcontextprotocol/sdk is a peer dependency — the host server owns the SDK instance; only zod ships as a runtime dependency.

License

MIT