Skip to main content
Glama
thecodacus

OKF Knowledge Agent MCP Server

by thecodacus

understory 🌱

Gedächtnis, das wächst.

Die Schicht unter deinen Agenten: ein selbstverdrahtetes, reines Markdown-Gedächtnis. Jede Tatsache, die deine Agenten lernen, wird als Markdown-Konzept abgelegt, in einen lebendigen Wissensgraphen verlinkt und vom Agenten selbst gesund gehalten – durchsuchbar, diffbar und ganz dein. Läuft hervorragend auf lokalen Modellen.

Bundles folgen der Open Knowledge Format (OKF) v0.1 Spezifikation – einfache Markdown-Dateien mit YAML-Frontmatter, für Menschen lesbar, in Git diffbar, über Tools hinweg portabel.

Drei Wege hinein, ein Agent:

  • MCP-Servermemory_query / memory_add / memory_update / memory_status / memory_maintain-Tools über stdio oder streamable HTTP. Jeder Aufruf steuert einen internen LLM-Agenten mit der OKF-Spezifikation im System-Prompt.

  • Web-UI – das Bundle durchsuchen (Baum, Konzept-Viewer, Update-Log, Konformitätsabzeichen), das Gedächtnis als kraftgerichteten Graphen im Obsidian-Stil ansehen (ziehen/verschieben/zoomen, nach Typ gefärbt, nach Verbindungen skaliert, verwaiste Knoten rot umrandet, klicken zum Öffnen) und mit demselben Agenten chatten, um es zu testen. Tool-Aufrufe werden inline gerendert, sodass du zusehen kannst, wie es arbeitet.

  • Query-Pfad-Wiedergabe – jeder Agentenlauf (Abfrage/Mutation/Chat) zeichnet seinen Durchlauf (Suchen → Lesen → Schreiben) in einer kompakten Notation auf, gespeichert unter <bundle>/.traces/. Die Graph-Ansicht listet letzte Läufe; die Auswahl eines Laufs spielt den Pfad als nummerierte gerichtete Sprünge über den Graphen ab – besuchte Konzepte umrandet, Suchtreffer gepunktet, alles andere ausgeblendet.

  • CLIpnpm agent:query "..." / pnpm agent:mutate "..." Smoke-Einstiege.

Designregel: Konformität wird im Code erzwungen, nicht in Prompts. Die deterministische Bundle-Schicht validiert Frontmatter (type erforderlich), regeneriert index.md-Dateien, hängt log.md-Einträge an (neueste zuerst, Spezifikation §7) und sandboxt alle Pfade auf das Bundle-Root. Das LLM entscheidet, was geändert wird; der Code garantiert, dass das Ergebnis ein konformes Bundle ist.

Schnellstart (Docker)

Kein Klonen nötig – das Image ist öffentlich. Speichere dies als docker-compose.yml:

services:
  understory:
    image: ghcr.io/thecodacus/understory:latest
    ports:
      - "3800:3800"
    # Lets the container reach a llama.cpp server running on the host via
    # http://host.docker.internal:8080/v1 (see "Local llama.cpp" below).
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      # Your memory lives here as plain markdown — a named volume, or point
      # a bind mount (e.g. ./my-memory:/bundle) at any OKF bundle.
      - understory-memory:/bundle
    environment:
      BUNDLE_ROOT: /bundle
      LLM_API_BASE_URL: ${LLM_API_BASE_URL}
      LLM_API_KEY: ${LLM_API_KEY}
      LLM_API_FORMAT: openai
      LLM_MODEL: ${LLM_MODEL:-}
      # Optional fallback
      LLM_FALLBACK_API_BASE_URL: ${LLM_FALLBACK_API_BASE_URL:-}
      LLM_FALLBACK_API_KEY: ${LLM_FALLBACK_API_KEY:-}
      LLM_FALLBACK_API_FORMAT: ${LLM_FALLBACK_API_FORMAT:-openai}
      LLM_FALLBACK_MODEL: ${LLM_FALLBACK_MODEL:-}
    restart: unless-stopped

volumes:
  understory-memory:
docker compose up -d

Einen Anbieter wählen

Das generische Anbietersystem unterstützt jede OpenAI-kompatible oder Anthropic-kompatible API. Setze LLM_API_BASE_URL + LLM_API_KEY + LLM_MODEL und lasse LLM_PROVIDER ungesetzt.

DeepSeek:

LLM_API_BASE_URL=https://api.deepseek.com/v1 LLM_API_KEY=sk-... LLM_MODEL=deepseek-chat

OpenAI:

LLM_API_BASE_URL=https://api.openai.com/v1 LLM_API_KEY=sk-... LLM_MODEL=gpt-4o

Anthropic (Claude):

LLM_API_BASE_URL=https://api.anthropic.com/v1 LLM_API_KEY=sk-ant-... LLM_API_FORMAT=anthropic LLM_MODEL=claude-sonnet-5

Groq:

LLM_API_BASE_URL=https://api.groq.com/openai/v1 LLM_API_KEY=gsk_... LLM_MODEL=llama-3.3-70b-versatile

Lokales llama.cpp:

LLM_API_BASE_URL=http://host.docker.internal:8080/v1 LLM_MODEL=

Wenn understory in Docker läuft, ist localhost der Container selbst, nicht der Host – ein llama-Server auf dem Host wird also unter host.docker.internal erreicht (die obigen Compose-Dateien mappen es bereits über extra_hosts). Wenn du aus dem Quellcode auf demselben Rechner wie llama-Server läufst, verwende http://localhost:8080/v1.

Lokales llama.cpp mit DeepSeek-Fallback:

LLM_API_BASE_URL=http://host.docker.internal:8080/v1 LLM_MODEL= \
LLM_FALLBACK_API_BASE_URL=https://api.deepseek.com/v1 LLM_FALLBACK_API_KEY=sk-... LLM_FALLBACK_MODEL=deepseek-chat

Die alten LLM_PROVIDER- und pro-Anbieter-Key-Umgebungsvariablen funktionieren weiterhin (abwärtskompatibel), sind aber veraltet.

Dann:

  • Web-UIhttp://localhost:3800 – das Gedächtnis durchsuchen, den Graphen beobachten, mit dem Agenten chatten

  • MCP-Endpunkthttp://localhost:3800/mcp (streamable HTTP) – in jedem MCP-Client registrieren:

    claude mcp add --transport http ustory http://localhost:3800/mcp
  • Dein Agent hat jetzt memory_query / memory_add / memory_update / memory_status / memory_maintain und erhält bei jedem Sitzungsstart eine Seed-Übersicht des Gedächtnisses.

Bringe ihm etwas bei (memory_add: „Wir deployen freitags, nie montags“), öffne dann den Graphen und beobachte, wie sich das Konzept selbst verdrahtet. Deployst du mit Portainer? Verwende docker-compose.portainer.yml als Repository-Stack.

Related MCP server: Kremis

Stack

pnpm-Monorepo:

Package

Was

packages/core

OKF-Bundle-Schicht (ohne LLM) + Agent (Vercel AI SDK Tool-Loop: search/read/list/write/patch/delete) + Provider-Registry

packages/server

Express: MCP streamable-HTTP unter /mcp, stdio-Bin, REST-Browse-API unter /api/*, Streaming-Chat unter /api/chat, serviert den Web-Build

packages/web

Vite + React + TS + Tailwind: Bundle-Browser + Agent-Chat (useChat)

Anbieter werden über LLM_API_BASE_URL, LLM_API_KEY, LLM_API_FORMAT (openai oder anthropic) und LLM_MODEL konfiguriert. Jeder OpenAI-kompatible Endpunkt (DeepSeek, OpenAI, Groq, OpenRouter, llama.cpp usw.) funktioniert mit LLM_API_FORMAT=openai; Anthropic-kompatible Endpunkte verwenden LLM_API_FORMAT=anthropic. Optionaler Fallback verwendet die passenden LLM_FALLBACK_*-Variablen.

llama.cpp

# on the inference box — --jinja enables OpenAI-style tool calling
llama-server -m model.gguf --jinja --host 0.0.0.0 --port 8080

# here — no model id needed, it's discovered for llama-server-like local endpoints
LLM_API_BASE_URL=http://inference-box:8080/v1 LLM_API_FORMAT=openai LLM_MODEL= \
BUNDLE_ROOT=./sample-bundle node packages/server/dist/index.js

Funktioniert auch hinter llama-swap: Die Erkennung bevorzugt das aktuell geladene Modell, sodass eine Abfrage keinen mehrminütigen Modellwechsel auslöst. Pinne ein bestimmtes Modell mit LLM_MODEL=.

Aus dem Quellcode

pnpm install
pnpm build
cp .env.example .env   # add your API key

BUNDLE_ROOT=./sample-bundle \
LLM_API_BASE_URL=https://api.deepseek.com/v1 \
LLM_API_KEY=sk-... \
LLM_API_FORMAT=openai \
LLM_MODEL=deepseek-chat \
node packages/server/dist/index.js
# → http://localhost:3800  (web UI + /api + /mcp)

Oder baue den Container selbst: docker compose up --build (das docker-compose.yml des Repos baut aus dem Quellcode und mountet ./sample-bundle).

Entwicklungsmodus (Server auf :3800, Vite HMR auf :5180 mit Proxy):

BUNDLE_ROOT=./sample-bundle pnpm --filter @understory/server dev
pnpm --filter @understory/web dev

MCP-Registrierung (Claude Code / Desktop)

claude mcp add ustory \
  -e BUNDLE_ROOT=/path/to/your/bundle \
  -e LLM_API_BASE_URL=https://api.deepseek.com/v1 \
  -e LLM_API_KEY=sk-... \
  -e LLM_API_FORMAT=openai \
  -e LLM_MODEL=deepseek-chat \
  -- node /path/to/understory/packages/server/dist/mcp/stdio.js

Oder richte einen HTTP-MCP-Client auf http://host:3800/mcp.

Authentifizierung

Standardmäßig ist der Server offen – auf localhost oder einem vertrauenswürdigen LAN in Ordnung. Bevor du ihn irgendwo anders freigibst, setze AUTH_TOKEN:

AUTH_TOKEN=$(openssl rand -hex 24)

Wenn gesetzt, erfordern /mcp und /api Authorization: Bearer <token> (die Web-UI bleibt erreichbar und fragt nach dem Token). Registriere authentifizierte MCP-Clients mit einem Header:

claude mcp add --transport http ustory http://host:3800/mcp \
  --header "Authorization: Bearer <token>"

Der stdio-Transport benötigt kein Token – es ist ein lokaler Prozess, der vom Client gestartet wird.

Seed-Gedächtnis

Ein Client-LLM, das nur vier nackte Tool-Namen sieht, bekommt nie den Instinkt, das Gedächtnis zu prüfen. Deshalb injiziert der Server bei Sitzungsstart eine kompakte Übersicht darüber, was die Wissensbasis enthält (Verzeichnisse, Konzepte mit Typen + Beschreibungen, letzte Aktivität) über beide Kanäle, die das Modell erreichen:

  1. das MCP-Initialize-instructions-Feld (Clients wie Claude legen es in den System-Prompt), und

  2. die memory_query-Tool-Beschreibung – den universellen Fallback, den jeder Tool-aufrufende Client lädt.

Der Seed wird für jede neue Sitzung frisch regeneriert. Nach memory_add / memory_update in einer langlebigen (stdio) Sitzung wird die Tool-Beschreibung über tools/list_changed aktualisiert, sodass die Sitzung ihre eigenen Schreibvorgänge sieht. Out-of-band-Änderungen (manuelle Bearbeitungen, andere Clients) werden bei der nächsten Sitzung übernommen.

Graph-Gesundheit & Wartung

Das Gedächtnis ist ein Graph, kein Notizhaufen, und Graphen verrotten: Konzepte werden verwaist (nichts verlinkt auf sie) und Links werden kaputt. Zwei Mechanismen halten es gesund:

  • Schreibzeit-Verknüpfung – neues Wissen reichert entweder das Konzept an, zu dem es gehört (ein Attribut einer bestehenden Entität wird eingepatcht, nicht separat abgelegt) oder, wenn es eine eigenständige Entität ist, wird es erstellt und von verwandten Konzepten zurückverlinkt. Widersprüche werden an Ort und Stelle ersetzt, nie neben dem alten Wert stehen gelassen.

  • memory_maintain – ein deterministischer Lint (verwaiste + kaputte Links, in memory_status unter graph sichtbar) treibt einen internen Agenten an, verwaiste Konzepte in verwandte Konzepte einzubinden und lose Links zu reparieren. Führe es regelmäßig aus, um Drift entgegenzuwirken; es ist ein No-op, wenn der Graph bereits gesund ist.

Dieses Design spiegelt das Muster in Karpathys LLM Wiki wider (index.md + log.md, create-vs-enrich, Lint für verwaiste). Aufgeschoben aus diesem Muster, bis der Maßstab es rechtfertigt: ein explizites Seiten-Typ-Schema und hybride FTS5+Embedding-Suche (der naive Scan in search.ts ist bis in die niedrigen Tausender von Konzepten in Ordnung).

Tests

pnpm test                                  # core: 18 tests (spec §5/§6/§7/§9, sandbox, search, concurrency)
pnpm --filter @understory/server exec tsx scripts/mcp-smoke.mts   # MCP stdio round-trip (needs SMOKE_BUNDLE + an API key)

Umgebung

Siehe .env.example. BUNDLE_ROOT ist erforderlich; GIT_AUTOCOMMIT=true committet jede Mutation.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    A Knowledge Graph MCP server optimized for LLM context efficiency through compact JSON and SQLite persistence. It enables full graph management including node/edge CRUD operations, full-text search, and subgraph traversal.
  • A
    license
    A
    quality
    A
    maintenance
    MCP server exposing a deterministic, local knowledge graph over stdio. Zero LLM calls in the bridge; answers are classified as Fact, Inference, or Unknown and persisted in redb (ACID, BLAKE3-hashed).
    10
    14
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    A local OKF-compatible knowledge engine for AI agents. Enables capturing agent conversations, hybrid semantic+keyword search, MCP serving to agents, interactive graph visualization, and OKF bundle export.
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides LLM agents with a structured, queryable, local-first knowledge base with typed documents and full-text search via MCP.
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/thecodacus/understory'

If you have feedback or need assistance with the MCP directory API, please join our Discord server