Skip to main content
Glama

granola-mcp

MCP server for semantic search across Granola meeting notes. Extracts insights, themes (pain-points, feature-requests, decisions, etc.), and key quotes with speaker attribution. Uses LanceDB for fast local vector search.

Based on reverse engineering research by Joseph Thacker and getprobo.

Features

  • Export: Extract all your Granola meetings with transcripts

  • Semantic Search: Vector-indexed search across meetings with pre-extracted insights

  • Speaker Attribution: Distinguishes between host (me) and participants

  • Theme Extraction: Auto-categorizes content into themes (pain-points, feature-requests, etc.)

  • MCP Server: Exposes search to Claude Code, Claude Desktop, and other AI tools

Prerequisites

  • Node.js 18+

  • Granola desktop app installed and logged in

  • OpenAI API key (for embeddings and insight extraction)

Installation

npm install npm run build

Quick Start

# One command to sync everything (export + index) OPENAI_API_KEY=sk-... node dist/index.js sync # Or with a custom data directory OPENAI_API_KEY=sk-... node dist/index.js sync ./my-data # Test search OPENAI_API_KEY=sk-... node dist/index.js search "user pain points"

CLI Commands

The easiest way to keep your data up to date - exports from Granola and rebuilds the index in one step:

OPENAI_API_KEY=sk-... node dist/index.js sync # With options OPENAI_API_KEY=sk-... node dist/index.js sync ./my-data OPENAI_API_KEY=sk-... node dist/index.js sync --skip-extraction # Faster, reuses existing insights

Export from Granola

Export only (without indexing):

node dist/index.js export ./output node dist/index.js export ./output --format markdown node dist/index.js export ./output --format json

Build Search Index

# Full indexing with insight extraction (~$0.02/document) OPENAI_API_KEY=sk-... node dist/index.js index ./export # Skip extraction (use existing insights, just rebuild embeddings) OPENAI_API_KEY=sk-... node dist/index.js index ./export --skip-extraction

Search from CLI

OPENAI_API_KEY=sk-... node dist/index.js search "pricing concerns" OPENAI_API_KEY=sk-... node dist/index.js search "feature requests" --folder "User interviews"

Export for ChatGPT

OPENAI_API_KEY=sk-... node dist/index.js export-combined ./chatgpt.md OPENAI_API_KEY=sk-... node dist/index.js export-combined ./chatgpt.md --query "user feedback"

Other Commands

node dist/index.js list # List documents node dist/index.js workspaces # List workspaces node dist/index.js folders # List folders node dist/index.js transcript <id> # Get specific transcript

MCP Server Setup

Claude Code

Add to .mcp.json in your project:

{ "mcpServers": { "granola": { "type": "stdio", "command": "node", "args": ["/path/to/granola-mcp/dist/mcp/server.js"], "env": { "GRANOLA_DATA_DIR": "/path/to/granola-mcp/export", "OPENAI_API_KEY": "sk-..." } } } }

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{ "mcpServers": { "granola": { "command": "node", "args": ["/path/to/granola-mcp/dist/mcp/server.js"], "env": { "GRANOLA_DATA_DIR": "/path/to/granola-mcp/export", "OPENAI_API_KEY": "sk-..." } } } }

MCP Tools

Tool

Description

search

Semantic search across meetings, returns summaries + quotes

search_themes

Find documents by theme (pain-points, feature-requests, etc.)

list_folders

List all folders with document counts

list_documents

List documents with brief summaries

get_document

Get full document details (all themes + quotes)

get_transcript

Get raw transcript (use sparingly)

get_themes

List available themes with definitions

Speaker Attribution

The system distinguishes between speakers:

  • speaker: "me" - The meeting host (you)

  • speaker: "participant" - Other people in the meeting

This helps AI understand what's your own idea vs external feedback.

Pre-defined Themes

  • pain-points: User frustrations, problems, complaints

  • feature-requests: Desired features, wishlist items

  • positive-feedback: What users liked, praised

  • pricing: Cost concerns, value perception

  • competition: Competitor mentions, alternatives

  • workflow: How users currently do things

  • decisions: Key decisions made, action items

  • questions: Open questions needing clarification

Output Structure

export/ ├── vectors.lance/ # LanceDB vector index ├── Meeting_Title_1/ │ ├── document.json # Raw document data │ ├── notes.md # Converted notes │ ├── transcript.json # Raw transcript with speaker info │ ├── transcript.md # Formatted transcript │ └── transcript.txt # Plain text transcript └── Meeting_Title_2/ └── ...

Keeping Data Updated

The system doesn't auto-sync with Granola. Run sync manually after new meetings, or set up a cron job:

Manual Update

OPENAI_API_KEY=sk-... node dist/index.js sync

Automated Updates (Cron)

Add to your crontab (crontab -e):

# Sync every night at 2am 0 2 * * * cd /path/to/granola-mcp && OPENAI_API_KEY=sk-... /usr/local/bin/node dist/index.js sync >> /tmp/granola-sync.log 2>&1 # Or every 6 hours 0 */6 * * * cd /path/to/granola-mcp && OPENAI_API_KEY=sk-... /usr/local/bin/node dist/index.js sync >> /tmp/granola-sync.log 2>&1

macOS LaunchAgent

Create ~/Library/LaunchAgents/com.granola-mcp.sync.plist:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.granola-mcp.sync</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/node</string> <string>/path/to/granola-mcp/dist/index.js</string> <string>sync</string> </array> <key>EnvironmentVariables</key> <dict> <key>OPENAI_API_KEY</key> <string>sk-...</string> </dict> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>2</integer> <key>Minute</key> <integer>0</integer> </dict> <key>StandardOutPath</key> <string>/tmp/granola-sync.log</string> <key>StandardErrorPath</key> <string>/tmp/granola-sync.log</string> </dict> </plist>

Load it with: launchctl load ~/Library/LaunchAgents/com.granola-mcp.sync.plist

How It Works

  1. Export: Reads credentials from ~/Library/Application Support/Granola/supabase.json and fetches all documents via Granola's API

  2. Index:

    • Extracts themes and key quotes using GPT-4o-mini

    • Generates embeddings using text-embedding-3-small

    • Stores in LanceDB for fast vector search

  3. Search:

    • Embeds your query

    • Finds semantically similar documents

    • Returns summaries + relevant quotes (not raw transcripts)

Cost Estimates

Documents

Insight Extraction

Embeddings

Total

25

~$0.50

~$0.01

~$0.51

100

~$2.00

~$0.02

~$2.02

500

~$10.00

~$0.10

~$10.10

Search queries are free (vector similarity, no LLM calls).

License

MIT

-
security - not tested
A
license - permissive license
-
quality - not tested

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mishkinf/granola-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server