Skip to main content
doc0blade47/mem0documentation home
Sign in

Plugin Synchronization

Last updated Oct 11, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

Plugin synchronization bridges canonical CLI authentication state with external ecosystem touchpoints cli/python/src/mem0_cli/plugin_sync.py:1-25, cli/node/src/plugin-sync.ts:1-22. By propagating active Mem0 API keys into runtime configuration files and shell environment export declarations, the synchronization subsystem prevents authentication mismatches during agent-mode bootstraps cli/python/src/mem0_cli/plugin_sync.py:1-15, cli/node/src/plugin-sync.ts:1-15.

Sources: cli/python/src/mem0_cli/plugin_sync.py:1-25, cli/node/src/plugin-sync.ts:1-22

The architecture enforces strict update constraints by modifying existing target entries without creating unrequested files, preserving document formatting and surrounding keys, and performing atomic file writes via temporary staging paths and renames cli/python/src/mem0_cli/plugin_sync.py:10-15, cli/node/src/plugin-sync.ts:10-15. It targets touchpoints such as Claude Code settings and shell resource configuration profiles cli/python/src/mem0_cli/plugin_sync.py:17-20, cli/node/src/plugin-sync.ts:16-19.

Sources: cli/python/src/mem0_cli/plugin_sync.py:10-20, cli/node/src/plugin-sync.ts:10-19

CLI Synchronization Mechanism

Propagation Targets and Rules

The Python and Node.js command-line interfaces implement identical credential synchronization logic to propagate active Mem0 API keys into external development environments cli/python/src/mem0_cli/plugin_sync.py:41-55, cli/node/src/plugin-sync.ts:40-50. When sync_api_key or syncApiKey executes with a valid string, it targets the Claude Code configuration file and three standard POSIX shell resource profiles cli/python/src/mem0_cli/plugin_sync.py:37-38, cli/node/src/plugin-sync.ts:28-33.

_CLAUDE_SETTINGS = Path.home() / ".claude" / "settings.json"
_SHELL_RCS = [Path.home() / ".zshrc", Path.home() / ".bashrc", Path.home() / ".bash_profile"]
 

Sources: cli/python/src/mem0_cli/plugin_sync.py:37-39

const CLAUDE_SETTINGS = path.join(os.homedir(), ".claude", "settings.json");
const SHELL_RCS = [
	path.join(os.homedir(), ".zshrc"),
	path.join(os.homedir(), ".bashrc"),
	path.join(os.homedir(), ".bash_profile"),
];

Sources: cli/node/src/plugin-sync.ts:28-33

Target PathConfig Key / PatternScope & Behavior
~/.claude/settings.jsonenv.MEM0_API_KEYUpdated only if parent env object and key already exist cli/python/src/mem0_cli/plugin_sync.py:67-70, cli/node/src/plugin-sync.ts:66-69
~/.zshrcexport MEM0_API_KEY="..."Replaces existing assignment value using regular expression matching cli/python/src/mem0_cli/plugin_sync.py:81-84, cli/node/src/plugin-sync.ts:37-38
~/.bashrcexport MEM0_API_KEY="..."Replaces existing assignment value using regular expression matching cli/python/src/mem0_cli/plugin_sync.py:81-84, cli/node/src/plugin-sync.ts:37-38
~/.bash_profileexport MEM0_API_KEY="..."Replaces existing assignment value using regular expression matching cli/python/src/mem0_cli/plugin_sync.py:81-84, cli/node/src/plugin-sync.ts:37-38

Sources: cli/python/src/mem0_cli/plugin_sync.py:37-84, cli/node/src/plugin-sync.ts:28-38

Important

The synchronization engine strictly enforces a non-creation policy for target keys. If MEM0_API_KEY is missing from settings.json or no export MEM0_API_KEY declaration exists in a shell resource file, the synchronizer skips that target without writing new keys cli/python/src/mem0_cli/plugin_sync.py:68-70, cli/node/src/plugin-sync.ts:67-69, cli/python/src/mem0_cli/plugin_sync.py:96-97, cli/node/src/plugin-sync.ts:87.

Sources: cli/python/src/mem0_cli/plugin_sync.py:68-70, cli/node/src/plugin-sync.ts:67-69, cli/python/src/mem0_cli/plugin_sync.py:96-97, cli/node/src/plugin-sync.ts:87

Parsing Patterns and Atomic Writes

Shell RC file matching relies on an anchored regular expression pattern that captures export prefixes, optional surrounding quotes, credential values, and trailing spaces while sparing newline characters cli/python/src/mem0_cli/plugin_sync.py:81-84, cli/node/src/plugin-sync.ts:37-38.

_RC_LINE = re.compile(
    r'^([ \t]*export[ \t]+MEM0_API_KEY[ \t]*=[ \t]*)(["\']?)([^"\'\n]*)(["\']?)[ \t]*$',
    re.MULTILINE,
)

Sources: cli/python/src/mem0_cli/plugin_sync.py:81-84

const RC_LINE_RE =
	/^([ \t]*export[ \t]+MEM0_API_KEY[ \t]*=[ \t]*)(["']?)([^"'\n]*)(["']?)[ \t]*$/m;

Sources: cli/node/src/plugin-sync.ts:37-38

Tip

Both implementations use explicit horizontal whitespace character classes [ \t]* rather than generic whitespace selectors \s* in regex definitions. This ensures that trailing newlines at the end of shell configuration files remain intact when MEM0_API_KEY resides on the final line cli/python/src/mem0_cli/plugin_sync.py:79-80, cli/node/src/plugin-sync.ts:35-36.

Sources: cli/python/src/mem0_cli/plugin_sync.py:79-80, cli/node/src/plugin-sync.ts:35-36

File persistence utilizes an atomic write procedure that writes content to a temporary staging file in the target directory, copies POSIX file access permissions via bitwise masking against 0o777, and replaces the destination file atomically via OS system calls cli/python/src/mem0_cli/plugin_sync.py:105-118, cli/node/src/plugin-sync.ts:97-120.

def _atomic_write_text(path: Path, content: str) -> None:
    """Write content to path atomically (temp + rename)."""
    dirname = path.parent
    fd, tmp_path = tempfile.mkstemp(prefix=f".{path.name}.", suffix=".tmp", dir=dirname)
    try:
        with os.fdopen(fd, "w", encoding="utf-8") as f:
            f.write(content)
        # Preserve mode if the original existed.
        if path.exists():
            os.chmod(tmp_path, path.stat().st_mode & 0o777)
        os.replace(tmp_path, path)

Sources: cli/python/src/mem0_cli/plugin_sync.py:105-115

function atomicWriteText(filePath: string, content: string): void {
	const dir = path.dirname(filePath);
	const tmp = path.join(dir, `.${path.basename(filePath)}.${process.pid}.tmp`);
	try {
		fs.writeFileSync(tmp, content, "utf-8");
		// Preserve permissions if original existed.
		if (fs.existsSync(filePath)) {
			try {
				const mode = fs.statSync(filePath).mode & 0o777;
				fs.chmodSync(tmp, mode);
			} catch {
				/* best-effort */
			}
		}
		fs.renameSync(tmp, filePath);
	} catch (err) {

Sources: cli/node/src/plugin-sync.ts:97-112

IDE MCP Tool Manifests

Manifest Structure Across Targets

Standardized Model Context Protocol server declarations across IDE integration targets configure the execution parameters for the mem0 memory service tool. Each manifest registers a server entry point executing via Python, pointing to the local core/mcp_server.py module relative to the plugin root.

{
  "mcpServers": {
    "mem0": {
      "command": "python3",
      "args": ["${CLAUDE_PLUGIN_ROOT}/core/mcp_server.py"],
      "env": {
        "MEM0_CODE_DATA_DIR": "${CLAUDE_PLUGIN_DATA}"
      }
    }
  }

Sources: integrations/claude-code-plugin/.mcp.json:1-10

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
  "mcpServers": {
    "mem0": {
      "type": "stdio",
      "command": "python3",
      "args": [
        "${PLUGIN_ROOT}/core/mcp_server.py"
      ]
    }
  }

Sources: integrations/mem0-agent-plugin/mcp.json:1-11

{
  "mcpServers": {
    "mem0": {
      "command": "python3",
      "args": ["./core/mcp_server.py"]
    }
  }

Sources: integrations/antigravity-plugin/mcp_config.json:1-7

Target configurations differ in their schema references, environment variable scoping, and path variables used for runtime resolution.

Target PluginSchema ReferenceCommandArgumentsEnvironment Variables
Claude Code PluginNonepython3["${CLAUDE_PLUGIN_ROOT}/core/mcp_server.py"]MEM0_CODE_DATA_DIR: "${CLAUDE_PLUGIN_DATA}"
Mem0 Agent Pluginhttps://agent-plugins.org/schemas/1.0.0/mcp.schema.jsonpython3["${PLUGIN_ROOT}/core/mcp_server.py"]None
Antigravity PluginNonepython3["./core/mcp_server.py"]None

Sources: integrations/claude-code-plugin/.mcp.json:1-10, integrations/mem0-agent-plugin/mcp.json:1-11, integrations/antigravity-plugin/mcp_config.json:1-7

Note

The mem0-agent-plugin explicitly declares a JSON schema validator URI https://agent-plugins.org/schemas/1.0.0/mcp.schema.json and a transport type property ("type": "stdio"), whereas Claude Code and Antigravity omit these explicit schema and transport declarations integrations/mem0-agent-plugin/mcp.json:2-5, integrations/claude-code-plugin/.mcp.json:1-10, integrations/antigravity-plugin/mcp_config.json:1-7.

Sources: integrations/mem0-agent-plugin/mcp.json:2-5, integrations/claude-code-plugin/.mcp.json:1-10, integrations/antigravity-plugin/mcp_config.json:1-7

Standalone MCP Server Implementation

JSON-RPC Server Loop and Request Dispatch

The standalone Model Context Protocol server entry point is implemented in Python under integrations/mem0-agent-plugin/core/mcp_server.py and integrations/antigravity-plugin/core/mcp_server.py. It operates via standard input (sys.stdin) line reading, executing a JSON-RPC message processing loop that parses line-delimited payloads and flushes serialized responses to standard output (sys.stdout) with newline termination.

def main() -> int:
    for raw_line in sys.stdin:
        try:
            message = json.loads(raw_line)
            response = handle_request(message)
        except json.JSONDecodeError:
            response = {
                "jsonrpc": "2.0",
                "id": None,
                "error": {"code": -32700, "message": "Parse error"},
            }
        except Exception:
            response = {
                "jsonrpc": "2.0",
                "id": None,
                "error": {"code": -32603, "message": "Internal error"},
            }
        if response is not None:
            sys.stdout.write(json.dumps(response, separators=(",", ":")) + "\n")
            sys.stdout.flush()
    telemetry.spawn_flush()
    return 0
 
 

Sources: integrations/mem0-agent-plugin/core/mcp_server.py:215-238, integrations/antigravity-plugin/core/mcp_server.py:215-238

The request router handles standard MCP JSON-RPC protocol methods. When an initialize request arrives, it echoes back the requested protocol version falling back to 2024-11-05, declares tool capabilities, and returns server metadata comprising name mem0 and the current PLUGIN_VERSION.

def handle_request(message: Any) -> dict[str, Any] | None:
    if not isinstance(message, dict):
        return None
    request_id = message.get("id")
    method = message.get("method")
 
    if method == "notifications/initialized":
        return None
    if method == "initialize":
        requested = (message.get("params") or {}).get("protocolVersion")
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "protocolVersion": requested or PROTOCOL_VERSION,
                "capabilities": {"tools": {"listChanged": False}},
                "serverInfo": {"name": "mem0", "version": PLUGIN_VERSION},
            },
        }
    if method == "ping":
        return {"jsonrpc": "2.0", "id": request_id, "result": {}}

Sources: integrations/mem0-agent-plugin/core/mcp_server.py:152-172, integrations/antigravity-plugin/core/mcp_server.py:152-172

Warning

Incoming JSON-RPC lines failing JSON deserialization return a -32700 parse error, while unhandled internal exceptions return a -32603 internal error code with id: None. Requests carrying unrecognized methods return a -32601 method not found error integrations/mem0-agent-plugin/core/mcp_server.py:206-232, integrations/antigravity-plugin/core/mcp_server.py:206-232.

Sources: integrations/mem0-agent-plugin/core/mcp_server.py:206-232, integrations/antigravity-plugin/core/mcp_server.py:206-232

Memory Retrieval Tool and Argument Validation

The server exposes a single retrieval tool named search_memories. The tool definition includes input validation schemas, descriptive text, and execution annotations.

PROTOCOL_VERSION = "2024-11-05"
TOOL_NAME = "search_memories"
TOOL_DESCRIPTION = (
    "Search memories from earlier work in this repository. Use it before "
    "repeating investigation or when earlier decisions, fixes, commands, or "
    "results may help."
)
TOOL_SCHEMA = {
    "type": "object",
    "properties": {
        "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "A direct question about earlier work in this repository.",
        },
        "top_k": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20,
            "description": "Maximum memories to return. Uses Mem0's configured default when omitted.",
        },
        "category": {
            "type": "string",
            "enum": list(CODING_MEMORY_CATEGORY_NAMES),
            "description": "Optional memory category. Omit to search every category.",
        },
        "scope": {
            "type": "string",
            "enum": list(SEARCH_SCOPES),
            "description": (
                "Which memories to search. 'repo' (default) is the whole repository's "
                "shared memory plus your own preferences, 'dir' narrows the shared "
                "part to the current directory, 'mine' is your preferences alone."
            ),
        },
        "run_id": {
            "type": "string",
            "minLength": 1,
            "description": (
                "Optional coding-agent session ID. With any scope, restricts results to memories "
                "saved in that session. Omit to recall memories across sessions."
            ),
        },
    },
    "required": ["query"],
    "additionalProperties": False,
}

Sources: integrations/mem0-agent-plugin/core/mcp_server.py:21-68, integrations/antigravity-plugin/core/mcp_server.py:21-68

PropertyTypeConstraints / EnumPurpose
querystringminLength: 1, maxLength: 2000, requiredDirect question about earlier work in the repository
top_kintegerminimum: 1, maximum: 20, optionalMaximum number of memories to return
categorystringCODING_MEMORY_CATEGORY_NAMES, optionalOptional memory category filter
scopestringSEARCH_SCOPES, optionalSearch boundary (repo, dir, or mine)
run_idstringminLength: 1, optionalRestricts results to a specific coding-agent session ID

Sources: integrations/mem0-agent-plugin/core/mcp_server.py:28-68, integrations/antigravity-plugin/core/mcp_server.py:28-68

The tools/list method announces search_memories with annotations configured with readOnlyHint: True, idempotentHint: True, and openWorldHint: True. Argument validation enforces strict type boundaries via _validate_arguments, raising ToolInputError if unknown arguments are present, strings exceed character limits, or integer bounds are violated.

def _validate_arguments(
    arguments: Any,
) -> tuple[str, int | None, str | None, str | None, str | None]:
    if not isinstance(arguments, dict):
        raise ToolInputError("Search arguments must be an object.")
 
    unknown = set(arguments) - {"query", "top_k", "category", "scope", "run_id"}
    if unknown:
        raise ToolInputError(f"Unknown search argument: {sorted(unknown)[0]}")
 
    query = arguments.get("query")
    if not isinstance(query, str) or not query.strip():
        raise ToolInputError("query must be a non-empty string.")
    query = query.strip()
    if len(query) > 2000:
        raise ToolInputError("query must be at most 2,000 characters.")
 
    top_k = arguments.get("top_k")
    if top_k is not None and (
        isinstance(top_k, bool) or not isinstance(top_k, int) or not 1 <= top_k <= 20
    ):
        raise ToolInputError("top_k must be an integer from 1 to 20.")
 
    category = arguments.get("category")
    if category is not None and category not in CODING_MEMORY_CATEGORY_NAMES:
        raise ToolInputError("category must be one of Mem0's supported categories.")
 
    scope = arguments.get("scope")
    if scope is not None and scope not in SEARCH_SCOPES:
        raise ToolInputError(f"scope must be one of {list(SEARCH_SCOPES)}.")
 
    run_id = arguments.get("run_id")
    if run_id is not None:
        if not isinstance(run_id, str) or not run_id.strip():
            raise ToolInputError("run_id must be a non-empty string.")
        run_id = run_id.strip()
 
    return query, top_k, category, scope, run_id
 

Sources: integrations/mem0-agent-plugin/core/mcp_server.py:75-113, integrations/antigravity-plugin/core/mcp_server.py:75-113

IDE Hook Event Dispatching

Hook Orchestration and Input Processing

Host IDE hooks are orchestrated through shared runner scripts that intercept environment events and route them into Mem0 background pipelines. Hook input is read directly from standard input as a JSON dictionary, defaulting to an empty structure on parse or I/O errors.

def read_hook_input() -> dict:
    try:
        value = json.load(sys.stdin)
        return value if isinstance(value, dict) else {}
    except (json.JSONDecodeError, OSError):
        return {}
 

Sources: integrations/antigravity-plugin/core/hook_runner.py:44-50, integrations/kimi-plugin/core/hook_runner.py:44-50, integrations/claude-code-plugin/core/hook_runner.py:44-50, integrations/codex-plugin/core/hook_runner.py:44-50, integrations/cursor-plugin/core/hook_runner.py:44-50

Note

Tool use response hooks evaluate tool exit codes and error flags to detect failed executions. If a tool response indicates a failure via exit_code != 0, isError: true, or success: false, the runner injects error telemetry into the payload before recording integrations/codex-plugin/hooks/adapter.py:42-55.

Sources: integrations/codex-plugin/hooks/adapter.py:42-55

Configuration and Handoff Mechanics

Plugin hooks configure their respective harness environments and execute asynchronous background flush workers to persist capture data without blocking the IDE event loop.

configure_harness("codex", data_dir_name="codex-plugin", source_tag="codex_plugin")
telemetry.init(harness="codex", source_tag="CODEX_PLUGIN")

Sources: integrations/codex-plugin/hooks/adapter.py:23-24

Constant NameValue / DefaultMeaning / Constraint
STALE_RUNNING_SECONDS300Threshold in seconds before a running handoff process is considered stale and reset
PENDING_EXPIRY_SECONDS604800 (7 days)Maximum age for pending handoff files before deletion
PENDING_LAUNCH_LIMIT5Maximum number of pending handoff processes launched concurrently
DEFAULT_IDLE_FLUSH_SECONDS300Default idle duration before triggering a flush

Sources: integrations/antigravity-plugin/core/hook_runner.py:36-39, integrations/kimi-plugin/core/hook_runner.py:36-39, integrations/claude-code-plugin/core/hook_runner.py:36-39, integrations/codex-plugin/core/hook_runner.py:36-39, integrations/cursor-plugin/core/hook_runner.py:36-39

Warning

Handoff payloads are hashed using SHA-256 over the working directory, session ID, and reason, truncated to 24 hex characters, to prevent duplicate worker invocations for concurrent identical events integrations/antigravity-plugin/core/hook_runner.py:170-191, integrations/kimi-plugin/core/hook_runner.py:170-191, integrations/claude-code-plugin/core/hook_runner.py:170-191, integrations/codex-plugin/core/hook_runner.py:170-191, integrations/cursor-plugin/core/hook_runner.py:170-191.

Sources: integrations/antigravity-plugin/core/hook_runner.py:170-191, integrations/kimi-plugin/core/hook_runner.py:170-191, integrations/claude-code-plugin/core/hook_runner.py:170-191, integrations/codex-plugin/core/hook_runner.py:170-191, integrations/cursor-plugin/core/hook_runner.py:170-191

In-Plugin Diagnostic Utilities

Plugin distributions bundle a command-line interface script (memory_cli.py) that exposes diagnostic checks, telemetry controls, and repository memory management directly within agent environments and IDE extensions integrations/mem0-agent-plugin/core/memory_cli.py:1-20. The script configures harness environments via --harness, overrides local storage paths through --plugin-data-dir, and dispatches structured subcommands parsed with argparse integrations/mem0-agent-plugin/core/memory_cli.py:61-87.

SubcommandArgumentsAction Performed
status--jsonPrints operational state, repository identity, local data paths, API key presence, and last operation metrics
doctor--jsonRuns system diagnostics and integrity checks against the working environment
pauseNoneDisables local memory saving and searching by setting the paused setting to true
resumeNoneRe-enables local memory operations by setting the paused setting to false
forget--remote, --yes, --include-project-memoryPurges local repository memory scopes and optionally removes remote repository data from Mem0

Sources: integrations/mem0-agent-plugin/core/memory_cli.py:67-80, integrations/mem0-agent-plugin/core/memory_cli.py:92-146]

Warning

The forget subcommand enforces a safety check requiring the --yes flag; attempting to execute deletion without --yes aborts with exit code 2 to prevent accidental loss of user or project memory scopes integrations/mem0-agent-plugin/core/memory_cli.py:124-129.

Sources: integrations/mem0-agent-plugin/core/memory_cli.py:124-129]

The CLI records control telemetry events for every invoked command before executing the corresponding handler integrations/mem0-agent-plugin/core/memory_cli.py:91. Upon completion, the underlying EvidenceStore is safely closed within a finally block, and background telemetry flushes are spawned to transmit pending diagnostic records integrations/mem0-agent-plugin/core/memory_cli.py:147-150.

Sources: integrations/mem0-agent-plugin/core/memory_cli.py:91, integrations/mem0-agent-plugin/core/memory_cli.py:147-150]

Was this page helpful?