Atlas / MCP servers / markhuangai / Dense-Mem

Dense-MemCAUTION

mcp/markhuangai/dense-mem

Self-hosted AI agent memory server with MCP, evidence provenance, typed claims, conflict detection, embeddings, recall, PostgreSQL, and pgvector

Verdict
CAUTION
Grade
F
Trust score
54 /100
Exposed tools
6 6r · 0w · 0d
Transport
streamable-http
License
Apache-2.0
Stars
39
01

Overview

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

Dense-Mem

English · 简体中文

Self-hosted MCP memory with durable evidence, explicit lifecycle, and support-gated recall.

Dense-Mem is a standalone HTTP MCP memory server using Streamable HTTP. It stages exact evidence, derives semantic state through validated server policy, and returns active evidence contexts with graph-shaped Relationship handles. PostgreSQL is the durable authority for knowledge, lifecycle, provenance, search, authorization, and audit; Redis is coordination only. A single-node deployment may use process-local coordination; a multi

Read from source at commit b48ff0e6c6c3OBSERVED · 2026-10-08
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
claude mcp add dense-mem-control-portal --env CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN} --env DENSE_MEM_BASELINE_SCRAPE_TOKEN=${DENSE_MEM_BASELINE_SCRAPE_TOKEN} --env DENSE_MEM_CANDIDATE_SCRAPE_TOKEN=${DENSE_MEM_CANDIDATE_SCRAPE_TOKEN} --env DENSE_MEM_CONTROL_TOKEN=${DENSE_MEM_CONTROL_TOKEN} -- npx -y [email protected]
claude-desktop
{
  "mcpServers": {
    "dense-mem-control-portal": {
      "command": "npx",
      "args": [
        "-y",
        "[email protected]"
      ],
      "env": {
        "CLOUDFLARE_API_TOKEN": "${CLOUDFLARE_API_TOKEN}",
        "DENSE_MEM_BASELINE_SCRAPE_TOKEN": "${DENSE_MEM_BASELINE_SCRAPE_TOKEN}",
        "DENSE_MEM_CANDIDATE_SCRAPE_TOKEN": "${DENSE_MEM_CANDIDATE_SCRAPE_TOKEN}",
        "DENSE_MEM_CONTROL_TOKEN": "${DENSE_MEM_CONTROL_TOKEN}"
      }
    }
  }
}
03

Exposed tools (6)

6 read · 0 write · 0 destructive.

ToolRiskDescription
Defaultread
Researchread
Stagingread
Teamread
rememberreadRemember
xread
04

Trust audit

CAUTIONgrade F · trust 54/100 Install with care. The audit found things worth knowing before you trust its output.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeWARN
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
none-observed
Network
declared (4 observation(s))
Shell
none-observed
Dependencies
not all pinned
Secrets in source
found

Findings (25)

MEDIUMNetwork egress · net.beacon_words · CWE-200, CWE-319
internal/assessor/assessor.go:52
Never create IDs, predicates, statuses, lifecycle decisions, owners, or conflict winners. Return exactly one evidence_security_results entry for every submitted evidence_id with decision pass or rejec
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
Dockerfile:97
CMD sh -c 'addr="${HTTP_ADDR:-:8080}"; port="${addr##*:}"; wget --quiet -O /dev/null "http://127.0.0.1:${port}/health"' || exit 1
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
Dockerfile.demo:75
CMD wget --quiet -O /dev/null http://127.0.0.1:8080/health || exit 1
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
cmd/internal/serverapp/composition_coverage_test.go:302
{"URL", "postgres://user:database-secret@localhost/memory?sslmode=disable", "database-secret"},
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
cmd/internal/serverapp/composition_coverage_test.go:303
{"escaped URL", "postgres://user:database%20p%40ss%3A%2F%25@localhost/memory?sslmode=disable", "database p@ss:/%"},
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
cmd/internal/serverapp/composition_coverage_test.go:331
dsn := "postgres://user:private%zz@localhost/memory"
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
internal/config/config_test.go:356
const resolvedDSN = "postgres://operator:resolved@localhost:5432/dense_mem?sslmode=disable"
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
internal/knowledge/postgres/owner_write_integration_test.go:205
dsn = "postgres://testuser:testpass@postgres:5432/testdb?sslmode=disable"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
internal/ontology/postgres/maintenance_service_integration_test.go:57
const token = "synthetic-maintenance-control"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
internal/recall/postgres/recall_evidence_history_integration_test.go:21
{name: "not required", state: "not_required", token: "historicalnotrequired"},
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
internal/storage/postgres/migrator_concurrency_integration_test.go:117
runtimeConfig.Password = "dense_mem_migration_runtime"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
tests/integration/discoverability_harness.go:51
token: "test-embedding-token-12345",
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
tests/uat/e2e_host_controller.test.mjs:884
const password = "ci-grafana-password-012345";
MEDIUMHard-coded secrets · secret.private_key · CWE-798, CWE-321
internal/remember/service/security_scan_test.go:33
"-----BEGIN PRIVATE KEY-----\nSGVsbG8gd29ybGQ=\n-----END PRIVATE KEY-----",
LOWInventory / provenance · inv.hidden_file · CWE-1104
.coderabbit.yaml
.coderabbit.yaml
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
.textlintignore
.textlintignore
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
.textlintrc.json
.textlintrc.json
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
tests/uat/pr_validation_policy.test.mjs:25
const permits = new Function("vars", "github", "needs", "always", `return (${condition});`);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
tests/uat/pr_validation_policy.test.mjs:41
const evaluate = new Function("needs", "github", `return (${expression});`);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
tests/uat/pr_validation_policy.test.mjs:208
return new Function(...Object.keys(context), `return (${javascript});`)(...Object.values(context));
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
tests/uat/pr_validation_policy.test.mjs:330
const shouldRun = new Function("needs", `return (${condition});`);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
tests/uat/pr_validation_policy.test.mjs:360
const shouldRun = new Function("needs", "github", `return (${condition});`);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
tests/eval/scripts/prepare_full_public_rag_eval.py:595
digest = hashlib.sha1(value.encode("utf-8")).hexdigest()[:16]
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
tests/eval/scripts/prepare_public_semantic_eval.py:886
digest = hashlib.sha1(value.encode("utf-8")).hexdigest()[:16]
LOWInformation disclosure · disclose.log_secret · CWE-209, CWE-532
internal/observability/logger_test.go:526
logger.Info(`request failed password=hunter2 metadata={"token":"json-secret"}`, slog.Group("request",

Gates applied: no_behavioural_pass.

Audited 2026-10-08 · audit v0.4.1 · source sha b48ff0e6c6c3full audit observations/trust-audit/mcp-server/markhuangai__dense-mem.json · Report an issue / request a re-scan
05

Audit history

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

DateSourceVerdictGradeScoreChange
2026-10-08b48ff0e6c6c3CAUTIONF54first audit
06

Questions

What is the Dense-Mem MCP server?

Self-hosted AI agent memory server with MCP, evidence provenance, typed claims, conflict detection, embeddings, recall, PostgreSQL, and pgvector

What tools does Dense-Mem expose?

6 in total: 6 read-only, 0 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is Dense-Mem safe to connect to an agent?

With care. The audit graded it F (54/100) and found 25 things worth knowing before you trust this server, listed below with the exact line each was found on.

What credentials does Dense-Mem need?

It reads CLOUDFLARE_API_TOKEN, DENSE_MEM_BASELINE_SCRAPE_TOKEN, DENSE_MEM_CANDIDATE_SCRAPE_TOKEN, DENSE_MEM_CONTROL_TOKEN, DENSE_MEM_LOAD_SCRAPE_TOKEN, EMBEDDING_PROXY_UPSTREAM_KEY and GITHUB_TOKEN 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 Dense-Mem run?

It speaks streamable-http, so it runs as a service you connect to over the network. It is published on npm as dense-mem-control-portal at 0.1.0.

How current is this page?

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

Advertisement