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
.mdfiles - 🔍 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_listmetadata_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
- CLI Reference — installing and using the
lithoscommand-line tool - Specification — full technical specification
- LCMA Design — design notes
- Generated architecture docs — diagrams, metrics, tool catalog, container view, and per-component drill-downs generated from the code, drift-checked in CI (
make diagrams)
Metadata Filtering
Lithos supports arbitrary metadata on both notes and tasks.
- Notes:
lithos_write(metadata={...})stores free-form metadata in frontmatter.lithos_readreturns it undermetadata.extra;lithos_listreturns it as each item'smetadata. - Tasks:
lithos_task_create(metadata={...})stores initial metadata;lithos_task_update(metadata={...})applies a per-key merge patch. - Note update semantics: omit or
nullpreserves existing metadata,{}clears all metadata, and{"key": null}deletes one key. - Task update semantics: omit or
nullpreserves existing metadata,{}is a no-op, and{"key": null}deletes one key. - Filtering:
metadata_matchis AND-across-keys. Eachkey: valuematches 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 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.
It is a global option, so it works for any command — not just serve:
lithos --data-dir ./data --telemetry-console serve
lithos --data-dir ./data --telemetry-console reconcile
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
Metadata
Release files for lithos-mcp 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| lithos_mcp-0.6.0.tar.gz | 1.1 MB | With provenance | Details for lithos_mcp-0.6.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| lithos_mcp-0.6.0-py3-none-any.whl | Python 3 | none | any | Details for lithos_mcp-0.6.0-py3-none-any.whl |
Total release size: 1.4 MB
Release files / lithos_mcp-0.6.0.tar.gz
| Download URL | lithos_mcp-0.6.0.tar.gz |
|---|---|
| Size | 1.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e1eb22112d4e02faf3bb639e6b2a93d7f4ca8b1578f9a4a73947d8899d22cb18
|
|
BLAKE2b-256 checksum How to use checksums |
ec8ae6e6ce51e83f16757e80b14dc0ac38a875bd2fdb49600028e7aadb6f27ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logRelease files / lithos_mcp-0.6.0-py3-none-any.whl
| Download URL | lithos_mcp-0.6.0-py3-none-any.whl |
|---|---|
| Size | 302.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fd97aba81d4938e90cc7f6d1e3b3aadb9c430c3ac3db4fb4feff2e9b6730d9bf
|
|
BLAKE2b-256 checksum How to use checksums |
9b501261e433dc7bdaa9168e088fb4d92de1f9aa1594d3c7b1713593de0d0a87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logSecurity for lithos-mcp 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for lithos_mcp-0.6.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.