Install
$ agentstack add mcp-felixgeelhaar-acai ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
acai
[](https://goreportcard.com/report/github.com/felixgeelhaar/acai) [](LICENSE) [](https://github.com/felixgeelhaar/acai/releases)
Website | [Getting Started](#quick-start) | [Documentation](#mcp-server)
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 --format md
# Add an agent note to a meeting
acai note add "Key insight from analysis"
# Export meeting chunks for embedding
acai export embeddings --meetings , --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.
License
[MIT](LICENSE)
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: felixgeelhaar
- Source: felixgeelhaar/acai
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.