MCP server for semantic search across Granola meeting notes.
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
Sync (Recommended)
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
Tools (7)
searchSemantic search across meetings, returns summaries + quotessearch_themesFind documents by theme (pain-points, feature-requests, etc.)list_foldersList all folders with document countslist_documentsList documents with brief summariesget_documentGet full document details (all themes + quotes)get_transcriptGet raw transcript (use sparingly)get_themesList available themes with definitionsEnvironment Variables
OPENAI_API_KEYrequiredFor embeddings and insight extractionGRANOLA_DATA_DIRrequiredPath to the exported Granola data directoryConfiguration
{
"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-..."
}
}
}
}