System Tools & HTTP Endpoints¶
One MCP tool (lithos_stats) plus the three plain HTTP routes the server mounts alongside the MCP transports.
lithos_stats¶
Knowledge base statistics and health indicators. Cheap to call — use it to understand KB scale before issuing broad queries, or as a health probe from agent code.
Returns:
{
"documents": 1234,
"chroma_chunk_count": 5678,
"agents": 5,
"active_tasks": 12,
"open_claims": 8,
"tags": 89,
"duplicate_urls": 0,
"index_drift_detected": false,
"tantivy_doc_count": 1234,
"unresolved_links": 3,
"expired_docs": 2,
"expired_claims": 0,
"tantivy_last_updated": "2026-09-01T12:00:00+00:00",
"chroma_last_updated": "2026-09-01T12:00:00+00:00",
"graph_node_count": 1240,
"graph_edge_count": 3100
}
| Field | Meaning |
|---|---|
documents |
Markdown documents in the corpus |
chroma_chunk_count |
Semantic chunks in ChromaDB (0 when the store is quarantined) |
tantivy_doc_count |
Documents in the full-text index; null when the index is unavailable (distinct from 0) |
index_drift_detected |
tantivy_doc_count disagrees with documents — run lithos reindex |
unresolved_links |
[[wiki-links]] pointing at documents that don't exist |
expired_docs |
Documents past their expires_at freshness deadline |
expired_claims |
Task claims past their TTL (cleaned lazily) |
graph_edge_count |
All wiki-link graph edges including ones to unresolved placeholders (= resolved edges + unresolved_links) |
HTTP Endpoints¶
When run with --transport http, one port serves both MCP transports — POST /mcp (StreamableHTTP, stateless) and GET /sse + POST /messages/ (legacy SSE) — plus these three routes. They are not MCP tools and do not appear in tools/list.
There is no GET /metrics — metrics are pushed via OTLP; see Observability.
GET /health¶
Lightweight health check for Docker HEALTHCHECK, load balancers, and monitoring.
200 OK:
{
"status": "ok",
"timestamp": "2026-09-01T12:00:00+00:00",
"components": {
"kb_directory": {"status": "ok"},
"search": {"status": "ok"},
"knowledge_base": {"status": "ok"}
}
}
503 Service Unavailable: same shape with "status": "degraded" and per-component error strings.
| Component | Check |
|---|---|
kb_directory |
Knowledge base directory exists on disk |
search |
SearchEngine.health() — composed full-text + semantic + embedding-model signal |
knowledge_base |
Can list at least one document |
GET /events¶
Best-effort Server-Sent Events stream over the in-memory event bus.
Query parameters / headers:
| Name | Description |
|---|---|
types |
Comma-separated event type filter (e.g. note.created,task.completed) |
tags |
Comma-separated tag filter; any matching tag passes |
since |
Replay buffered events strictly after the given event ID |
Last-Event-ID header |
Standard SSE reconnect; takes precedence over since |
Event types: note.created, note.updated, note.deleted, note.renamed, edge.upserted, task.created, task.updated, task.claimed, task.released, task.completed, task.cancelled, task.reopened, finding.posted, agent.registered.
Behavior:
- Replays from the in-memory ring buffer (default 500 events) when
since/Last-Event-IDis supplied, then streams live. - When the reconnect id is not in the ring (evicted, or from a previous server run), the stream emits an
event: resynccontrol message — deliberately with noid:line, so it never becomes the client's nextLast-Event-ID— telling the client to re-fetch current state instead of trusting a truncated replay. Consumers must handleresync. - Periodic keepalive comments when idle.
503whenevents.sse_enabled=false;429whenevents.max_sse_clientsis exceeded;401when MCP auth is configured and the request is unauthenticated.- Delivery is best-effort and process-local — events outside the ring buffer cannot be replayed. Treat the stream as a cache-invalidation hint, not a durable log.
GET /audit¶
Read-only access to the audit log of document reads (search results returned, documents fetched).
Query parameters:
| Name | Type | Description |
|---|---|---|
agent_id |
string | Filter to entries reported by this agent |
after |
string | ISO-8601 timestamp; only entries after this time |
limit |
int | Max entries (default 100) |
doc_id |
string | Filter entries for a specific document |
Returns:
200—{"entries": [{"id": …, "agent_id": "…", "doc_id": "…", "operation": "…", "timestamp": "…"}]}400—{"error": "invalid_after", "message": "…"}whenaftercannot be parsed503—{"error": "audit_log_unavailable", "entries": []}when the coordination layer fails
Trust boundary
The endpoint is unauthenticated and agent_id values are self-reported by callers. The audit log is advisory-only — never use it for access control. Suitable for trusted-network deployments only.
The same data is available from the CLI: lithos audit --agent <id> --since <iso> --limit 50.