You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a Python MCP server that exposes agentic-memory as persistent memory infrastructure for external agents such as Claude Code, Cursor, Windsurf, and custom MCP clients.
The MCP layer should be a thin wrapper only:
validate tool inputs
call core memory services
return structured outputs that help the host LLM decide the next action
All memory behavior stays in the core Python modules. The MCP server must not import or call any generative LLM SDK. The only model dependency remains Gemini Embedding 2 for embeddings.
Repo Reality Check
The current repo mostly matches the intended architecture, with a few important corrections:
procedural memory is already implemented in code, even though the README still marks parts of it as planned
semantic contradiction detection and supersession resolution already exist in forgetting/contradiction.py
procedural outcome tracking and Wilson-score ranking already exist in stores/procedural_store.py
there is no cognitive_memory/ package today; the business logic lives in top-level modules such as stores/, retrieval/, forgetting/, models/, and utils/
PDF support exists explicitly via embed_pdf() and multimodal records
event emission is broader than the initial brief: the code already emits memory.accessed, memory.ranked, memory.supersession_resolved, memory.faded, and forgetting-cycle events
MemoryAPIService.__init__() currently mutates config.CHROMA_DB_PATH during runtime construction; that is not thread-safe and must be removed as part of the shared-runtime extraction
Why This Matters
Today the project has:
a core memory engine
a FastAPI wrapper
a Next.js playground
What it does not yet have is the agent-facing protocol boundary that lets any MCP-capable host reuse the memory system directly without going through the web app.
That MCP boundary is the product surface for long-lived agent memory.
Internet-Researched Constraints
1. Prefer FastMCP from the official Python SDK
The official mcp Python SDK currently recommends:
FastMCP for most server implementations
Streamable HTTP as the preferred production transport
stdio as the simplest local transport for IDE and CLI integrations
Implication:
implement the server with FastMCP
support both stdio and streamable-http
default the README examples to stdio for Claude Code / Cursor / Windsurf local setups
2. Do not rely on MCP resources for primary memory retrieval
Multiple public MCP issues show that some hosts list resources correctly but do not reliably read them when answering questions.
Implication:
make all primary memory operations tools, not resources
resources can be added later for optional media access, but recall must not depend on them
3. Keep the tool surface tight
Current host constraints matter:
Claude Code warns when MCP output exceeds 10,000 tokens
Windsurf limits available MCP tools and also caps tool calls per prompt
Implication:
keep the tool inventory small and high-signal
prefer store-specific write tools and a small number of retrieval/admin tools
bound result counts aggressively
4. Avoid rich binary output contracts in v1
Current MCP Python SDK and client issues show rough edges around:
binary/base64 content handling
resource encoding mismatches
schema generation around image output types
Implication:
accept media as local file paths, with base64 input as a fallback
return structured JSON plus durable media_ref paths
do not make raw binary/image tool outputs part of the critical path
5. Similar memory servers already hit config and race-condition problems
Public MCP memory-server issues include:
path/env handling bugs
write failures under concurrent usage
search normalization bugs
Implication:
validate all storage paths at startup
add a core-level run lock for forgetting cycles before exposing mutating admin tools
keep write paths single-owner and deterministic
Main Problems To Solve Before or During MCP Work
P0. The core service container is trapped inside api/app.py
MemoryAPIService currently lives inside the FastAPI module. The MCP server should not depend on FastAPI wiring.
Required change:
extract a shared core service container used by both the API and MCP entrypoints
stop mutating config.CHROMA_DB_PATH during runtime construction
pass chroma_path directly into each store or its PersistentClient constructor instead of routing through module-level global config
make embedding dimensions runtime-injectable instead of relying only on module-level config so future reindex migrations can stand up a parallel runtime cleanly
P1. Superseded semantic memories can still leak into normal retrieval
The current retriever fans out across stores but does not exclude semantic records that have been superseded.
Required change:
add an active-record filter in SemanticStore so the store contract itself does not surface superseded facts by default
P2. Contradiction detection failures are currently swallowed in the API
_safe_contradiction_lookup() catches broad exceptions and silently returns [].
Required change:
MCP write responses must expose contradiction-check status explicitly as completed, skipped, or error
a failure to run contradiction detection must not be indistinguishable from “no contradictions found”
P3. Forgetting-cycle execution is not concurrency-guarded
The current forgetting service has no visible single-run guard.
Required change:
add a core-level asyncio.Lock and return already_running for overlapping requests
P4. Manual single-record forgetting is not yet safe to expose
Low-level store delete() methods do not provide one coordinated path for:
record deletion
owned media cleanup
event emission
store-type resolution
Implication:
do not expose a generic forget_memory MCP tool in v1
expose forgetting-cycle preview/run first
add a core admin delete service later if needed
Proposed MCP Tool Surface
Write tools
remember_fact
remember_episode
remember_procedure
resolve_contradiction
record_procedure_outcome
Recall tools
recall_memories
recall_procedures
recall_episodes
get_memory
Admin and observability tools
get_memory_overview
preview_forgetting_cycle
run_forgetting_cycle
Notably absent in v1:
raw embedding tools
raw Chroma collection tools
EventBus subscription tools
generic delete/forget-by-id tool
resource-dependent primary recall flow
Tool-shape clarifications:
get_memory should require both memory_type and record_id rather than probing all three stores
recall_procedures should call ProceduralStore.get_best_procedure_matches() directly, not UnifiedRetriever.query()
recall_episodes should cover recent, session, and time_range modes in one tool rather than splitting temporal recall into additional tools
MCP-1A: Extract a shared core runtime for API and MCP
Owns:
new shared service-container module
API import cleanup so api/app.py becomes an adapter, not the owner of runtime composition
removal of the thread-unsafe config.CHROMA_DB_PATH mutation during runtime construction
moving EventRecorder into the shared runtime if it remains part of the common observability surface
injecting embedding dimensions through runtime construction so a migration can run 768-dim and 1536-dim runtimes side by side against different Chroma paths
Acceptance criteria:
FastAPI and MCP entrypoints construct the same stores, retriever, contradiction detector, forgetting service, and media store from one shared runtime factory
runtime construction never mutates module-level config state to swap Chroma paths
chroma_path is injected directly into store/client construction, so concurrent runtime creation cannot observe another runtime's database path
embedding dimensions can be supplied at runtime rather than only through module-level config, enabling parallel re-embedding into a fresh database path during future dimension upgrades
MCP-1B: Harden the core for MCP-safe behavior
Owns:
active-only semantic retrieval filtering
explicit contradiction-check status reporting
forgetting-cycle lock / single-flight guard
consistent exception mapping hooks
event emission when ProceduralStore.record_outcome() updates a procedure
removal of duplicate ContradictionDetector construction paths so the runtime owns one shared detector instance
Acceptance criteria:
a superseded semantic record is not returned by default recall
contradiction lookup failure is visible in the write response
a second forgetting-cycle request receives already_running instead of overlapping execution
procedural outcome recording emits an event that observability surfaces can show
the forgetting guard uses asyncio.Lock rather than an ad hoc sync primitive in the async MCP runtime
MCP-1C: Define MCP schemas and serializers
Owns:
typed request/response models for all MCP tools
shared success/error envelope
serialization of memory records, procedural matches, contradiction candidates, and forgetting reports
get_memory(memory_type, record_id) routing in the request model
explicit store-first-then-contradiction-check ordering in remember_fact
configurable truncation for large forgetting reports
Acceptance criteria:
all tools return machine-readable structured output
errors are stable and typed
responses stay below practical host token limits for common calls
forgetting preview/run responses cap decisions to a configurable maximum and report when output was truncated
remember_fact documentation makes it explicit that contradiction detection runs only after the new semantic record has been stored
MCP-1D: Implement the MCP transport layer
Owns:
FastMCP server
one runtime entrypoint that selects stdio or streamable-http
startup validation and health exposure
Acceptance criteria:
local clients can run the server over stdio
remote/self-hosted clients can connect over /mcp via streamable HTTP
the server can switch transport via a single CLI/env-controlled startup path, for example MEMORY_MCP_TRANSPORT=stdio|streamable-http
MCP-1E: Add multimodal input handling for MCP calls
Owns:
file-path input support
base64 input fallback
temporary-file handling for inline payloads
size limits and validation errors
explicit validation that local file paths are readable from the server filesystem, not merely meaningful to the client
Acceptance criteria:
screenshot, audio, and PDF-backed memories can be stored via MCP without the FastAPI upload endpoints
text recall can find media-backed memories
remote deployments fail clearly when a caller provides a local path that is not accessible from the MCP server host
MCP-1F: Document client setup and integration behavior
Owns:
README setup for Claude Code, Cursor, and Windsurf
env var reference
startup modes
deployment notes for local-path media behavior when the server is remote
tested mcp package version and pinning guidance
embedding-dimension migration guidance so users understand that changing vector size requires a re-embedding cutover, not an in-place live switch
troubleshooting section for common MCP client issues
Acceptance criteria:
a user can install dependencies, start the server, and connect one of the three supported hosts without guessing config structure
Defensive Engineering Rules
Use structured output for every tool. Do not rely on free-form strings.
Keep tool descriptions short and trigger-oriented so hosts call the right tool without orchestration glue.
Prefer local file paths for media input. Base64 is fallback-only.
Bound all list-style results with explicit defaults and max values.
Exclude superseded semantic memories from default recall.
Never silently swallow contradiction-check failures.
Return typed retryable metadata on dependency failures.
Keep the MCP layer free of business logic. If logic is missing, add it in core first.
reject or loudly warn on relative storage paths in non-local deployments so the server does not accidentally point at a different Chroma database because of working-directory drift
treat embedding-dimension changes as reindex migrations: never point an existing Chroma collection at a new vector size and hope it works
Packaging Plan
Add a real Python package boundary so users can run only the MCP server if they do not need the API or web UI.
Recommended shape:
add pyproject.toml
add a console script such as agentic-memory-mcp
make MCP dependencies installable as an extra
keep API dependencies installable separately
pin the tested mcp version explicitly instead of floating across point releases
Suggested dependency split:
core dependencies in [project.dependencies]: chromadb, google-genai, numpy, python-dotenv
API extra in [project.optional-dependencies].api: fastapi, uvicorn, python-multipart
MCP extra in [project.optional-dependencies].mcp: mcp[cli]
Recommended runtime/config additions:
allow EMBEDDING_DIMENSIONS to be overridden via env and runtime constructor parameters
keep the default at 768 for now
treat 1536 as a supported migration target, not a hot-swappable live toggle on existing collections
Future Migration Note: 768 to 1536
gemini-embedding-2-preview supports both 768-dimensional and 1536-dimensional embeddings. Moving from 768 to 1536 is a valid production migration, but it is a one-time re-embedding and reindexing operation because Chroma collection dimensions are fixed once data has been written.
Guidance:
do not change embedding size in place on an existing Chroma path
stand up a new runtime with the target embedding size and a fresh Chroma path
read records from the old collections
re-embed all records at the new size
write them into new collections
verify retrieval quality and record counts
switch traffic to the new runtime/path
retire the old collections after validation
When this work happens, MCP-1A should already have made the necessary runtime changes:
chroma_path injected directly instead of via global config mutation
embedding dimensions injected at runtime
parallel runtimes possible during migration without restart-coupled global state
Operational recommendation:
keep 768 as the default unless retrieval quality justifies the migration cost
support 1536 cleanly once the runtime/config injection refactor lands
Acceptance Surface
The MCP server is complete when:
an MCP host can store semantic, episodic, and procedural memories
contradiction candidates are returned on semantic writes and can be resolved explicitly
procedural recall uses similarity plus Wilson-score ranking
procedural outcomes can be recorded and affect future ranking
text recall can retrieve media-backed episodic and semantic memories
forgetting cycles can be previewed and run safely
the server runs without the FastAPI app
setup docs exist for Claude Code, Cursor, and Windsurf
Architecture
flowchart LR
Host[Claude Code / Cursor / Windsurf / Custom MCP Client]
MCP[FastMCP Server]
Runtime[Shared Memory Runtime]
RET[UnifiedRetriever]
CD[ContradictionDetector]
FGT[ForgettingService]
SS[SemanticStore]
ES[EpisodicStore]
PS[ProceduralStore]
MS[MediaStore]
EMB[GeminiEmbedder]
CH[(ChromaDB)]
BUS[EventBus]
Host --> MCP
MCP --> Runtime
Runtime --> RET
Runtime --> CD
Runtime --> FGT
Runtime --> SS
Runtime --> ES
Runtime --> PS
Runtime --> MS
SS --> EMB
ES --> EMB
PS --> EMB
SS --> CH
ES --> CH
PS --> CH
SS -. emit .-> BUS
ES -. emit .-> BUS
PS -. emit .-> BUS
RET -. emit .-> BUS
FGT -. emit .-> BUS
MCP-1: Add an MCP server layer for agentic-memory
Summary
Add a Python MCP server that exposes
agentic-memoryas persistent memory infrastructure for external agents such as Claude Code, Cursor, Windsurf, and custom MCP clients.The MCP layer should be a thin wrapper only:
All memory behavior stays in the core Python modules. The MCP server must not import or call any generative LLM SDK. The only model dependency remains Gemini Embedding 2 for embeddings.
Repo Reality Check
The current repo mostly matches the intended architecture, with a few important corrections:
forgetting/contradiction.pystores/procedural_store.pycognitive_memory/package today; the business logic lives in top-level modules such asstores/,retrieval/,forgetting/,models/, andutils/embed_pdf()andmultimodalrecordsmemory.accessed,memory.ranked,memory.supersession_resolved,memory.faded, and forgetting-cycle eventsMemoryAPIService.__init__()currently mutatesconfig.CHROMA_DB_PATHduring runtime construction; that is not thread-safe and must be removed as part of the shared-runtime extractionWhy This Matters
Today the project has:
What it does not yet have is the agent-facing protocol boundary that lets any MCP-capable host reuse the memory system directly without going through the web app.
That MCP boundary is the product surface for long-lived agent memory.
Internet-Researched Constraints
1. Prefer FastMCP from the official Python SDK
The official
mcpPython SDK currently recommends:FastMCPfor most server implementationsStreamable HTTPas the preferred production transportstdioas the simplest local transport for IDE and CLI integrationsImplication:
FastMCPstdioandstreamable-httpstdiofor Claude Code / Cursor / Windsurf local setups2. Do not rely on MCP resources for primary memory retrieval
Multiple public MCP issues show that some hosts list resources correctly but do not reliably read them when answering questions.
Implication:
3. Keep the tool surface tight
Current host constraints matter:
Implication:
4. Avoid rich binary output contracts in v1
Current MCP Python SDK and client issues show rough edges around:
Implication:
media_refpaths5. Similar memory servers already hit config and race-condition problems
Public MCP memory-server issues include:
Implication:
Main Problems To Solve Before or During MCP Work
P0. The core service container is trapped inside
api/app.pyMemoryAPIServicecurrently lives inside the FastAPI module. The MCP server should not depend on FastAPI wiring.Required change:
config.CHROMA_DB_PATHduring runtime constructionchroma_pathdirectly into each store or itsPersistentClientconstructor instead of routing through module-level global configP1. Superseded semantic memories can still leak into normal retrieval
The current retriever fans out across stores but does not exclude semantic records that have been superseded.
Required change:
SemanticStoreso the store contract itself does not surface superseded facts by defaultP2. Contradiction detection failures are currently swallowed in the API
_safe_contradiction_lookup()catches broad exceptions and silently returns[].Required change:
completed,skipped, orerrorP3. Forgetting-cycle execution is not concurrency-guarded
The current forgetting service has no visible single-run guard.
Required change:
asyncio.Lockand returnalready_runningfor overlapping requestsP4. Manual single-record forgetting is not yet safe to expose
Low-level store
delete()methods do not provide one coordinated path for:Implication:
forget_memoryMCP tool in v1Proposed MCP Tool Surface
Write tools
remember_factremember_episoderemember_procedureresolve_contradictionrecord_procedure_outcomeRecall tools
recall_memoriesrecall_proceduresrecall_episodesget_memoryAdmin and observability tools
get_memory_overviewpreview_forgetting_cyclerun_forgetting_cycleNotably absent in v1:
Tool-shape clarifications:
get_memoryshould require bothmemory_typeandrecord_idrather than probing all three storesrecall_proceduresshould callProceduralStore.get_best_procedure_matches()directly, notUnifiedRetriever.query()recall_episodesshould coverrecent,session, andtime_rangemodes in one tool rather than splitting temporal recall into additional toolsChild Issues
Delivery Plan
MCP-1A: Extract a shared core runtime for API and MCP
Owns:
api/app.pybecomes an adapter, not the owner of runtime compositionconfig.CHROMA_DB_PATHmutation during runtime constructionEventRecorderinto the shared runtime if it remains part of the common observability surfaceAcceptance criteria:
chroma_pathis injected directly into store/client construction, so concurrent runtime creation cannot observe another runtime's database pathMCP-1B: Harden the core for MCP-safe behavior
Owns:
ProceduralStore.record_outcome()updates a procedureContradictionDetectorconstruction paths so the runtime owns one shared detector instanceAcceptance criteria:
already_runninginstead of overlapping executionasyncio.Lockrather than an ad hoc sync primitive in the async MCP runtimeMCP-1C: Define MCP schemas and serializers
Owns:
get_memory(memory_type, record_id)routing in the request modelremember_factAcceptance criteria:
decisionsto a configurable maximum and report when output was truncatedremember_factdocumentation makes it explicit that contradiction detection runs only after the new semantic record has been storedMCP-1D: Implement the MCP transport layer
Owns:
FastMCPserverstdioorstreamable-httpAcceptance criteria:
stdio/mcpvia streamable HTTPMEMORY_MCP_TRANSPORT=stdio|streamable-httpMCP-1E: Add multimodal input handling for MCP calls
Owns:
Acceptance criteria:
MCP-1F: Document client setup and integration behavior
Owns:
mcppackage version and pinning guidanceAcceptance criteria:
Defensive Engineering Rules
retryablemetadata on dependency failures.Packaging Plan
Add a real Python package boundary so users can run only the MCP server if they do not need the API or web UI.
Recommended shape:
pyproject.tomlagentic-memory-mcpmcpversion explicitly instead of floating across point releasesSuggested dependency split:
[project.dependencies]:chromadb,google-genai,numpy,python-dotenv[project.optional-dependencies].api:fastapi,uvicorn,python-multipart[project.optional-dependencies].mcp:mcp[cli]Recommended runtime/config additions:
EMBEDDING_DIMENSIONSto be overridden via env and runtime constructor parameters768for now1536as a supported migration target, not a hot-swappable live toggle on existing collectionsFuture Migration Note: 768 to 1536
gemini-embedding-2-previewsupports both 768-dimensional and 1536-dimensional embeddings. Moving from 768 to 1536 is a valid production migration, but it is a one-time re-embedding and reindexing operation because Chroma collection dimensions are fixed once data has been written.Guidance:
When this work happens, MCP-1A should already have made the necessary runtime changes:
chroma_pathinjected directly instead of via global config mutationOperational recommendation:
Acceptance Surface
The MCP server is complete when:
Architecture
flowchart LR Host[Claude Code / Cursor / Windsurf / Custom MCP Client] MCP[FastMCP Server] Runtime[Shared Memory Runtime] RET[UnifiedRetriever] CD[ContradictionDetector] FGT[ForgettingService] SS[SemanticStore] ES[EpisodicStore] PS[ProceduralStore] MS[MediaStore] EMB[GeminiEmbedder] CH[(ChromaDB)] BUS[EventBus] Host --> MCP MCP --> Runtime Runtime --> RET Runtime --> CD Runtime --> FGT Runtime --> SS Runtime --> ES Runtime --> PS Runtime --> MS SS --> EMB ES --> EMB PS --> EMB SS --> CH ES --> CH PS --> CH SS -. emit .-> BUS ES -. emit .-> BUS PS -. emit .-> BUS RET -. emit .-> BUS FGT -. emit .-> BUSSources