Atlas / MCP servers / memtether / MemTether

MemTetherBLOCK

mcp/memtether/memtether

Cross-client AI memory hub — one physical SQLite, many clients. File-level pointers, REST API, Web Dashboard, MCP. Zero cloud. Dual-timeline governance. PyPI: memtether

Verdict
BLOCK
Grade
F
Trust score
52 /100
Exposed tools
—
Transport
stdio
License
Apache-2.0
Stars
2
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

Your agent remembers things. Who audits what it remembers?

MemTether is a local-first memory hub for multi-client AI agents. While most memory systems compete on retrieval accuracy, MemTether competes on governance: who wrote each fact, when it took effect, what it superseded, which conflicts a human adjudicated, and a tamper-evident hash chain anyone can verify — no code, no dependencies. Retrieval is provided (SGM deterministic SQL routing + hybrid embedding), but it is not the headline: agent memory that you can audit, correct, and trust is.

Coming from mem0, Zep, or Letta? examples/mem0_migration.py shows a complete round-trip migration from a mem0 JSON export — no mem0 SDK required.

$ memtether court fact-20261007-abc
+============================================================+
| MEMTETHER MEMORY COURT - CASE FILE                          |
| 1. CONTENT    Clash proxy port is 7897                      |
| 2. TEMPORAL   valid: 10-05 → present | known: 10-05 → now   |
| 3. PROVENANCE #1 remember by=codex → #2 correct by=user     |
| 4. CONFLICTS  case #3: vs fact-...old verdict=superseded    |
| 5. INTEGRITY  chain: PASS (3 anchors, 42 entries hashed)    |
+============================================================+

TL;DR

  • Your AI clients forget each other? Every agent keeps its own memory. MemTether gives them one shared, governed brain via file-level pointers — no cloud, no sync.
  • Your AI writes things it should not? Every memory carries a source identity and a hash-chained audit trail. Tamper with the database and the chain detects it — run python examples/audit_chain_demo.py to see it turn red.
  • Your AI changed its mind? Corrections never delete. Bi-temporal supersession keeps who-changed-what-when-why forever, queryable at
Read from source at commit 6cc5008e1812OBSERVED · 2026-10-11
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (pypi)
claude mcp add memtether -- None memtether==0.1.0a73
03

Trust audit

BLOCKgrade F · trust 52/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryWARN
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)FAIL
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (1 observation(s))
Network
declared (5 observation(s))
Shell
declared (7 observation(s))
Dependencies
pinned
Secrets in source
none-found

Findings (24)

HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
clients/local.py:74
yaml.load(text, Loader=_Loader)
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHPrompt injection · prompt.zero_width · CWE-94, CWE-1427
demo.html:1
<!DOCTYPE html>
Why it matters. invisible characters in instruction text
Fix. strip non-printing characters
MEDIUMInventory / provenance · inv.binary · CWE-1104
releases/eaf_artifact_bundle.zip
eaf_artifact_bundle.zip
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
gateway.py:1026
mod = __import__(os.path.splitext(os.path.basename(cred_path))[0])
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
gateway.py:1904
__import__(m)
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
mcp_server.py:490
__import__(_m)
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
memsearch.py:277
mod = __import__(os.path.splitext(os.path.basename(cred_path))[0])
MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
memsearch.py:455
__import__(m)
MEDIUMObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
trigger_detector.py:1
# -*- coding: utf-8 -*-
LOWInventory / provenance · inv.hidden_file · CWE-1104
.pre-commit-config.yaml
.pre-commit-config.yaml
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
.release-baseline.json
.release-baseline.json
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
integrations/codex-marketplace/plugins/memtether-memory/.mcp.json.template
.mcp.json.template
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
gateway.py:365
h = hashlib.md5(text.encode('utf-8')).hexdigest()[:12]
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
gateway.py:1209
rid = 'miss-%s' % hashlib.md5(query.encode('utf-8')).hexdigest()[:10]
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
hubguard.py:279
hashlib.md5(('%f' % time.time()).encode()).hexdigest()[:8])
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
scripts/selfcheck.py:135
h = hashlib.md5()
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
tests/test_absorb_semantic.py:58
h = hashlib.md5((c + "test").encode()).hexdigest()[:12]
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
.github/workflows/ci.yml:65
if curl -sf http://127.0.0.1:8820/health > /dev/null; then break; fi
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
.github/workflows/ci.yml:68
curl -sf http://127.0.0.1:8820/health
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
.github/workflows/ci.yml:69
BODY=$(curl -sf http://127.0.0.1:8820/dashboard)
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
_dev/benchmarks/asof_benchmark.py:31
"openai_base_url": "http://127.0.0.1:7874/v1",
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
_dev/benchmarks/downstream_harm.py:65
client = OpenAI(api_key=WB2API_KEY, base_url='http://127.0.0.1:7874/v1')
LOWObfuscation / stealth · obf.homoglyph · CWE-506, CWE-94
_dev/benchmarks/locomo_full_run.py:39
for ci, conv in enumerate(locomо if False else locomo):
LOWInventory / provenance · mcp.no_tools_extracted · CWE-1104
server.json
Why it matters. the tool list is enumerated at runtime by tools/list, not declared in source
Fix. the page says so rather than showing an empty table

Gates applied: no_behavioural_pass.

Audited 2026-10-11 · audit v0.4.1 · source sha 6cc5008e1812full audit observations/trust-audit/mcp-server/memtether__memtether.json · Report an issue / request a re-scan
04

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-116cc5008e1812BLOCKF52first audit
05

Questions

What is the MemTether MCP server?

Cross-client AI memory hub — one physical SQLite, many clients. File-level pointers, REST API, Web Dashboard, MCP. Zero cloud. Dual-timeline governance. PyPI: memtether

Is MemTether safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (52/100) and found 2 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does MemTether need?

It reads DEEPSEEK_OFFICIAL_KEY, GPTX_ASTRA_KEY, MEMTETHER_API_KEY, MEM_EXTRACT_API_KEY and ZHIPU_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does MemTether run?

It speaks stdio, so it runs as a local process your client starts. It is published on PyPI as memtether.

How current is this page?

The grade is for one exact copy of the source (6cc5008e1812), read on 2026-10-11. The repository is watched and re-audited when it changes.

Advertisement