AgentStack
MCP verified MIT Self-run

Acai

mcp-felixgeelhaar-acai · by felixgeelhaar

Go CLI and MCP server that exposes Granola meeting intelligence as structured, queryable MCP resources for AI agents and automation pipelines

No reviews yet
0 installs
2 views
0.0% view→install

Install

$ agentstack add mcp-felixgeelhaar-acai

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

Are you the author of Acai? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.