Skip to main content

Shared cognitive substrate for AI agents (local-first, Markdown-native, MCP)

Project description

Lithos

Shared memory for AI agents.

A local, privacy-first knowledge base that enables heterogeneous AI agents to share knowledge and coordinate work.

The Problem

When agents cannot share what they know, every agent starts from zero. Work is duplicated, discoveries are lost, and coordination breaks down. Lithos solves this by providing a persistent, shared knowledge layer that compounds in value over time.

What It Is

Lithos is an MCP server that provides a shared knowledge store for AI agents running on your local infrastructure. Knowledge is stored as human-readable Markdown files (compatible with Obsidian) while providing fast full-text and semantic search for agents.

Who It's For

Lithos is the Knowledge Layer for teams running AI agents in production.

Just as Alation coined the term "Knowledge Layer" for enterprise data governance, Lithos provides the equivalent for AI agent systems: a structured, searchable, shared memory that compounds in value the more it is used. Each agent interaction enriches the knowledge base, making every subsequent agent smarter and faster.

  • Teams running multiple AI agents (Agent Zero, OpenClaw, Claude Code, custom agents)
  • Developers who want agents to share discoveries and avoid duplicate work
  • Anyone who needs agent knowledge to be inspectable and version-controlled

Key Features

  • 📁 Markdown-first: All knowledge stored as Obsidian-compatible .md files
  • 🔍 Fast search: Tantivy full-text + ChromaDB semantic search
  • 🕸️ Knowledge graph: NetworkX-powered relationships via [[wiki-links]]
  • 🤝 Multi-agent coordination: Task claiming, findings sharing, status tracking
  • 🧠 Research cache: One-call freshness check so agents skip redundant research — returns hit/miss/stale with update guidance
  • 🔗 URL deduplication: Automatic detection and prevention of duplicate notes from the same source URL
  • 🧬 Provenance tracking: Declare which notes a synthesis is derived from and query lineage across the knowledge base
  • 🏷️ Free-form metadata: Attach arbitrary JSON metadata to notes and tasks, then filter by it with lithos_list / lithos_task_list metadata_match (scalar equality or array membership, AND across keys). Notes are filtered through an in-memory inverted index (no full scan); task filtering is evaluated inside SQLite (no Python post-scan)
  • 🔌 MCP interface: Works with any MCP-compatible agent or tool
  • 🏠 Local & private: No cloud dependencies, you own your data

Quickstart

Agent Zero

Agent Zero running inside docker on the same machine running lithos

{
  "mcpServers": {
    "lithos": {
      "url": "http://host.docker.internal:8765/sse"
    }
  }
}

OpenClaw

Update mcporter.json Probably in ~/.openclaw/workspace/config/mcporter.json

Use localhost if running on the same machine as OpenClaw, otherwise the name or IP address of the server.

{
  "mcpServers": {
    "lithos": {
      "baseUrl": "http://<your hostname>:8765/sse"
    }
  },
  "imports": []
}

Claude code

claude mcp add --transport sse lithos http://localhost:8765/sse

MCP endpoints

The HTTP server (lithos serve --transport http, the Docker default) exposes both MCP transports on the same port, so any compliant client can connect without a bridge:

Endpoint Transport Use with
GET http://localhost:8765/sse Legacy SSE Agent Zero, OpenClaw, older clients
POST http://localhost:8765/mcp StreamableHTTP (MCP 2025-03-26+, stateless) Claude Desktop, Hermes Agent, newer clients

Clients that speak StreamableHTTP should point at /mcp:

claude mcp add --transport http lithos http://localhost:8765/mcp

Documentation

Metadata Filtering

Lithos supports arbitrary metadata on both notes and tasks.

  • Notes: lithos_write(metadata={...}) stores free-form metadata in frontmatter. lithos_read returns it under metadata.extra; lithos_list returns it as each item's metadata.
  • Tasks: lithos_task_create(metadata={...}) stores initial metadata; lithos_task_update(metadata={...}) applies a per-key merge patch.
  • Note update semantics: omit or null preserves existing metadata, {} clears all metadata, and {"key": null} deletes one key.
  • Task update semantics: omit or null preserves existing metadata, {} is a no-op, and {"key": null} deletes one key.
  • Filtering: metadata_match is AND-across-keys. Each key: value matches when the stored value equals the scalar query value or is an array containing it. Query values must be strings, numbers, or booleans.

Tech Stack

Component Technology
Storage Markdown + YAML frontmatter
Full-text search Tantivy
Semantic search ChromaDB + sentence-transformers
Knowledge graph NetworkX
Agent interface MCP (FastMCP)
File sync watchdog

Development Commands

# Install dependencies (uses uv; the ``dev`` dependency group is installed
# by default via uv, so no extra flag is required).
uv sync

# Run unit tests
uv run pytest -m "not integration" tests/ -q

# Run integration tests
uv run pytest -m integration tests/ -q

# Run all tests with coverage
uv run pytest tests/ --cov=lithos --cov-report=xml

# Lint
uv run ruff check .

# Format check
uv run ruff format --check src/ tests/

# Type check
uv run pyright src/

# Auto-fix lint + format
uv run ruff check --fix . && uv run ruff format src/ tests/

# Start server (stdio)
uv run lithos serve

# Start server (HTTP — serves both /mcp and /sse)
uv run lithos serve --transport http --port 8765

# Docker
cd docker && docker compose up -d --build

# run pointing at data dir
LITHOS_DATA_PATH="<DATA DIR PATH>" docker compose up -d --build

# stop
cd docker && docker compose down

Docker: running multiple environments

Lithos ships with docker/run.sh, a thin wrapper around docker compose that drives each environment from its own gitignored .env.<name> file and a distinct compose project name (-p lithos-<name>). This lets you run prod, staging, and fuzz side-by-side on one host without container name, port, or volume collisions.

Set up env files

Create one file per environment under docker/:

docker/.env.prod

LITHOS_ENVIRONMENT=production
LITHOS_DATA_PATH=/path/to/lithos/data
LITHOS_HOST_PORT=8765
LITHOS_CONTAINER_NAME=lithos

docker/.env.staging

LITHOS_ENVIRONMENT=staging
LITHOS_DATA_PATH=/path/to/lithos/data-staging
LITHOS_HOST_PORT=8766
LITHOS_CONTAINER_NAME=lithos-staging

docker/.env.fuzz

LITHOS_ENVIRONMENT=fuzz
LITHOS_DATA_PATH=/path/to/lithos/data-fuzz
LITHOS_HOST_PORT=8767
LITHOS_CONTAINER_NAME=lithos-fuzz

LITHOS_ENVIRONMENT becomes the OTEL deployment.environment resource attribute, so metrics, traces, and logs are labelled per environment in your observability stack.

Use the launcher

cd docker

./run.sh prod                 # build & start production (default action = up)
./run.sh staging up           # same, explicit
./run.sh fuzz logs            # follow container logs
./run.sh staging status       # show running containers for this stack
./run.sh prod down            # stop & remove the stack
./run.sh fuzz restart         # down + up

Each environment gets its own container (lithos, lithos-staging, lithos-fuzz), its own host port, and its own data volume, so they can all run concurrently. Running ./run.sh with no arguments prints usage.

Telemetry & Observability

Lithos emits OpenTelemetry metrics, traces, and logs when telemetry is enabled. The only supported export path is OTLP/HTTP push to a collector — there is no /metrics scrape endpoint on the Lithos process itself (see closed issue #164 for the rationale).

How metrics reach your dashboards

  Lithos process
       │  OTLP/HTTP  (push every export_interval_ms, default 30 s)
       ▼
  OTEL Collector   ← lithos-observability/otel-collector/config.yml
       │  Prometheus exporter on :8889
       ▼
  Prometheus       ← lithos-observability/prometheus/prometheus.yml
       │
       ▼
  Grafana

Traces fan out to Tempo, logs to Loki, via the same collector.

Configuration

telemetry:
  enabled: false               # master switch
  endpoint: null               # OTLP base URL, e.g. http://otel-collector:4318
  console_fallback: false      # print spans/metrics to stdout when no endpoint
  service_name: lithos
  environment: null            # becomes OTEL deployment.environment
  export_interval_ms: 30000

Environment variables override endpoint per signal when needed: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT.

Local debugging without a collector

Pass --telemetry-console to lithos serve to route metrics and spans to stdout via console exporters. This is equivalent to setting telemetry.enabled=true + telemetry.console_fallback=true in config, and is the shortest path to "is my instrumentation even firing?" when no collector is running.

lithos --data-dir ./data serve --telemetry-console

Running the full observability stack locally

See lithos-observability/ for a one-command Docker Compose stack (OTEL Collector + Prometheus + Grafana + Tempo + Loki). Point Lithos at it with:

LITHOS_TELEMETRY__ENABLED=true \
LITHOS_TELEMETRY__ENDPOINT=http://localhost:4318 \
lithos serve

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lithos_mcp-0.4.0.tar.gz (851.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lithos_mcp-0.4.0-py3-none-any.whl (231.5 kB view details)

Uploaded Python 3

File details

Details for the file lithos_mcp-0.4.0.tar.gz.

File metadata

  • Download URL: lithos_mcp-0.4.0.tar.gz
  • Upload date:
  • Size: 851.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lithos_mcp-0.4.0.tar.gz
Algorithm Hash digest
SHA256 821ecb9944608fe490f57ef93e9f1b8f1beb65a44394cbdeb597613b73fa1ac8
MD5 3d23653c1a7782767129aea4de7592f0
BLAKE2b-256 96d2f12d4afd92f3305c4aff1ddc3847cac1ee8b3e67bf344687ada92668af6b

See more details on using hashes here.

Provenance

The following attestation bundles were made for lithos_mcp-0.4.0.tar.gz:

Publisher: pypi.yml on agent-lore/lithos

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lithos_mcp-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: lithos_mcp-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 231.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lithos_mcp-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 92bc9ec214deaa408118f2fd848fb330e83067a9e1960b005108cb8e02acbf57
MD5 53e592b5df35eefe2159a56f9ea7abb5
BLAKE2b-256 d8e9c7c1e27d594d6b8f9010b706402e37c2ecf11bffc7695c2c4944089081d2

See more details on using hashes here.

Provenance

The following attestation bundles were made for lithos_mcp-0.4.0-py3-none-any.whl:

Publisher: pypi.yml on agent-lore/lithos

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page