spoon-cli
v0.3.0
Published
A CLI tool to consume your Granola — query and sync Granola AI meeting notes via Granola's MCP server
Readme
spoon
a cli tool to consume your granola
spoon is an unofficial command-line interface for Granola AI meeting notes, built on Granola's public MCP server.
$ spoon meetings list --since "last week"
$ spoon query "What action items came out of this week's standups?"
$ spoon meetings get abc123 --format markdown
$ spoon sync ./meetingsDisclaimer: This project is not affiliated with, endorsed by, or supported by Granola AI. "Granola" is a trademark of its respective owner. This is an independent, community-built tool that uses Granola's publicly available MCP API.
Installation
npm install -g spoon-cliOr run without installing:
npx spoon-cli --helpRunning from source
Clone the repo and run directly without publishing to npm:
git clone https://github.com/MadSkills-io/spoon-cli.git
cd spoon-cli
pnpm install
pnpm build
node dist/index.js --helpTo use spoon as a global command from your local checkout:
pnpm link --global
spoon --helpTo unlink later:
pnpm unlink --global spoon-cliAuthentication
Granola uses OAuth 2.1. Run this once to authenticate:
spoon auth loginYour browser will open for sign-in. The token is stored in ~/.spoon/credentials.json and refreshes automatically.
spoon auth status # check authentication state
spoon auth logout # revoke and clear credentialsCI / headless environments: Set GRANOLA_TOKEN=<token> to skip the OAuth flow entirely.
Commands
spoon meetings list
List your meetings.
Options:
--since <date> Show meetings since date (ISO 8601 or natural language)
--until <date> Show meetings until date (ISO 8601 or natural language)
--attendee <name> Filter by attendee name or email
--limit <n> Cap the number of results (default: all meetings in range)
--format <format> json | table | csv | markdown | textspoon meetings list
spoon meetings list --since "last week"
spoon meetings list --since 2024-01-01 --until 2024-02-01
spoon meetings list --attendee "Sarah" --limit 5
spoon meetings list --since "2 days ago" --format csv
# Pipe to jq
spoon meetings list --format json | jq '.[].title'
spoon meetings list --format json | jq '.[0].id'spoon meetings get <id>
Get the full content of a meeting by ID.
Options:
--no-private Exclude private notes
--no-enhanced Exclude AI-enhanced notes
--format <format> json | table | csv | markdown | textspoon meetings get abc123
spoon meetings get abc123 --format markdown
spoon meetings get abc123 --no-private --format json
# Pipe a meeting ID from list
spoon meetings list --format json | jq -r '.[0].id' | xargs spoon meetings getspoon meetings transcript <id>
Get the raw word-for-word transcript of a meeting. Requires a Granola paid plan.
spoon meetings transcript abc123
spoon meetings transcript abc123 --format jsonspoon query "<question>"
Ask a natural language question across all your meetings.
Options:
--format <format> json | table | textspoon query "What action items came out of this week's standups?"
spoon query "What did Sarah say about the Q4 roadmap?"
spoon query "Summarize all meetings from last week"
spoon query "Who mentioned the budget?" --format jsonspoon sync <output-dir>
Mirror Granola meeting notes and transcripts to a local directory as Markdown files with YAML front-matter. Supports incremental sync — only fetches meetings since the last run. Shows a live progress bar in interactive terminals.
Options:
--since <date> Override incremental sync; start from this date
--until <date> Only sync meetings up to this date
--force Re-sync all meetings (ignores last-run state)
--transcripts Also fetch transcripts (see rate limit warning below)
--no-private Exclude private notes from meeting files
--batch-size <n> IDs per get_meetings call (default: 5)
--delay <ms> Delay between MCP calls in ms (default: 1000)
--dry-run List meetings that would sync, don't write files
--format <fmt> Progress output format: text, jsonTranscript rate limit: The Granola API enforces a hard limit of approximately 2 transcript calls per 7-minute window. Transcripts are therefore opt-in via
--transcriptsand are not fetched by default. For large syncs, fetch meeting notes first and transcripts separately in small batches.
# Sync all meeting notes (no transcripts — fast, no rate limiting)
spoon sync ./meetings
# Sync only meetings from last week
spoon sync ./meetings --since "last week"
# Sync a specific date range
spoon sync ./meetings --since "2025-12-01" --until "2026-01-31"
# Preview what would be synced
spoon sync ./meetings --dry-run
# Re-sync everything, overwriting existing files
spoon sync ./meetings --force
# Also fetch transcripts (slow — will hit rate limits on more than ~2 meetings)
spoon sync ./meetings --transcripts --since "today"
# Exclude private notes
spoon sync ./meetings --no-privateOutput layout:
meetings/
_unfiled/ # meetings with no folder
2024-01-16-standup-abc12345.md
2024-01-16-standup-abc12345.transcript.md
Planning/ # one dir per Granola folder
2024-01-15-q1-planning-session-def67890.md
2024-01-15-q1-planning-session-def67890.transcript.mdFilenames use the pattern YYYY-MM-DD-title-SHORTID where SHORTID is the last 8 characters of the meeting's unique ID. This ensures multiple meetings with the same title on the same day never overwrite each other.
Meeting files contain YAML front-matter (id, title, date, attendees, folders) followed by Summary, Notes, and Private Notes sections. Transcript files contain speaker-attributed, timestamped dialogue.
Sync state is persisted at ~/.spoon/sync-state.json — running sync again only fetches new meetings.
spoon mcp
Inspect and interact with the MCP server directly. Power-user commands for protocol-level introspection.
# Health check — measure round-trip latency
spoon mcp ping
# Server version, capabilities, and instructions
spoon mcp info
spoon mcp info --format json
# List all available tools with schemas
spoon mcp tools
spoon mcp tools --format json
# Call any tool by name with raw JSON arguments
spoon mcp call list_meetings '{"time_range":"this_week"}'
spoon mcp call list_meetings '{"time_range":"this_week"}' --format json
spoon mcp call get_meeting_transcript '{"meeting_id":"abc123"}'
# Pipe JSON args from stdin
echo '{"time_range":"this_week"}' | spoon mcp call list_meetings
# List resources and prompts (gracefully handles unsupported)
spoon mcp resources
spoon mcp promptsThe call subcommand returns raw server output — no XML parsing or JSON unwrapping — so you see exactly what the MCP server returns.
spoon config
Show the current configuration and file paths.
spoon config
spoon config --format jsonOutput Formats
Output format is auto-detected based on context:
| Context | Default format |
|---------|---------------|
| Interactive terminal (TTY) | table / text with colors |
| Piped / redirected | json |
| --format flag | Always overrides |
Available formats for most commands: json, table, csv, markdown, text.
# Human-readable in terminal
spoon meetings list
# JSON for scripting
spoon meetings list --format json | jq '.[].title'
# CSV for spreadsheets
spoon meetings list --format csv > meetings.csv
# Markdown for notes
spoon meetings get abc123 --format markdown > meeting.mdExit Codes
| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | General error |
| 2 | Authentication error |
| 3 | Rate limited |
| 4 | Not found |
Errors are written to stderr — as JSON when piped, colored text when interactive:
# Structured error on stderr when piped
spoon meetings list 2>&1 | jq .error
# → "auth_error"Environment Variables
| Variable | Description |
|----------|-------------|
| GRANOLA_TOKEN | Bearer token — skips OAuth entirely (useful for CI) |
| NO_COLOR | Disable colored output (no-color.org) |
GRANOLA_TOKEN=eyJ... spoon meetings listScripting & AI Agent Usage
spoon outputs JSON when piped, making it easy to compose with other tools:
# Get all meeting IDs from last week
spoon meetings list --since "last week" --format json | jq -r '.[].id'
# Export a meeting to markdown
spoon meetings get abc123 --format markdown > standup-2024-01-15.md
# Find action items across all recent meetings
spoon query "What are all the open action items?" | grep -i "TODO"
# Use in a shell script
ID=$(spoon meetings list --format json | jq -r '.[0].id')
spoon meetings transcript "$ID" --format json > transcript.json
# Mirror all meetings to local Markdown files
spoon sync ~/spoon-backup
# Incremental backup (only new meetings since last run)
spoon sync ~/spoon-backup --since "last week"AI agents can discover all commands from spoon --help with zero token overhead — no MCP tool definitions needed.
Data & Credentials
All credentials and config are stored in ~/.spoon/:
~/.spoon/
├── credentials.json # Access + refresh tokens (chmod 0600)
├── client.json # OAuth client registration (cached)
├── config.json # CLI preferences
├── discovery.json # OAuth server metadata (cached)
└── sync-state.json # Incremental sync state (last run, synced meeting IDs)Requirements
- Node.js 20+
- A Granola account
License
MIT
