Documentation source
Documentation source
Documentation source
Connect Granola meeting notes and transcripts to Amble through OAuth, Streamable HTTP MCP, and the integration ledger.
## Overview The Granola connector synchronizes meeting details, notes, participants, and transcripts into tenant-scoped Amble records. Granola remains the source of truth for the meeting. Amble stores: - one `granola-meeting` entity per Granola meeting; - one `granola-transcript` entity and linked Markdown document per transcript; - the integration object, entity link, mapper version, payload hash, and field provenance needed to audit every mapped record. The connector uses Granola's OAuth-protected Streamable HTTP MCP endpoint at `https://mcp.granola.ai/mcp`. It does not use the separate API-key product or undocumented REST endpoints. ## Connect Open **Admin → Integrations → Granola** and choose **Connect Granola**. Amble registers an OAuth client for the deployment's stable callback URL, starts an Authorization Code + PKCE flow in Granola, and stores the resulting OAuth2 envelope only in encrypted `agent_connections.encrypted_credentials` storage. Dynamic Client Registration means there are no app-level `GRANOLA_*` secrets to add to the deployment environment. Access tokens are refreshed through the shared OAuth engine before they enter their last five minutes of validity. ## Sync contract Each pull uses Granola's documented list → detail → transcript sequence: 1. `list_meetings` receives a bounded `time_range` derived from the connection cursor or the operator's requested window. 2. `get_meetings` batch-loads notes and participants for the new meeting IDs. 3. `get_meeting_transcript` loads each readable transcript. 4. The raw-ledger runner maps and tenant-scopes every write through the normal integration framework. Meetings upsert by `(tenant, external_source="granola:meeting", external_id=meeting_id)`. Transcripts use `granola:transcript` with the same meeting ID. A repeated window updates the existing entities and does not create another transcript document. The last meeting timestamp advances only after an apply run finishes with zero record failures. A meeting without an available transcript still syncs as a meeting entity; it does not block later meetings in the same window. ## Sensitive-content policy Transcript text and full meeting notes are available to their intended entity and document, but are not copied verbatim into `integration_objects`. The raw ledger keeps an allow-safe projection containing IDs, timestamps, counts, and SHA-256 values. This preserves change detection and provenance without creating an extra plaintext transcript store. Treat `granola-transcript` entities and their documents as sensitive operating records. Do not copy transcript text into logs, action metadata, or support tickets. ## Dry-run and enablement Apply is gated by a successful dry-run at the current connector version. The shipped scheduled sync and post-meeting routine are both disabled. Tyler's enablement checklist: 1. Choose **Connect Granola**, approve Granola OAuth, and confirm the connection returns active. DCR happens automatically; no token file or API key is used. 2. Run a dry-run for a small recent window. Review meeting/transcript counts, conflicts, and the redacted raw-ledger samples. 3. Run the first real apply. Confirm meeting fields, readable documents, `metadata.integration`, and `integration_entity_links` provenance. 4. Re-run the same window and confirm it creates zero new entities or documents. 5. Enable `sprinter-granola-scheduled-sync` only after the first real apply is accepted. Its deterministic executor is `integrations.scheduledSync` with `slug="granola"` and the dry-run gate enabled. 6. Enable `sprinter-granola-post-meeting-routine` separately only after the `amble` agent, action-item wording, and follow-up destination have been reviewed. It summarizes decisions, extracts explicitly assigned actions, and files follow-ups when a `granola-meeting` entity is created. ## Failure behavior - OAuth refresh failures mark the connection for operator attention; token values are never logged. - A list, detail, or transcript failure fails that connection's run and leaves its cursor unchanged so the same window can retry. - A concurrent cursor update fails closed instead of overwriting the newer checkpoint. - One failed Granola account does not prevent another selected account from running; the admin result lists the failed connection explicitly. ## Verification boundary Repository validation uses seeded MCP tool responses over the official MCP SDK's real initialize and Streamable-HTTP/SSE protocol path. It proves the connector flow without requiring or reading a developer's local Granola token file. A seeded test is not evidence that production Granola authorization or live meeting data has been verified. ## Follow-up `features/mcp/bridges/granola.ts` is the first spec-current outbound MCP client in Amble. After this connector soaks, promote its initialize/SSE transport into the general outbound MCP client without changing the Granola integration contract.