Acai
Go CLI and MCP server that exposes Granola meeting intelligence as structured, queryable MCP resources for AI agents and automation pipelines
Installation
npx acaiAsk AI about Acai
Powered by Claude Β· Grounded in docs
I know everything about Acai. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
acai
Website | Getting Started | Documentation
Granola meeting intelligence for the MCP ecosystem. A Go CLI and MCP server that exposes Granola meetings, transcripts, summaries, and action items as structured MCP resources and tools β enabling AI agents to reason over meeting knowledge.
Features
- MCP Server β Typed tools and resources for meetings, transcripts, action items, notes, and embeddings
- CLI β Authenticate, sync, search, export, annotate, and manage meetings from the terminal
- Write-Back β Agent-generated notes and action item updates persisted locally with outbox pattern for future upstream sync
- Embedding Export β Chunk meeting content by speaker turn, time window, or token limit and export as JSONL
- Agent Policies β Per-meeting ACL (allow/deny by tool + tags) and content redaction (emails, speakers, keywords, patterns)
- Resilient β Circuit breaker, retry with backoff, rate limiting, and timeouts on every API call via Fortify
- Cached β SQLite local cache reduces API calls and enables offline access
- Multi-Workspace β Query meetings across multiple Granola workspaces
- Event Streaming β Real-time meeting events via domain event dispatcher
- Webhook Support β Push-based sync with HMAC-SHA256 signature validation
Installation
Homebrew
brew tap felixgeelhaar/tap
brew install acai
Go install
CGO_ENABLED=1 go install github.com/felixgeelhaar/acai/cmd/acai@latest
CGO is required for the SQLite driver.
From source
git clone https://github.com/felixgeelhaar/acai.git
cd acai
make build
Quick Start
# Authenticate with Granola
export ACAI_GRANOLA_API_TOKEN=gra_xxxxx
acai auth login --method api_token
# List recent meetings
acai list meetings
# Export a meeting as markdown
acai export meeting <meeting-id> --format md
# Add an agent note to a meeting
acai note add <meeting-id> "Key insight from analysis"
# Export meeting chunks for embedding
acai export embeddings --meetings <id1>,<id2> --strategy speaker_turn
# Start as MCP server (stdio, for Claude Code)
acai serve
CLI Commands
acai
auth
login Authenticate with Granola (--method oauth|api_token)
status Show current authentication status
list
meetings List meetings (--format table|json, --source, --limit, --since, --until)
export
meeting Export a meeting (--format json|md|text)
embeddings Export meeting chunks as JSONL (--meetings, --strategy, --max-tokens)
note
add Add an agent note to a meeting
list List agent notes for a meeting (--format table|json)
delete Delete an agent note
action
complete Mark an action item as completed
update Update an action item's text
sync Sync meetings from Granola API (--since)
serve Start MCP server on stdio
version Show version information
MCP Server
When running as an MCP server (acai serve), the following tools and resources are exposed:
Tools
| Tool | Description |
|---|---|
list_meetings | Search and filter meetings with date, source, and text filters |
get_meeting | Get full meeting details including summary and action items |
get_transcript | Get the transcript with speaker utterances |
search_transcripts | Full-text search across all meeting transcripts |
get_action_items | Get action items from a specific meeting |
meeting_stats | Aggregated meeting statistics with interactive D3.js dashboard |
list_workspaces | List all Granola workspaces |
add_note | Add an agent note to a meeting |
list_notes | List agent notes for a meeting |
delete_note | Delete an agent note |
complete_action_item | Mark an action item as completed |
update_action_item | Update an action item's text |
export_embeddings | Export meeting content as chunks for embedding generation |
Resources
| URI Pattern | Description |
|---|---|
meeting://{id} | Full meeting details as JSON |
transcript://{meeting_id} | Transcript utterances as JSON |
note://{meeting_id} | Agent notes for a meeting as JSON |
workspace://{id} | Workspace details as JSON |
ui://meeting-stats | Interactive meeting statistics dashboard (HTML) |
Claude Code Integration
Add to your Claude Code MCP configuration (~/.claude/mcp.json):
{
"mcpServers": {
"granola": {
"command": "acai",
"args": ["serve"],
"env": {
"ACAI_GRANOLA_API_TOKEN": "gra_xxxxx"
}
}
}
}
Agent Policies
Control what data AI agents can access and how sensitive content is handled. Create a YAML policy file and set the ACAI_POLICY_FILE environment variable:
default_effect: allow
rules:
- name: block-confidential-transcripts
effect: deny
tools: [get_transcript, export_embeddings]
conditions:
meeting_tags: [confidential]
redaction:
enabled: true
rules:
- type: emails
replacement: "[EMAIL]"
- type: speakers
replacement: "Speaker {n}"
- type: keywords
keywords: [salary, confidential]
replacement: "[REDACTED]"
- type: patterns
pattern: '\d{3}-\d{2}-\d{4}'
replacement: "[SSN]"
ACL β First-match-wins rule evaluation. Deny rules block tool execution for meetings matching tag conditions.
Redaction β Applied to all tool responses. Emails replaced by regex, speakers anonymized consistently (same person always maps to same "Speaker N"), keywords matched case-insensitively with word boundaries, custom regex patterns supported.
Configuration
Configuration uses 12-factor principles: sensible defaults with environment variable overrides.
| Variable | Default | Description |
|---|---|---|
ACAI_GRANOLA_API_URL | https://api.granola.ai | Granola API base URL |
ACAI_GRANOLA_API_TOKEN | β | API token for authentication |
ACAI_MCP_TRANSPORT | stdio | MCP transport (stdio or http) |
ACAI_MCP_HTTP_PORT | 8080 | HTTP port when using HTTP transport |
ACAI_CACHE_TTL | 15m | Local cache time-to-live |
ACAI_LOGGING_LEVEL | info | Log level (debug, info, warn, error) |
ACAI_LOGGING_FORMAT | console | Log format (console or json) |
ACAI_WEBHOOK_SECRET | β | HMAC secret for webhook signature validation |
ACAI_POLICY_FILE | β | Path to YAML policy file (enables ACL + redaction) |
Architecture
The project follows strict Domain-Driven Design with hexagonal architecture:
cmd/acai/main.go Composition root (DI wiring)
internal/
domain/ Pure business logic, zero dependencies
meeting/ Meeting aggregate, value objects, events, chunks
annotation/ Agent notes bounded context
policy/ ACL rules, redaction config value objects
auth/ Token, credential, auth service port
workspace/ Workspace aggregate
application/ Use cases (one per file)
meeting/ ListMeetings, GetMeeting, CompleteActionItem, ...
annotation/ AddNote, ListNotes, DeleteNote
embedding/ ExportEmbeddings, chunking strategies
auth/ Login, CheckStatus
workspace/ ListWorkspaces, GetWorkspace
export/ ExportMeeting
infrastructure/ External adapters
granola/ Granola API client + repository (anti-corruption layer)
resilience/ Fortify: circuit breaker, retry, rate limit, timeout
cache/ SQLite local cache (repository decorator)
localstore/ SQLite local store for notes + action item overrides
outbox/ Outbox dispatcher for write events
policy/ YAML loader, redaction engine
events/ Domain event dispatcher + MCP notifier
sync/ Background polling sync manager
webhook/ HMAC-SHA256 webhook handler
auth/ File-based token storage
config/ 12-factor configuration
interfaces/ Inbound adapters
mcp/ MCP server with tools, resources, policy middleware
cli/ CLI commands (cobra)
Decorator Chain
Read path: Granola API β Resilient Repo β Cached Repo β Use Cases
Write path: Use Cases β Local SQLite Store β Outbox Dispatcher β Event Dispatcher
Key Libraries
| Library | Purpose |
|---|---|
| felixgeelhaar/mcp-go | MCP server framework with typed tools, resources, and multi-transport |
| felixgeelhaar/fortify | Resilience patterns: circuit breaker, retry, rate limit, timeout |
| spf13/cobra | CLI framework |
| mattn/go-sqlite3 | SQLite driver for local cache and local store |
| gopkg.in/yaml.v3 | YAML parsing for policy files |
Development
# Run tests (requires CGO for SQLite)
make test
# Run tests with race detection and coverage
make test-race
# Build
make build
# Lint
make lint
# Clean
make clean
Test Coverage
377 tests with 0 race conditions across all packages:
| Layer | Coverage |
|---|---|
| Domain (meeting, annotation, policy, auth, workspace) | 94-100% |
| Application (meeting, annotation, embedding, auth, workspace) | 86-100% |
| Infrastructure (granola, resilience, cache, policy, localstore, outbox) | 85-97% |
| Interfaces (mcp, cli) | 74-81% |
Website
The project website at felixgeelhaar.github.io/acai is built with Astro, Vue, and Tailwind CSS v4. Source lives in the site/ directory.
# Development
cd site && npm install && npm run dev
# Production build
npm run build && npm run preview
Deployed automatically to GitHub Pages via .github/workflows/pages.yml on push to main.
