mempill-mcp
MCP adapter for the mempill AI-agent memory engine.
A FastMCP server exposing 5 tools over stdio transport. Backed by the mempill Python wheel
(which wraps the Rust engine). Requires Python ≥ 3.11.
See the root README for full architecture and concepts.
Install
pip install mempill-mcp
Run
export MEMPILL_AGENT_ID="my-agent" # required
export MEMPILL_DB_DIR="/data" # optional; omit for in-memory (ephemeral)
mempill-mcp
Or: python -m mempill_mcp
The server starts on stdio transport (the default for Claude Desktop and other MCP clients).
Environment contract
| Variable | Required | Description |
|---|---|---|
MEMPILL_AGENT_ID |
Yes | Unique agent identifier. The server fails fast if not set. |
MEMPILL_DB_DIR |
No | Base directory for SQLite storage. The database file is derived automatically as MEMPILL_DB_DIR/agent_{MEMPILL_AGENT_ID}.db. Omit for in-memory (data lost on exit). |
Breaking change (0.4.0):
MEMPILL_DB_PATH(a full file path) was replaced byMEMPILL_DB_DIR(a base directory), because storage is now opened viamempill.open_for_agent(base_dir, agent_id)— the file path is always derived fromagent_id, so it is no longer possible to point two different agents at the same file. Existing pre-0.4.0MEMPILL_DB_PATHdatabases are not auto-migrated; pointMEMPILL_DB_DIRat a fresh directory, or migrate the old file manually (see themempill-sqliteCHANGELOG).
The engine is opened once at startup (FastMCP lifespan) and shared across all tool calls.
Tools
ingest_claim
Write a belief claim to the engine.
Parameters:
subject(str) — the entity the claim is about, e.g."user:alice"predicate(str) — the property being asserted, e.g."location"value(any JSON) — the claimed valueprovenance(str or dict) — see belowcardinality(str, default"Functional") —"Functional"|"SetValued"|"Unknown"confidence_value(float, default 0.9) — value confidence in [0, 1]confidence_valid_time(float, default 0.9) — not persisted; currently a no-op. The mempill storage layer (SQLite and Postgres both) keeps only a singlevalid_time_confidencecolumn per claim, and that column is populated exclusively fromvalid_time["valid_time_confidence"](see below). This parameter's value is forwarded into the ingest request but is silently dropped by both storage backends — it is never written, never read back, and has no effect on gating, succession, or the returned belief. Do not rely on this parameter for anything; it will be removed or wired up in a future release. The single source of truth for valid-time confidence isvalid_time["valid_time_confidence"].criticality(str, default"Low") —"Low"|"Medium"|"High"|"Critical"valid_time(dict, optional) —{"start"?: ISO-8601, "end"?: ISO-8601, "valid_time_confidence": float, "start_granularity"?: str, "end_granularity"?: str}.start/endare optional (omit for unknown/open-ended).valid_time_confidence(inside this dict) is the authoritative temporal-confidence value: it is the one persisted to storage, the one every downstream engine decision reads (incoherence gating, succession detection, valid-time ordering — seemempill-core'sgate.rs/truth_engine.rs/valid_time_helpers.rs), and the one echoed back in bothbelief.valid_time.valid_time_confidenceandbelief.confidence.valid_time_confidenceonquery_memory. It is required whenever thevalid_timedict is supplied at all (no default — omit the wholevalid_timedict, not just this key, if you have no temporal confidence to give; omitting the dict entirely defaults the stored confidence to0.0, i.e. "unknown").start_granularity/end_granularityare optional display-only precision hints — one of"year","month","day","instant"— recording how preciselystart/endwere known (e.g."year"for a bare"2024"normalised to a full timestamp); omit for full ISO-8601 instants or when precision is unknown. They are never used for matching or ordering, only for honest display on read (seequery_memorybelow).derived_from(list[str], optional) — source claim UUIDs
Returns: {"claim_ref": str, "disposition": str, "contested_with": [str]}
Non-committed dispositions include a "status_reason" field.
query_memory
Read the canonical belief for a (subject, predicate) pair.
Parameters:
subject(str)predicate(str)as_of_tx_time(str, optional) — ISO-8601 UTC timestamp; rewinds the transaction-time axisvalid_at(str, optional) — ISO-8601 UTC timestamp; filters by real-world validity window (independent ofas_of_tx_time)
Returns: {"belief": {...BeliefProjection...}}. Each belief slot (belief.primary,
belief.alternatives[i]) also carries honest-display precision metadata:
valid_from_display / valid_until_display (pre-rendered strings at the recorded
precision, e.g. "2020-03" for Month, absent when the endpoint is unknown/open) and the
raw valid_time.start_granularity / valid_time.end_granularity tags.
reconcile
Trigger conflict reconciliation for a set of subject lines.
Parameters:
subject_lines(list[list[str]]) — list of[subject, predicate]pairs
Returns: {"outcomes": [[claim_ref, disposition], ...], "oracle_escalations": int}
audit
Query the immutable ledger for claim history.
Parameters:
limit(int, default 50) — max entries to returnclaim_ref(str, optional) — filter by specific claim UUIDfrom_tx_time(str, optional) — ISO-8601 UTC lower bound on transaction time
Returns: {"entries": [LedgerEntry, ...]}
end_fact
End an open-ended fact: explicitly close the incumbent claim on a (subject, predicate)
line as of a given instant (the SDK contract's assert_validity op). This is the correct
way to say "X stopped being true at time T" — it bounds the incumbent claim in place (the
original row is never touched or duplicated), so a later non-overlapping claim on the
same line folds to a clean succession with no conflict and no adjudication needed.
Resolution never guesses which claim to close: zero live claims raises NotFoundError,
exactly one live claim is bounded, and more than one live claim (a genuinely contested or
set-valued line) raises ValidationError — inspect the line via ingest_claim /
query_memory and resolve the ambiguity before retrying.
Parameters:
subject(str)predicate(str)at(str) — ISO-8601 date/time the fact stopped being true. AcceptsYYYY,YYYY-MM,YYYY-MM-DD, or full RFC3339.provenance(str or dict, optional) — same forms asingest_claim(see below). Must be first-hand external evidence — only the host acting as its own oracle may close or reopen a fact. Defaults toExternal:UserAsserted.confidence(float, default 1.0) — confidence in this validity assertion, in [0, 1]
Returns: {"claim_ref": str, "disposition": str, "effective_at": str, "no_op": bool}.
no_op is true only when this call repeated an identical bound already in effect — no
new write was made. Repeating end_fact on an already-fully-closed line (nothing left
live) raises NotFoundError, not a no-op — there is no live claim left to close.
Provenance strings
ingest_claim accepts provenance as a friendly string (case-insensitive, separator-tolerant)
or as a wire-shape dict:
| String | Wire dict |
|---|---|
"External:UserAsserted" |
{"type": "External", "kind": "UserAsserted"} |
"External:ExternalFirstHand" |
{"type": "External", "kind": "ExternalFirstHand"} |
"RecallReEntry" |
{"type": "RecallReEntry"} |
"ModelDerived" |
{"type": "ModelDerived"} |
License
Apache-2.0. See LICENSE for the full text.
Release files for mempill-mcp 0.4.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 | |
|---|---|---|---|
| mempill_mcp-0.4.0.tar.gz | 19.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mempill_mcp-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.0 kB
Release files / mempill_mcp-0.4.0.tar.gz
| Download URL | mempill_mcp-0.4.0.tar.gz |
|---|---|
| Size | 19.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
25b706057f0ea5441c8b61bbc674e833c301b35911483a28666fbdb375445d4e
|
|
BLAKE2b-256 checksum How to use checksums |
c34a500a012cea29a0d35db19fb93ba3bd440cb2fcfe1e66dc3661d372d484a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / mempill_mcp-0.4.0-py3-none-any.whl
| Download URL | mempill_mcp-0.4.0-py3-none-any.whl |
|---|---|
| Size | 12.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
325cb36ff84f142700783fe14240e3cf8db520725a3327b9d544d6b3b3c14a1e
|
|
BLAKE2b-256 checksum How to use checksums |
30210b59cd687b95dd5ff5407ed12833a97b74ef0460833ab16aa0ee425cc748
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|