feat(mem0-plugin): support self-hosted Mem0 server via MEM0_BASE_URL

Adds an optional MEM0_BASE_URL override (env var, falling back to
settings.json's base_url, defaulting to the hosted Platform unchanged)
so the plugin's REST-backed hooks can talk to a self-hosted server/
deployment instead of api.mem0.ai.

A new scripts/_api.py centralizes the hosted-vs-self-hosted protocol
differences (unversioned paths, X-API-Key auth, agent_id instead of
app_id) that every hook previously hardcoded, and all 9 urllib call
sites now route through it.

MCP tools have no self-hosted backend (server/ implements no MCP), so
they continue to talk to the hosted Platform regardless of
MEM0_BASE_URL; this is documented rather than silently left unclear.
Coding-category customization also has no self-hosted SDK equivalent
and now skips cleanly with a log message instead of failing.

Closes MEM-5647
This commit is contained in:
kartik-mem0
2026-08-13 18:29:24 +05:30
parent 96d45b78c7
commit 16c2cfe50e
18 changed files with 579 additions and 151 deletions
@@ -71,37 +71,15 @@ fi
MEM0_COUNT="?"
if command -v python3 >/dev/null 2>&1; then
MEM0_COUNT=$(python3 -c "
import json, os, urllib.request, urllib.error
MEM0_COUNT=$(PYTHONPATH="$SCRIPT_DIR" python3 -c "
import os
from _api import count_memories
api_key = os.environ.get('MEM0_API_KEY', '')
user_id = os.environ.get('MEM0_RESOLVED_USER_ID', 'default')
app_id = os.environ.get('MEM0_PROJECT_ID', '')
project_id = os.environ.get('MEM0_PROJECT_ID', '')
global_search = os.environ.get('MEM0_GLOBAL_SEARCH', 'false') == 'true'
def get_count(filters):
body = json.dumps({'filters': filters}).encode()
req = urllib.request.Request(
'https://api.mem0.ai/v3/memories/?page=1&page_size=1',
headers={'Authorization': f'Token {api_key}', 'Content-Type': 'application/json'},
data=body, method='POST',
)
with urllib.request.urlopen(req, timeout=5) as r:
data = json.loads(r.read())
if isinstance(data, dict) and 'count' in data:
return data['count']
if isinstance(data, list):
return len(data)
return 0
try:
if global_search:
filters = {'OR': [{'user_id': '*'}]}
else:
filters = {'AND': [{'user_id': user_id}, {'app_id': app_id}]}
total = get_count(filters)
print(total)
except Exception:
print('?')
print(count_memories(api_key, user_id, project_id, global_search=global_search))
" 2>/dev/null || echo "?")
fi