granola
granola
¶
Granola connector — syncs meeting notes via the Granola public API.
Uses an API key (Bearer token) stored locally. All network calls are
isolated in module-level functions (_granola_api_*) to make them
trivially mockable in tests.
Users create an API key in the Granola desktop app under Settings → API (requires Business or Enterprise plan).
Classes¶
GranolaKeyError
¶
Bases: ValueError
Raised when a Granola API key is missing or rejected by the API.
Surfaced through the /connect endpoint as an HTTP 400 so the user
sees why the key was refused instead of a silent failed sync later.
GranolaConnector
¶
Bases: BaseConnector
Connector that syncs meeting notes from Granola via the public REST API.
Authentication uses an API key created in the Granola desktop app (Settings → API, requires Business or Enterprise plan). The key is stored locally in a JSON credentials file.
| PARAMETER | DESCRIPTION |
|---|---|
api_key
|
Granola API key. If provided, it takes priority over any stored credentials file.
TYPE:
|
credentials_path
|
Path to the JSON file where the API key is stored. Defaults to
TYPE:
|
Source code in src/openjarvis/connectors/granola.py
Functions¶
is_connected
¶
disconnect
¶
auth_url
¶
Return the URL where users can create a Granola API key.
Users must open the Granola desktop app and navigate to Settings → API to generate their key.
Source code in src/openjarvis/connectors/granola.py
handle_callback
¶
Validate and persist the API key.
The code parameter holds the raw API key string provided by the
user. The key is verified with a live GET /v1/notes?limit=1
probe before it is written, so an invalid key can never overwrite
a working credential on disk (raises :class:GranolaKeyError on a
401/403).
Source code in src/openjarvis/connectors/granola.py
sync
¶
sync(*, since: Optional[datetime] = None, cursor: Optional[str] = None) -> Iterator[Document]
Yield :class:Document objects for Granola meeting notes.
Paginates through GET /v1/notes and fetches each note's full
content (summary + transcript) via GET /v1/notes/{id}.
| PARAMETER | DESCRIPTION |
|---|---|
since
|
If provided, only notes created after this datetime are returned
(passed as
TYPE:
|
cursor
|
Pagination cursor from a previous sync to resume paginating.
TYPE:
|
Source code in src/openjarvis/connectors/granola.py
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | |
sync_status
¶
sync_status() -> SyncStatus
Return sync progress from the most recent :meth:sync call.
Source code in src/openjarvis/connectors/granola.py
mcp_tools
¶
mcp_tools() -> List[ToolSpec]
Expose two MCP tool specs for real-time Granola queries.