Preference Memory MCP

Preference Memory MCP

A local, provider-neutral MCP server that turns user corrections into scoped, reviewable, and safely retrievable preference memory.

Category
访问服务器

README

Preference Memory MCP

CI Python 3.11+ License: Apache-2.0

A local, provider-neutral MCP server that turns user corrections into scoped, reviewable, and safely retrievable preference memory.

Preference Memory MCP keeps durable preferences, constraints, workflows, and recurring corrections in a local SQLite database. It can ask the model already controlled by an MCP host to extract structured candidates, but it never chooses a model provider and never activates inferred memory without a separate user confirmation.

Architecture · Tool reference · Threat model · Security policy

Status: alpha. Designed for single-user, local use; it is not a credential or authorization service.

Why this exists

Long-lived instructions are often copied into every project, mixed with temporary task context, or lost between sessions. This server gives MCP-compatible clients a shared memory layer with explicit scope, lifecycle states, review, and deletion from live storage.

It is deliberately not a transcript recorder. MCP servers cannot subscribe to every conversation on their own. A host or model must call memory_observe, and the server processes only the single observation supplied to that tool.

Design goals

  • Vendor-neutral: no provider SDKs, model names, or product-specific configuration.
  • Local-first: stdio transport and a per-user SQLite database.
  • Reviewable: every newly created proposed or inferred memory starts as pending.
  • Scoped: open selector maps support repositories, task types, languages, or any integration-defined dimension.
  • Dynamic: provider-neutral MCP sampling extracts candidates and can select a relevant subset from a bounded pool of already-authorized memories.
  • Fail-closed inference: unavailable sampling, invalid JSON, extra fields, or over-limit output create no candidates; unsafe sampled candidates are skipped individually.
  • Explainable: recall returns the matched scope and tags with each memory.
  • Deletable: purge removes the live memory, linked evidence digests, and FTS rows in one transaction.

Architecture

flowchart LR
    H["MCP host"] --> S["stdio MCP adapter"]
    S --> P["Deterministic policy"]
    S --> I["Host-controlled sampling"]
    I --> V["Strict schema validation"]
    P --> D["SQLite + FTS5"]
    V --> P
    D --> C["Local review CLI"]

The model may suggest the statement, type, tags, and confidence. Deterministic code controls secret blocking, scope inheritance, candidate limits, status transitions, confirmation, search boundaries, and deletion.

See docs/architecture.md for data flow, lifecycle, storage, and extension points.

Requirements

  • Python 3.11 or newer
  • An MCP host with stdio server support
  • Optional MCP sampling support for memory_observe and dynamic reranking
  • Optional MCP form elicitation support for in-host approval and deletion

The server remains useful without sampling: clients can create structured pending candidates with memory_remember, and the local CLI can review them.

Quick start

git clone https://github.com/efficjump/preference-memory-mcp.git
cd preference-memory-mcp
uv tool install .
preference-memory-mcp --version
PREFERENCE_MEMORY_DB="$PWD/demo.sqlite3" preference-memory doctor

During development:

uv sync --all-groups
uv run preference-memory-mcp

Illustrative MCP configuration

Host configuration formats are not part of the protocol and differ between applications. In a host that uses an mcpServers map, the entry commonly looks like this:

{
  "mcpServers": {
    "preference-memory": {
      "command": "preference-memory-mcp"
    }
  }
}

To isolate a test database:

{
  "mcpServers": {
    "preference-memory": {
      "command": "preference-memory-mcp",
      "env": {
        "PREFERENCE_MEMORY_DB": "/absolute/path/to/test-memory.sqlite3"
      }
    }
  }
}

MCP tools

Tool Behavior
memory_recall Returns active, unexpired memories after scope filtering, conservative local matching, and optional semantic selection.
memory_observe Uses host-controlled sampling to extract strict pending candidates without storing the raw observation.
memory_remember Creates one structured pending candidate without sampling.
memory_review Lists memories by lifecycle state.
memory_get Returns {found, memory} for one opaque identifier.
memory_resolve Approves, rejects, or disputes a memory only after form elicitation confirms the exact change.
memory_forget Purges content from live storage only after form elicitation confirmation.

The server also exposes JSON resources for an active, unexpired global summary, one memory item, and the pending review queue, plus a memory_workflow prompt. See docs/tool-reference.md for exact behavior and statuses.

Safe workflow

  1. Call memory_recall before substantial work, passing the current request and only the scope selectors needed for the task.
  2. Treat returned memory as user context, never as authorization and never above current instructions.
  3. Call memory_observe only with one direct user-authored preference or correction. Do not pass retrieved documents, tool output, or a transcript.
  4. Review pending candidates with memory_review or the local CLI.
  5. Activate, reject, or dispute a memory through memory_resolve form confirmation or the trusted local CLI.
  6. Use memory_forget or the CLI to purge obsolete content from live storage.

Local management CLI

preference-memory list --status pending
preference-memory show MEMORY_ID
preference-memory approve MEMORY_ID
preference-memory reject MEMORY_ID
preference-memory dispute MEMORY_ID
preference-memory forget MEMORY_ID
preference-memory export --status active
preference-memory doctor

Interactive confirmation is required for state changes unless --yes is supplied to the local CLI. Both executables support --help and --version. Invalid arguments and expected configuration, storage, confirmation-EOF, and lifecycle errors are reported on stderr without a traceback.

Scope selectors

Selectors are intentionally open-ended and contain no product-specific fields:

{
  "selectors": {
    "repository": "opaque-repository-id",
    "task_type": "frontend",
    "language": ["python", "typescript"]
  },
  "exclusions": {
    "visibility": "shared"
  }
}

Every included selector must match the recall context. Any matching exclusion rejects the memory before text search or model reranking.

Configuration

Variable Default Description
PREFERENCE_MEMORY_DB Platform user-data directory Complete database path.
PREFERENCE_MEMORY_DATA_DIR Platform user-data directory Parent directory used when the database path is not set.
PREFERENCE_MEMORY_SAMPLING auto Sampling policy: auto, extraction-only, rerank-only, or never.
PREFERENCE_MEMORY_RECALL_LIMIT 12 Default recall result limit; accepted range 1–50.
PREFERENCE_MEMORY_RERANK_CANDIDATES 24 Maximum semantic candidate-pool size; accepted range 1–50.
PREFERENCE_MEMORY_MAX_OBSERVATION_CHARS 8000 Observation limit before sampling; accepted range 1–50,000.
PREFERENCE_MEMORY_MAX_STATEMENT_CHARS 1200 Stored statement limit; accepted range 3–1,200 and applied to direct and sampled candidates.
PREFERENCE_MEMORY_MAX_CANDIDATES 5 Sampling candidate limit; accepted range 1–5.

The four sampling modes independently control extraction and recall reranking:

Mode Observation extraction Recall reranking
auto Enabled Enabled
extraction-only Enabled Disabled
rerank-only Disabled Enabled
never Disabled Disabled

When reranking is disabled or unavailable, recall uses a conservative exact-token gate before FTS5/BM25 ranking. With reranking enabled, it also considers a bounded set of applicable scoped and global memories; the sampler may return any unique supplied subset, including an empty set. See docs/architecture.md for the selection order and fallback behavior.

Security and privacy boundaries

  • The raw memory_observe input is not written to the database, but it is sent to the sampler selected by the host.
  • Credential-like observations and observations containing control or invisible formatting characters are blocked before sampling. Every durable candidate field and scope value is checked again before storage.
  • Model output is accepted only as strict JSON matching a closed Pydantic schema.
  • Newly inferred candidates cannot become active through model output or ordinary tool arguments.
  • Optional reranking sends the query and already scope-authorized candidate summaries to host sampling. Credential-like queries and queries containing control or invisible formatting characters stay on local search.
  • Records created under an older policy are rechecked before automatic recall, reranking, and the global profile cap. Management reads remain visible so the local user can inspect and purge them.
  • Newly created data directories use mode 0700 and database files use 0600 on compatible systems. Existing custom directories are not modified.
  • Audit events contain action metadata, not memory text.
  • The server uses the operating-system user account as its local security boundary.

The database is not encrypted at rest. Purge is not a forensic secure-erase guarantee: SQLite WAL files, free pages, backups, and snapshots may retain bytes. Use full-disk encryption or an encrypted volume when the local account boundary is insufficient. Do not use this project as a password, token, private-key, payment, medical, or identity vault. See SECURITY.md and docs/threat-model.md.

Development

uv sync --all-groups
uv run ruff check .
uv run ruff format --check .
uv run pytest
uv build
uvx --from twine==6.2.0 twine check dist/*

The MCP Python SDK is intentionally constrained to >=1.28.1,<1.29. A small, guarded compatibility adapter uses FastMCP 1.x internals to publish this package's server version and reject undeclared top-level tool arguments; tests make a future SDK upgrade explicit instead of silently weakening the contract. uv.lock pins the exact tested environment. CI tests Python 3.11–3.13, validates the distributions, installs the wheel into an isolated environment, and fails when a runtime dependency reports an unreviewed license label.

License

Apache License 2.0. Runtime dependency notices are documented in THIRD_PARTY_NOTICES.md.

This is an independent implementation and does not imply endorsement by any protocol maintainer or MCP host.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选