memory MCP server
Commit Oct 29, 2026Provides persistent semantic memory for AI agents using PostgreSQL, pgvector, and local Ollama models for hybrid retrieval and memory management.
Also known as tokarix/memory-server
- Stars
- 1
- Tools
- 17
- Downloads, 30 days
- —
- Latest version
- —
- Last commit
- Oct 29, 2026
- License
- Apache-2.0
What is memory MCP?
memory provides persistent semantic memory for AI agents using PostgreSQL, pgvector, and local Ollama models for hybrid retrieval and memory management. It exposes 17 tools, such as memory_server_version, memory_store, memory_search.
Summary generated from the project's README
About memory MCP server
Providing persistent semantic memory for AI agents is what this service enables through a hybrid retrieval system. It uses PostgreSQL with pgvector for vector similarity and full-text search, combined with local Ollama models like bge-m3 for embeddings and llama3.1 for tasks like query expansion and reranking. The architecture consists of a memoryd HTTP daemon and a memory-mcp stdio adapter that connects to clients like Claude Code or Codex.
Developers can organize information into specific categories such as decisions, error fixes, plans, and rules. The system supports a memory graph with weighted edges to allow for cross-reference traversal and search expansion. It also manages session transcripts through tools like session_log_store to ensure context is preserved even when durable memories are not found.
Setting up the server requires a PostgreSQL 17 instance and an Ollama installation. For distributed teams, the daemon can be configured to listen on all interfaces with an api_token for secure remote access, allowing multiple agents to share a common memory store across different machines.
What you can do with it
- 1Retrieve project contextAn AI agent can load essential architectural decisions and implementation plans at the start of a session.
- 2Search historical error resolutionsDevelopers can use hybrid semantic search to find how previous similar bugs were fixed.
- 3Enforce coding standardsThe system can deliver mandatory project rules and constraints based on the current programming language and profile.
- 4Archive session historyThe server can save full conversation transcripts to be used for later search or audit purposes.
Written from the project's README. Every use case is checked against a quote from it.
memory MCP tools 17
Detected from the READMEmemory_server_versionmemory_storememory_searchmemory_recallmemory_rulesmemory_bootstrapmemory_listmemory_getmemory_updatememory_neighborsmemory_deletesession_start
| memory_server_version | — | |
| memory_store | — | |
| memory_search | — | |
| memory_recall | — | |
| memory_rules | — | |
| memory_bootstrap | — | |
| memory_list | — | |
| memory_get | — | |
| memory_update | — | |
| memory_neighbors | — | |
| memory_delete | — | |
| session_start | — |
Show all 17 toolsShow fewer tools
session_message_appendsession_finalizesession_log_storereview_queuereview_submit
| session_message_append | — | |
| session_finalize | — | |
| session_log_store | — | |
| review_queue | — | |
| review_submit | — |
Configuration
RUST_LOG
| Name | Description | |
|---|---|---|
| RUST_LOG | — |
Automated checks
Ran Nov 14, 2026Full report →Not verified yet. A server needs a score of 80, no serious finding, and enough data for us to check. How checks work · What to fix for more points
- Source repository linked and reachabletokarix/memory-server is public and reachablegithub.com/tokarix/memory-server ↗Pass
- Package names this repository as its sourceNot checked
- Build provenance (Sigstore attestation)Not checked
- Open source license (OSI)Apache-2.0spdx.org/licenses/Apache-2.0.html ↗Pass
- Commit or release in the last yearLast commit or release 2026-10-29github.com/tokarix/memory-server ↗Pass
- OpenSSF ScorecardNot checked
- Package name not close to a popular packageNot checked
- No critical advisory in the package or its dependenciesNot checked
- No hidden instructions to the model17 tool descriptions and the README read; no override phrases, credential paths or hidden charactersPass
- Destructive tools are labelledNo tool named like delete, drop or execPass
- Remote endpoint answers the MCP handshakeNot checked
README
View on GitHubmemory-server
Semantic memory service and MCP adapter backed by PostgreSQL, pgvector, and local Ollama models.
Current layout:
agent client <--stdio--> memory-mcp <--HTTP--> memoryd
|
+--> memory-common
|
+--> PostgreSQL + pgvector
|
+--> Ollama
Workspace crates:
memory-common: shared config, models, transcript parsing, error types, and HTTP/MCP payload typesmemoryd: the HTTP service plusdreamandingestmaintenance binariesmemory-mcp: the stdio MCP adapter that talks tomemorydover HTTP
Current features
- Persistent semantic memories with embeddings stored in PostgreSQL
- Hybrid retrieval: vector similarity plus PostgreSQL full-text search
- Optional query expansion and LLM reranking for
memory_search - Core-memory recall at session start with
memory_recall - CRUD tools: store, search, list, get, update, delete
- Memory graph: weighted edges between memories for cross-reference traversal and search expansion
- Session transcript archival via
session_log_store - Session-log fallback search when no durable memories match
- Maintenance binaries for transcript ingest and dream/prune passes
Memory categories
| Category | Purpose |
|---|---|
context |
Project conventions and stable background |
decision |
Architectural or workflow decisions |
error_fix |
Symptoms, root cause, and resolution |
plan |
Reusable implementation plans |
rule |
Durable instructions or constraints |
memory_recall returns the categories considered core by the current
implementation: decision, error_fix, plan, and rule.
Semantic search and standalone recall exclude task-scoped workflow artifacts
by default. These retained audit records include plans tagged with a valid
task:<uuid> or legacy superseded-for-task:<uuid> marker, earlier Plan
revisions reached recursively through supersedes-plan:<uuid>, Decisions that
target a marked Plan through reviewed-item:<uuid>, and session transcripts
containing a valid task:<uuid> token. Pass
include_workflow_artifacts=true to memory_search or memory_recall to use
the previous inclusive behavior.
The default applies before vector, full-text, graph-neighbor, and session-log
candidate limits, so protected records cannot consume an ordinary result
window. Exact listing and direct retrieval remain inclusive, as do public
neighbor, review, normalized-session, and session-log browsing surfaces.
memory_bootstrap retains its stronger policy: its recall payload omits every
Plan and review Decision even though standalone recall has an opt-in.
See the workflow artifact verification notes for relationship indexing, review contracts, query-plan comparisons, and tests.
Prerequisites
- Rust 1.88+
- PostgreSQL 17 with
pgvector - Ollama with:
- embedding model:
bge-m3 - generation models: defaults use
llama3.1
- embedding model:
Setup
1. Start PostgreSQL with pgvector
Example with Podman:
podman run -d --name memory-pg \
-e POSTGRES_DB=memory \
-e POSTGRES_USER=memory \
-e POSTGRES_PASSWORD=memory \
-p 5432:5432 \
-v memory-pg-data:/var/lib/postgresql/data \
pgvector/pgvector:pg17
2. Pull the Ollama models
ollama pull bge-m3
ollama pull llama3.1
3. Configure the server
Copy and edit config.toml.example if needed:
http_bind = "127.0.0.1:8080"
memoryd_url = "http://127.0.0.1:8080"
database_url = "postgres://memory:memory@localhost/memory"
ollama_url = "http://localhost:11434"
embedding_model = "bge-m3"
expand_model = "llama3.1"
rerank_model = "llama3.1"
dream_model = "llama3.1"
expand_num_ctx = 8192
rerank_num_ctx = 8192
dream_num_ctx = 8192
Configuration fields:
| Field | Default | Purpose |
|---|---|---|
database_url |
postgres://memory:memory@localhost/memory |
PostgreSQL connection string |
http_bind |
127.0.0.1:8080 |
Bind address for memoryd |
memoryd_url |
http://127.0.0.1:8080 |
Base URL used by memory-mcp |
guardrails_project |
required for MCP | Explicit work project for mandatory guardrails; use general for a general-only session |
ollama_url |
http://localhost:11434 |
Ollama base URL |
embedding_model |
bge-m3 |
Embedding model |
embedding_tokenizer_repo |
None |
HF hub repo (e.g. BAAI/bge-m3) to download tokenizer from for guided truncation |
embedding_tokenizer_revision |
main |
HF hub repo revision (branch/tag/SHA) |
expand_model |
llama3.1 |
Query expansion model |
rerank_model |
llama3.1 |
Search reranking model |
dream_model |
llama3.1 |
Dream/prune maintenance model |
expand_num_ctx |
8192 |
Context window for query expansion |
rerank_num_ctx |
8192 |
Context window for search reranking |
dream_num_ctx |
8192 |
Context window for dream maintenance |
generate_num_ctx |
8192 |
(Legacy) Context window for all generation calls; used as fallback |
4. Build
cargo build -p memory-mcp --release
cargo build -p memoryd --release
When building a specific workspace package from the repository root,
always pass -p <package>. For example, use cargo build -p memory-mcp --release instead of cargo build --bin memory-mcp --release, because
the latter can still pull in other workspace members and unify their
features.
5. Run
RUST_LOG=info ./target/release/memory-mcp ./config.toml
RUST_LOG=info ./target/release/memoryd ./config.toml
memoryd runs the HTTP service on http_bind. memory-mcp is the
stdio adapter that calls memoryd_url.
MCP client setup
Minimal memory-mcp config:
memoryd_url = "http://127.0.0.1:8080"
guardrails_project = "memory-server"
resolution_context = { profile = "workstation-host", phase = "implementing", language = ["rust"] }
# api_token = "replace-me"
memoryd uses the full server config shown earlier. memory-mcp also
requires an explicit guardrails_project and a trusted context sufficient to
resolve the policies in that project. Startup fails if the daemon cannot
deliver a nonempty mandatory pack. Configure api_token if enabled on the
daemon. See guardrail delivery for rollout and
reconnection behavior.
Codex
Add an MCP server entry to ~/.codex/config.toml:
[mcp_servers.memory]
command = "/absolute/path/to/target/release/memory-mcp"
args = ["/absolute/path/to/config.toml"]
[mcp_servers.memory.env]
RUST_LOG = "info"
Claude Code
Add a stdio MCP server entry to ~/.claude.json:
{
"mcpServers": {
"memory": {
"type": "stdio",
"command": "/absolute/path/to/target/release/memory-mcp",
"args": ["/absolute/path/to/config.toml"]
}
}
}
Multi-agent / distributed setup
For use cases where multiple agents across different machines or locations need to share a common memory store:
1. Server-side configuration
By default, memoryd binds to 127.0.0.1, which only allows local connections.
To make it reachable over a network, set http_bind to 0.0.0.0 (all
interfaces) or a specific IP address in your config.toml:
http_bind = "0.0.0.0:8080"
2. Authentication
When the service is reachable over a network, you must enable api_token in
the server config.toml. The default (no token) is only appropriate for
private localhost use.
api_token = "your-secure-shared-secret"
3. Client-side configuration
Each agent's memory-mcp needs to know where the central memoryd is running.
In each agent's local config.toml, set memoryd_url to the server's actual
address and include the api_token:
memoryd_url = "http://memory.example.com:8080"
api_token = "your-secure-shared-secret"
4. Firewall and Reverse Proxy
memoryd speaks plain HTTP. For internet-facing setups or when traversing
untrusted networks, it is recommended to run memoryd behind a reverse proxy
(such as Nginx or Caddy) that provides TLS (HTTPS) termination.
5. Sharing memory across agents
Multiple agents (e.g. Claude Code on a laptop and Codex on a remote server) can
all point to the same memoryd instance. They will share all memories
within the same project namespace, enabling cross-agent collaboration and
persistent context.
HTTP API
memoryd currently exposes:
GET /api/v1/healthPOST /api/v1/memoriesPOST /api/v1/memories/searchGET /api/v1/memories/{id}PATCH /api/v1/memories/{id}DELETE /api/v1/memories/{id}GET /api/v1/projects/{project}/recallPOST /api/v1/sessions
If api_token is set in config, all /api/v1/* routes except health
require Authorization: Bearer <token>.
Available MCP tools
| Tool | Purpose |
|---|---|
memory_server_version |
Return version plus git hash |
memory_store |
Store a new memory |
memory_search |
Hybrid semantic search within a project |
memory_recall |
Load core memories for a project |
memory_rules |
Load general + project durable rules |
memory_bootstrap |
Load effective rules plus non-rule core recall |
memory_list |
Browse memories by project/category |
memory_get |
Fetch a single memory by UUID |
memory_update |
Update summary/content/tags and re-embed if needed |
memory_neighbors |
List neighbor memories reachable via graph edges |
memory_delete |
Delete a memory by UUID |
session_start |
Create or upsert a normalized shared session |
session_message_append |
Append a prompt/response/tool event to a shared session |
session_finalize |
Finalize a shared session into searchable chunks |
session_log_store |
Store a full session transcript for archival/search |
review_queue |
List memories tagged review-needed, with optional category filter |
review_submit |
Store a review decision and mark the original reviewed |
Policy identity for Rules
Rules may carry structured policy metadata. A legacy Rule has policy: null
and remains contextual; existing rows are never classified from their text or
tags. A classified Rule has a project-local policy_key, a positive revision,
a delivery_class of contextual or mandatory, a server-controlled state,
and an optional predecessor UUID in supersedes. The active revision is
resolved by memory_rules and memory_bootstrap; superseded revisions remain
available through memory_get, memory_list, and search. Applicable mandatory
Rules are delivered regardless of tags or include_general.
Classified Rules may also declare selectors for profile, phase,
language, and tool, plus exact values for shared settings. Omitted
selector dimensions match every execution. Selector members within one
dimension are alternatives; dimensions combine. For example,
{"selectors":{"profile":["workstation-host"],"language":["rust"]},"values":{"rust.build.target_storage":"persistent-disk"}}
applies only to Rust work on the workstation host. These fields are immutable
within a revision. One active revision remains per (project, policy_key);
environment variants use distinct keys.
MCP execution context comes from the operator's resolution_context in
config.toml, not from tool arguments, tags, the daemon's host, or model text.
The default is unknown. A tool context argument can only assert values
already bound at startup. Direct authenticated HTTP callers may pass a typed
URL-encoded JSON context query value. The hook uses the operator-supplied
MEMORY_RESOLUTION_CONTEXT JSON environment value. Missing context for a
participating scoped policy fails visibly with policy_context_required.
See policy resolution for precedence, diagnostics,
canonical output, and rollout details.
The pinned host/container conversion manifest and operator steps are in
storage policy conversion.
To publish a new root, call memory_store with category rule and a complete
write payload such as
"policy":{"policy_key":"build.storage","revision":1,"delivery_class":"contextual"}.
To revise it, store a new Rule with a higher revision and supersedes set to
the current active revision's UUID. Classified content, summary, tags, and
delivery class are immutable; editing them requires a new revision. A key is
1–128 ASCII bytes, starting with a lowercase letter or digit, followed only
by lowercase letters, digits, ., _, :, or -.
To classify an existing legacy Rule while preserving its UUID and contents:
- Call
memory_get(id)and inspect its project, category, content, summary, tags, andpolicy: nullstatus. Copy theupdated_at:field from the metadata header before the blank line that introduces content. It is the persisted UTC instant with nine fractional digits andZ, for example2026-09-26T12:34:27.123456000Z. The separateUpdated:minute display is never a concurrency token. - Call
memory_updatewith onlyid, that exactexpected_updated_atvalue, and the complete write payload. Example:{"id":"<legacy-rule-uuid>","expected_updated_at":"2026-09-26T12:34:27.123456000Z","policy":{"policy_key":"build.storage","revision":1,"delivery_class":"contextual"}}. Replace the example timestamp with the actual value just read. - On success, call
memory_geton the same UUID to verify the committed identity. If the server returnspolicy_stale_assignment, read and inspect the changed Rule again before deciding whether to retry. Never refresh the token and classify text you have not inspected.
Stop older write-capable memoryd instances before enabling classification;
they do not have the new immutability guards. The policy migration rolls back
only while every Rule remains unclassified. Once classification occurs, its
down migration refuses to discard identity and history. Use a separately
authorized export or restore procedure for that case.
memory_search behavior:
- expands the user query with the configured LLM
- runs hybrid vector + FTS retrieval against durable memories
- expands seed results via graph edges (same-project by default)
- optionally reranks the combined set with the configured rerank model (disabled by default)
- falls back to session-log search if no durable memories match
- excludes task-scoped workflow artifacts at every retrieval stage unless
include_workflow_artifacts=true
Additional binaries
ingest
Parses a JSONL transcript file and stores it into session_logs and
session_log_chunks.
cargo run -p memoryd --release --bin ingest -- ./config.toml /path/to/transcript.jsonl
Dry run:
cargo run -p memoryd --release --bin ingest -- --dry-run ./config.toml /path/to/transcript.jsonl
dream
Runs maintenance passes that merge near-duplicate memories and prune
stale low-importance memories. plan and rule memories are protected
from these mutations.
cargo run -p memoryd --release --bin dream -- ./config.toml
Dry run:
cargo run -p memoryd --release --bin dream -- --dry-run ./config.toml
Database notes
Migrations currently create and evolve:
memoriessession_logssession_log_chunks- full-text search support on memories and session logs
- HNSW vector indexes for semantic retrieval
The current schema is migration-driven. For the next planned shape, see
docs/http-api-v1.md.
Hooks
For mandatory startup guardrails, use the managed memory-hooks session-start
helper with a protected version-two or version-three configuration and a fixed installation
anchor. It fetches a fresh classified mandatory pack for every supported
SessionStart, publishes its exact text to Codex or Claude Code, and records
the local output result for later validation. Provisioning, client registration,
root migration, and recovery are described in
docs/hooks-delivery.md. Startup delivery is not
action gating. The managed memory-hooks pre-tool command checks a fresh
pack for every observed PreToolUse event, records a required private audit
entry, and returns an empty neutral result only after exact snapshot equality.
See managed gate operations for registration, denial,
recovery, coverage and maintenance.
See managed delegated hooks for the direct-child
Claude contract, pinned client evidence, recovery, and coverage limits.
The shell scripts below are legacy optional recall and transcript-capture
features. They do not establish mandatory delivery and should be configured
separately from the managed helper. Their /tmp state and remote session writes
are not imported by memory-hooks.
A Claude Code PreCompact hook script is included at
hooks/pre-compact.sh. It runs the ingest
binary against the session transcript before compaction.
Additional hook scripts are available for durable rule bootstrap and per-message session capture:
hooks/bootstrap.sh: fetches and cachesmemory_bootstrapoutput for the current session and creates the normalized remote session rowhooks/capture-message.sh: append a user or assistant message to the normalized remote session streamhooks/pre-command.sh: retired migration denial; remove old PreToolUse registrations and use the managed gatehooks/session-stop.sh: final flush of the normalized session into searchable chunks
This lets you save each prompt and each response as the session unfolds, with agent identity, instead of only storing a transcript at compaction time.
Example wiring with explicit agent identities:
{
"hooks": {
"SessionStart": [{
"hooks": [{
"type": "command",
"command": "/absolute/path/to/memory-server/hooks/bootstrap.sh claude"
}]
}],
"UserPromptSubmit": [{
"hooks": [{
"type": "command",
"command": "/absolute/path/to/memory-server/hooks/capture-message.sh claude user"
}]
}],
"AssistantResponse": [{
"hooks": [{
"type": "command",
"command": "/absolute/path/to/memory-server/hooks/capture-message.sh claude assistant"
}]
}],
"PreCompact": [{
"hooks": [{
"type": "command",
"command": "/absolute/path/to/memory-server/hooks/pre-compact.sh"
}]
}],
"Stop": [{
"hooks": [{
"type": "command",
"command": "/absolute/path/to/memory-server/hooks/session-stop.sh"
}]
}]
}
}
Notes:
- Use
claudeandcodexas explicit first arguments if both clients write into the same memory service. That makes the stored session events attributable during search/finalization. - The exact event names vary by client. Map these scripts to the closest available events in each client.
- The scripts expect
jqandcurl. - They read
memoryd_urland optionalapi_tokenfromconfig.toml, or fromMEMORY_SERVER_CONFIGif you want to point at another config file. - Hook state is cached under
/tmp/memory-server-hooks/<external-session-id>/.
The managed helper's trust and private-state boundary is documented in
docs/hooks-trust.md. Its configuration and state are
separate from the legacy hook files. Existing historical raw command logs are
not automatically scrubbed, and separately configured transcript systems may
still capture raw tool input.
For durable instruction enforcement, prefer the following flow over
duplicating guidance in AGENTS.md or CLAUDE.md:
- Store durable instructions as
rulememories. Put cross-project rules under projectgeneral; put repo-specific rules under that repo's project name. - Use managed
memory-hooks session-startfor the mandatory pack. Optionalmemory_bootstrap(project)can still add supporting non-rule recall. - Call
memory_rules(project)from pre-action hooks when only the enforceable rule set is needed. - Keep hooks focused on deterministic enforcement and verification that does not preempt the client's own permission flow: ensuring bootstrap has happened where needed and recording compliance failures.
- Keep memory rules focused on durable intent and policy that the model must follow but that a shell hook cannot reliably derive on its own.
Memory Graph
Memories are connected by weighted edges stored in the memory_edges
table. Edges enable graph-aware search expansion and cross-reference
navigation.
Edge types
| Relation | Direction | Description |
|---|---|---|
references |
directed | Explicit reference from one memory to another |
related_tag |
undirected | Shared non-structural tags between memories |
similar |
undirected | Embedding cosine similarity neighborhood |
Edge origins
| Origin | When created |
|---|---|
content_uuid_ref |
Write-time: UUID found in memory content |
structural_tag_ref |
Write-time: structural tag like plan:<uuid> |
shared_tag |
Dream maintenance: shared topical tags |
embedding_neighbor |
Dream maintenance: cosine similarity 0.75–0.92 |
usage_reinforcement |
Future: successful retrieval signals |
manual |
Future: explicit user/admin edits |
Search expansion
memory_search expands results via graph edges between outer RRF and
LLM reranking. Expansion follows non-suppressed edges with weight ≥ 0.5.
Scope policy (all conservative by default):
- Same-project edges: always followed
generalproject: only wheninclude_general=true- Foreign projects: only when
cross_project=true, optionally filtered byproject_allowlist - Task-scoped workflow artifacts: only when
include_workflow_artifacts=true
Score decay per hop: 0.7×, with additional discounts for general
(0.9×) and foreign projects (0.5×).
Graph maintenance
The dream binary includes a graph refresh phase that runs before
merge/prune. It builds similar and related_tag edges using
idempotent upserts. ON DELETE CASCADE on both foreign keys ensures
edges are cleaned up when memories are deleted.
Graph refresh remains inclusive, but merge and prune maintenance exclude workflow artifacts during candidate generation and recheck provenance inside the mutation transaction. Historical workflow plans, reviews, and transcripts are retained for audit and explicit retrieval.
Review Workflow
For cross-agent collaboration, use the review-needed tag on any memory
to request review, and the review_queue/review_submit tools to
manage the workflow.
Plan reviews
- Claude stores a
planmemory taggedreview-needed. - Codex calls
review_queue(project, category: "plan")to find pending plan reviews. - Codex reviews the plan and calls
review_submit(...). review_submitstores adecisionmemory linked to the plan and updates the original plan tags fromreview-neededtoreviewed.
Code reviews
- An agent stores a
contextmemory taggedreview-neededandcode-review, with git range and description in the content. - Another agent calls
review_queue(project)orreview_queue(project, category: "context")to find pending reviews. - The reviewer inspects the code and calls
review_submit(...). review_submitstores adecisionmemory and retags the original.
memory MCP questions
What tools does memory MCP provide?
It exposes 17 tools, including memory_server_version, memory_store, memory_search, memory_recall, memory_rules.
What technologies power the memory service?
The service is backed by PostgreSQL with pgvector for vector storage and local Ollama models for embeddings and generation.
How can I share memory across multiple agents?
You can point multiple agents to a central memoryd instance by setting the memoryd_url in their configuration and enabling an api_token for network access.
Does the server support hybrid search?
Yes, it provides hybrid retrieval using both vector similarity and PostgreSQL full-text search.