chrisguillory/granola-mcp
If you are the rightful owner of granola-mcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
Granola MCP Server provides access to Granola meeting notes and data via Claude Code.
Granola MCP Server
MCP server for accessing Granola meeting notes and data via Claude Code.
API Research Findings
Authentication
Granola uses WorkOS OAuth tokens stored locally:
- Location:
~/Library/Application Support/Granola/supabase.json - Format: JSON file with
workos_tokensfield (JSON string) - Token fields:
access_token,refresh_token,expires_in,session_id - Auth method: Bearer token in Authorization header
Available API Endpoints
Documents endpoint: POST https://api.granola.ai/v2/get-documents
- Parameters:
limit(int),offset(int),include_last_viewed_panel(bool) - Returns:
{"docs": [...]} - Pagination: Use offset for additional results
- Note:
notesandnotes_markdownfields often empty for newer meetings
Document panels endpoint: POST https://api.granola.ai/v1/get-document-panels
- Parameters:
document_id(str) - Returns: Array of panels with AI-generated content
- Each panel:
id,title,content(ProseMirror JSON),template_slug, timestamps - Primary panel:
template_slug: "v2:meeting-summary-consolidated" - Contains the actual AI-generated meeting notes
Transcript endpoint: POST https://api.granola.ai/v1/get-document-transcript
- Parameters:
document_id(str) - Returns: Array of transcript segments with timestamps
- Each segment:
document_id,id,start_timestamp,end_timestamp,text,source,is_final - Source values: "microphone" (user) or "system" (other party)
Headers required:
Authorization: Bearer {access_token}
Content-Type: application/json
Document Structure
Each document contains:
id(str): Unique document identifiertitle(str | None): Meeting titlecreated_at(str): ISO timestampupdated_at(str): ISO timestampnotes(dict): ProseMirror JSON format (AI-generated notes)notes_markdown(str | None): Markdown version of notespeople(dict): Meeting participantsgoogle_calendar_event(dict | None): Calendar metadatatranscribe(bool): Whether transcript was enabledtype(str): Usually "meeting"
ProseMirror Format
Notes are stored in ProseMirror JSON:
{
"type": "doc",
"content": [
{
"type": "heading",
"attrs": {"level": 3, "id": "..."},
"content": [{"type": "text", "text": "..."}]
},
{
"type": "bulletList",
"attrs": {"tight": true},
"content": [...]
}
]
}
What Works
✅ Search/list all meetings with pagination and optional filtering ✅ AI-generated meeting notes via panels endpoint (ProseMirror→Markdown) ✅ Meeting metadata (title, date, participants) ✅ Download notes with structural metadata (sections, bullets, word count) ✅ Raw meeting transcripts with timestamps and speaker attribution ✅ Download transcripts with metadata (duration, speaker breakdown)
What Doesn't Work
❌ Individual document GET endpoints (404 errors) ❌ Separate chapters endpoints (404 errors)
Note: Granola's API is private and undocumented. All endpoints discovered through reverse engineering.
Future Enhancements
The following features may be supported by the Granola API but are not yet implemented:
- Advanced filtering: Filter by date ranges, meeting status, or custom metadata
- Sorting: Specify sort order (e.g., by date, title, or last modified)
- Type filtering: Filter by document/meeting type
- Tag filtering: Filter meetings by attached tags or labels
- Archived meetings: Include or exclude archived meetings
- User filtering: Restrict results to specific user(s)
These parameters would be added to the search_meetings tool once the Granola API documentation becomes available or through further reverse engineering.
Installation
# Add to Claude Code MCP config (user scope)
claude mcp add --scope user --transport stdio granola -- uv run --script ~/granola-mcp/granola-mcp.py
Available Tools
Discovery & Organization
search_meetings: Search/list meetings with optional query, list filter, and pagination. When query is omitted, returns all meetings. Supports filtering by title keyword (case-insensitive) and by list ID (server-side filtering). Parameters:query,list_id,limit,offset.get_meeting_lists: Get all meeting lists/collections with their document IDs. Returns lists with metadata including which meetings belong to each list.get_meetings: Fetch multiple specific meetings by document IDs (batch retrieval). Parameter:document_ids(list of strings). Useful for fetching all meetings in a list at once.
Download Tools
download_note: Download AI-generated meeting notes to a temporary Markdown file. Uses/v1/get-document-panelsendpoint. Returns metadata (section count, bullet count, heading breakdown, word count, panel title). Files are auto-cleaned on server shutdown. (Produces markdown identical to Granola's official export)download_private_notes: Download user's private notes to a temporary Markdown file. Uses/v2/get-documentsendpoint to fetchnotes_markdownfield. Returns metadata (word count, line count). Files are auto-cleaned on server shutdown. (Produces markdown identical to Granola's official export)download_transcript: Download meeting transcript to a temporary Markdown file. Returns metadata (segment count, duration, speaker breakdown). Combines consecutive segments from same speaker. Files are auto-cleaned on server shutdown. (Produces markdown identical to Granola's official export)
Management Tools (Write Operations)
list_deleted_meetings: List all deleted meeting document IDs. Returns IDs that can be used withundelete_meeting()to restore meetings. Uses/v2/get-documentsendpoint to access the 'deleted' array.delete_meeting: Delete a meeting by setting itsdeleted_attimestamp. Deleted meetings don't appear in search results and appear in the 'deleted' array of API responses. Can be fully restored usingundelete_meeting(). Uses/v1/update-documentendpoint. Parameter:document_id.undelete_meeting: Restore a deleted meeting by clearing itsdeleted_attimestamp. Undeleted meetings are fully restored and appear in search results again with all original data intact. Uses/v1/update-documentendpoint. Parameter:document_id.
Implementation Notes
- Uses
httpxfor async HTTP requests - Strict Pydantic validation (fail fast on API changes)
- Temp directory for downloads (auto-cleanup on shutdown)
- Follows browser-automation-mcp.py patterns
- Helper functions organized in
src/helpers.py - Pydantic models in
src/models.py
Development
Formatting:
uvx ruff format .