Skip to main content
Glama

What is karve?

Claude Code is powerful but stateless. Every session starts cold: no memory of past decisions, preferred patterns, or project context. You re-explain, re-discover, and re-decide the same things.

karve gives Claude Code persistent, searchable memory that lives entirely on your Mac.

It runs two local servers — a 4B-parameter embedding model on Apple Silicon (via MLX) and an agent-native context database (OpenViking) — and exposes them to Claude as six MCP tools. Claude stores notes, searches past context, and retrieves project knowledge across sessions. Nothing leaves your machine.

Named after the karve, a light, fast class of Viking longship.


Related MCP server: umo-memory

Why local semantic memory?

Cloud AI tools that promise "memory" route your context through remote servers. If your notes contain code decisions, architectural choices, or proprietary system designs, that's a meaningful privacy exposure.

karve is local-first:

  • Embeddings computed on-device by Qwen3-Embedding-4B-mxfp8 via MLX — Apple Silicon native, no GPU rental

  • Storage in OpenViking, an open-source context database that runs entirely on localhost

  • Retrieval by semantic similarity — not keyword matching, not brittle file search

OpenViking isn't a vector store you query with scripts. It uses a file-system interface (viking://user/memory/, viking://resources/, etc.) that Claude navigates autonomously. Think of it as a filesystem your AI can search by meaning.


Is karve right for you?

Scenario

Fit

macOS Apple Silicon (M1 / M2 / M3 / M4)

✅ Required

Claude Code as your primary AI client

✅ Required

Single-user, local-only workflow

✅ Ideal

Intel Mac, Linux, or Windows

❌ MLX won't run

Teams sharing memory across machines

❌ Local stack only

Other AI clients (Cursor, Windsurf, etc.)

❌ MCP server targets Claude Code

Real-time or very large-scale retrieval

❌ Single-user, not designed for this


Quick Start

Prerequisites: macOS Apple Silicon · Python 3.11+ · uv

1. Clone and install

git clone <repo-url>
cd karve
uv sync

2. Create credentials

cp credentials.yml.dist credentials.yml

Edit credentials.yml — any string works for local use:

openviking:
  api_key: my-local-key

3. Start the stack

./scripts/start_openviking.sh

The first run downloads ~4 GB of model weights — allow ~5 minutes. Subsequent starts take a few seconds. Logs go to logs/embedding.log and logs/openviking.log.

4. Register the MCP with Claude Code

See MCP Registration below, then restart Claude Code.

5. Verify the connection

In any Claude Code session, ask Claude to run viking_status(). A healthy response confirms the stack is reachable.


MCP Registration

Add karve to your .mcp.json. For user-wide registration, create or edit ~/.claude/.mcp.json:

{
  "mcpServers": {
    "openviking": {
      "command": "uv",
      "args": ["--project", "/path/to/karve", "run", "python", "-m", "src.openviking_mcp_server"]
    }
  }
}

Replace /path/to/karve with the absolute path to your cloned repository. Restart Claude Code after saving.

Alternatively, register via the CLI:

claude mcp add openviking -s user -- uv --project /path/to/karve run python -m src.openviking_mcp_server

Project-scoped memory

By default all tools use the global viking:// namespace, so memories from different projects can mix. To isolate memory per project, add a KARVE_PROJECT env var in a project-level .mcp.json at your project root:

{
  "mcpServers": {
    "openviking": {
      "command": "uv",
      "args": ["--project", "/path/to/karve", "run", "python", "-m", "src.openviking_mcp_server"],
      "env": {
        "KARVE_PROJECT": "my-project-name"
      }
    }
  }
}

When KARVE_PROJECT is set:

  • Searches default to viking://user/projects/my-project-name/ instead of viking://

  • viking_remember stores at viking://user/projects/my-project-name/<category>/

  • Global search is still available by passing uri="viking://" explicitly

Without KARVE_PROJECT, all tools use the global viking:// namespace (original behaviour).


MCP Tools

Six tools become available once Claude Code restarts with the MCP registered:

Tool

Purpose

Key Parameters

viking_search

Fast semantic similarity search

query, uri="viking://", limit=5

viking_deep_search

Intent-aware search with query expansion

query, uri="viking://", limit=5

viking_read

Read content at a specific URI

uri, depth="overview"

viking_list

Browse the context filesystem

uri="viking://"

viking_remember

Store text for future retrieval

text, category="memory", name=""

viking_status

Health check — returns server details

Depth levels for viking_read

Depth

Approx. tokens

Use when

abstract

~100

Quick triage — is this the right resource?

overview

~2000

Default — good balance of context

full

complete

Full document needed

URI scoping

All search and list tools accept a uri parameter to scope the query:

viking://               # everything
viking://user/          # all user-owned content
viking://user/memory/   # stored memories only
viking://resources/     # indexed resources

Architecture

┌──────────────────────────────────────────────────────┐
│  Claude Code                                          │
│                                                       │
│  viking_search  viking_deep_search  viking_read       │
│  viking_list    viking_remember     viking_status     │
└──────────────────────┬───────────────────────────────┘
                       │ stdio  (FastMCP subprocess)
                       ▼
┌──────────────────────────────────────────────────────┐
│  src/openviking_mcp_server.py                         │
│  FastMCP wrapper — thin HTTP bridge, no local state   │
└──────────────────────┬───────────────────────────────┘
                       │ HTTP  localhost:1933
                       ▼
┌──────────────────────────────────────────────────────┐
│  OpenViking server                                    │
│  Agent-native context database                        │
│  File-system interface: viking:// URIs                │
│  Three-tier loading: L0 abstract · L1 overview · L2   │
└──────────────────────┬───────────────────────────────┘
                       │ HTTP  localhost:8000
                       ▼
┌──────────────────────────────────────────────────────┐
│  MLX embedding server  (mlx-openai-server)            │
│  mlx-community/Qwen3-Embedding-4B-mxfp8               │
│  OpenAI-compatible API · Apple Silicon native         │
└──────────────────────────────────────────────────────┘

All components run on localhost. No external network calls.
Active ports written to ~/.openviking/runtime.json on each startup.

Configuration

config.yml — non-secret settings

Key

Default

Notes

embedding.model

mlx-community/Qwen3-Embedding-4B-mxfp8

MLX model path

embedding.base_port

8000

Scans upward if occupied

openviking.base_port

1933

Scans upward if occupied

logging.level

INFO

DEBUG | INFO | WARNING | ERROR

Ports are dynamic: if a base port is occupied, the startup script finds the next free port. The MCP wrapper reads ~/.openviking/runtime.json at startup to locate the current ports — so restarting the stack never breaks the MCP connection.

credentials.yml — secrets (gitignored)

openviking:
  api_key: your-key-here   # any string — local auth only

Copy from credentials.yml.dist. Never commit this file.


Dashboard

When Claude Code spawns the MCP server, a status dashboard automatically opens in your browser. It polls the OpenViking REST API every 5 seconds and displays:

  • Server health and system status

  • Observer component health (queue, vikingdb, transaction)

  • Embedding server status and active model name

  • Active session count

  • Context filesystem root listing

The dashboard is a single static dashboard.html file — no build step, no web server required. It runs entirely client-side.


Development

uv sync                    # install all deps including dev tools
uv run pytest              # 64 tests, 100% coverage

Quality gates (all passing):

Tool

Result

ruff

zero violations

mypy --strict

zero errors

pytest

64 tests, 100% coverage

bandit

no security issues

interrogate

100% docstring coverage

pylint

9.77 / 10

radon

all grade B or better

xenon

max-absolute B


Acknowledgments

  • OpenViking — open-source agent-native context database by ByteDance Volcano Engine; the core storage and retrieval engine powering karve

  • FastMCP — the MCP server framework used here; v3.0 released January 2026, powers 70% of MCP servers with 1M+ downloads/day

  • MLX — Apple's array framework for fast on-device inference; makes local 4B-parameter embeddings practical on consumer hardware


Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Persistent memory for Claude Code. Automatically indexes every conversation and provides production-grade hybrid search (BM25 + vectors + reranker) via MCP tools. 100% local, zero config, zero API keys, zero invoice.
    16
    33 npm
    7
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Persistent memory for AI coding agents that stores and recalls preferences, decisions, and conventions via semantic similarity, with zero cloud dependencies and plug-and-play MCP integration for Claude Code.
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides persistent, searchable memory for Claude Code using local SQLite, semantic embeddings, and full-text search, enabling Claude to recall and retrieve context across sessions and projects without external services.
    6 npm
    4
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Persistent memory with semantic search for Claude and MCP-compatible clients, storing context that survives conversations and can be retrieved intelligently.
    1
    MIT