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

carly-ai

v0.3.0

Published

Agent-native CLI and MCP server for Carly — the AI scheduling assistant. Read bookings, booking pages, event types, and slots from any MCP-compatible client or shell.

Downloads

638

Readme

carly-cli

License: MIT

Agent-native CLI and MCP server for Carly — the AI scheduling assistant. Read and manage booking pages, event types, calendars, and bookings from your shell or any MCP-compatible client.

11 tools across 5 resource groups. Same command definitions drive the CLI and the MCP server, so there is no drift between human and agent interfaces.

Install

npm install -g carly-ai

Or run from source:

git clone https://github.com/shirschfield/carly-cli.git
cd carly-cli
npm install && npm run build
npm link       # exposes `carly` on PATH

Quick start

Brand new user? Sign up from the CLI — it opens the OAuth consent page in your browser, connects your calendar, and you land back in the dashboard. Then mint an API key and run carly login.

carly signup                  # opens Google OAuth (use --with microsoft for Outlook)
# ... approve in browser, then:
carly login                   # paste the API key you minted at /booking-pages (expand "Generate API key")

Already have a Carly account?

# 1. Authenticate (interactive — saves to ~/.carly-cli/config.json)
carly login

# 2. Confirm the key works
carly profile whoami --pretty

# 3. See what you have
carly calendars list --output table
carly booking-pages list --output table
carly bookings list --output table

Connect additional calendars / video providers

carly calendars connect google       # Google Calendar (also handles first-time signup)
carly calendars connect microsoft    # Outlook calendar + Teams meetings
carly calendars connect zoom         # Zoom (for video-only; requires existing Carly account)

Each command opens the dashboard's OAuth page in your browser. No tokens touch the CLI.

Authentication

Resolved in priority order:

| # | Method | Example | |---|--------|---------| | 1 | --api-key flag | carly --api-key carly_live_xxxx profile whoami | | 2 | CARLY_API_KEY env var | export CARLY_API_KEY=carly_live_xxxx | | 3 | Config file | carly login writes ~/.carly-cli/config.json (mode 0600) |

Base URL defaults to https://dashboard.carlyassistant.com and can be overridden with --api-base-url or CARLY_API_BASE_URL.

Mint a key at <base-url>/booking-pages → expand Generate API key (under "Use Carly from your terminal or AI agent"). Scopes are enforced server-side; see Scopes below.

MCP server setup

carly mcp starts an MCP server over stdio that exposes every CLI command as a tool to any MCP-compatible client.

Claude Code

claude mcp add carly -- carly mcp
# or, before `npm link`:
claude mcp add carly -- node /path/to/carly-cli/dist/mcp.js

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "carly": {
      "command": "carly",
      "args": ["mcp"],
      "env": {
        "CARLY_API_KEY": "carly_live_xxxx"
      }
    }
  }
}

Cursor

Add to .cursor/mcp.json:

{
  "mcpServers": {
    "carly": {
      "command": "carly",
      "args": ["mcp"],
      "env": {
        "CARLY_API_KEY": "carly_live_xxxx"
      }
    }
  }
}

Command reference

Auth + utility

carly login                     # Interactive API key setup
carly logout                    # Remove stored credentials
carly auth-status               # Show current auth resolution
carly mcp                       # Start MCP server (stdio)
carly profile whoami            # Confirm identity + key validity

Calendars

carly calendars list            # Connected calendars (provider + account + key)

Use calendar_key values from this list as the --calendar-key argument when creating/updating booking pages.

Booking pages (5 commands)

carly booking-pages list
carly booking-pages get <event-type-id>

carly booking-pages create --title <title> [options]
  --slug <slug>                 # URL slug (e.g. "15min")
  --description <text>
  --duration <min>              # Meeting length (default 30)
  --location <loc>              # Physical location or URL
  --video-provider <name>       # google_meet, teams, zoom, ...
  --calendar-key <key>          # From `carly calendars list`
  --timezone <tz>               # IANA TZ (e.g. America/New_York)
  --username <username>         # Profile username (lowercase)
  --display-name <name>
  --event-name-template <tpl>
  --min-notice-minutes <n>      # Default 120
  --max-days-ahead <n>          # Default 60
  --before-event-buffer <min>
  --after-event-buffer <min>
  --slot-interval <min>
  --availability <json>         # [{"days":[1,2,3,4,5],"start_time":"09:00","end_time":"17:00"}]
  --custom-questions <json>     # [{"label":"Company","type":"text","required":true}]
  --duration-options <list>     # CSV (15,30,60) or JSON array ([15,30,60])

carly booking-pages update <event-type-id> [options]   # Same flags as create, all optional
  --is-active <true|false>      # Enable or disable the page

carly booking-pages delete <event-type-id>             # Soft-delete: sets is_active=false. Re-activate with `update <id> --is-active true`.

Nested-field notes:

  • --availability days are numbered Sunday=0, Monday=1, …, Saturday=6. Times are HH:MM in the page's timezone.
  • --custom-questions type is one of text, textarea, number, phone, email, select, checkbox, radio, boolean. options is only required for select/radio.
  • On update, any nested field you pass replaces the previous value wholesale — there is no partial merge.
  • MCP callers may pass these as native arrays/objects instead of stringified JSON.

Event types

carly event-types list                          # Caller's own event types
carly event-types list --username <username>    # Public active event types for a profile

Slots

carly slots list --event-type-id <id> --start-time <iso> --end-time <iso> [--duration <min>]

# or, public access via profile+slug:
carly slots list --username <username> --event-type-slug <slug> \
  --start-time <iso> --end-time <iso>

Bookings

carly bookings list [options]
  --status <status>             # accepted, cancelled, rescheduled, ...
  --event-type-id <id>
  --limit <n>                   # 1–1000, default 100
  --start-time <iso>
  --end-time <iso>

carly bookings get <uid>

bookings:write (create, cancel, reschedule) is intentionally not exposed on this CLI or the MCP surface; use the web dashboard.

Output formats

Every data-returning command accepts these global/per-command flags:

| Flag | Behavior | |------|----------| | --output json (default) | Single-line JSON to stdout | | --output pretty | Pretty-printed JSON | | --pretty | Shortcut for --output pretty | | --output table | Fixed-width table; columns come from the command's defaultColumns (or scalar keys of the first row) | | --fields <a,b,c> | Narrow JSON keys; override table columns | | --quiet | Suppress stdout (exit code only) |

Table mode flattens Carly's {items: [...]} envelope and the {slots: {date: [...]}} map automatically. For single-object responses (e.g. bookings get), table mode falls back to pretty JSON with a note on stderr.

# Default compact JSON
carly bookings list

# Human-friendly table
carly bookings list --output table

# Just the columns you care about
carly bookings list --output table --fields uid,status,start_time

# Pretty JSON with a field filter
carly bookings list --fields uid,status,start_time --pretty

Scopes

| Scope | Needed for | |-------|------------| | booking_pages:read | calendars list, booking-pages list/get, event-types list (own), slots list (own event type) | | booking_pages:write | booking-pages create/update/delete | | bookings:read | bookings list, bookings get |

bookings:write is not accepted when minting new keys and is not surfaced on this CLI or the MCP server. Existing keys that were minted with it still authenticate, but no write paths are wired up for bookings.

Architecture

src/
├── index.ts                 # CLI entry (Commander.js)
├── mcp.ts                   # MCP entry (re-exports server.ts)
├── core/
│   ├── types.ts             # CommandDefinition — single source of truth
│   ├── client.ts            # CarlyClient (fetch + retry/backoff)
│   ├── auth.ts              # Flag → env → config resolution
│   ├── config.ts            # ~/.carly-cli/config.json (mode 0600)
│   ├── handler.ts           # executeCommand (path/query/body routing)
│   ├── output.ts            # json | pretty | table renderer + --fields
│   └── errors.ts            # AuthError, NotFoundError, RateLimitError, ...
├── commands/
│   ├── index.ts             # allCommands registry + Commander wiring
│   ├── auth/                # login, logout, auth-status
│   ├── profile/             # whoami
│   ├── calendars/           # list
│   ├── booking-pages/       # list, get, create, update, delete
│   ├── event-types/         # list
│   ├── slots/               # list
│   └── bookings/            # list, get
└── mcp/
    └── server.ts            # Register every CommandDefinition as an MCP tool

Each CommandDefinition carries:

  • name — MCP tool name (e.g. booking_pages_update)
  • group / subcommand — CLI routing (e.g. carly booking-pages update)
  • inputSchema — Zod schema shared by CLI validation and MCP input schema
  • endpoint — HTTP method + path template (e.g. PATCH /booking-pages/{eventTypeId})
  • fieldMappings — per-field routing to path, query, or body
  • defaultColumns — optional; columns used by --output table
  • handler — executes via CarlyClient

Development

git clone https://github.com/shirschfield/carly-cli.git
cd carly-cli
npm install

# Hot reload via tsx (no build step)
npm run dev -- profile whoami --pretty
npm run dev -- bookings list --output table

# Typecheck only
npm run typecheck

# Production build
npm run build           # → dist/index.js + dist/mcp.js
npm link                # expose `carly` on PATH

To add a command:

  1. Author a CommandDefinition in src/commands/<group>/index.ts
  2. Export it from the group's *Commands array
  3. Include the group in src/commands/index.tsallCommands
  4. npm run build && carly <group> <subcommand> --help

Both the CLI and the MCP server pick it up automatically.

License

MIT