No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Pappmann a3d022a22a
All checks were successful
build-test-push-deploy / build-test-push (push) Successful in 3m12s
build-test-push-deploy / deploy (push) Has been skipped
memory_forget: optionaler project-Parameter für Unterprojekt-Scopes
memory_forget akzeptiert wie memory_get/pending/consolidate einen
server-autorisierten Unterprojekt-Scope, sodass Pending-Einträge aus dem
Root-Scope heraus verworfen werden können. Autorisierung mit
for_mutation=True: nur eigener Scope und Scopes darunter. read_scopes
werden dafür nun auch bei memory_forget mit project berechnet.

Fix: Das Label des eigenen Scopes (".") wurde bei Mutationen fälschlich
als read-only abgelehnt; betraf auch memory_consolidate.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 15:46:33 +02:00
.forgejo/workflows Auto-deploy mongomind-http to node1 via Keel webhook after CI build 2026-08-16 21:33:06 +02:00
deploy/k8s Fix Keel RBAC: cluster-wide read, namespace-scoped write 2026-08-16 21:41:15 +02:00
docs Registry-Flag include_global und read-only read_children-Scopes 2026-10-08 22:36:24 +02:00
evals Harden compression, add secret redaction, version chains and server guards 2026-07-11 17:58:35 +02:00
hooks Track Git actions in pending sessions 2026-07-13 13:15:57 +02:00
mongomind memory_forget: optionaler project-Parameter für Unterprojekt-Scopes 2026-10-09 15:46:33 +02:00
tests memory_forget: optionaler project-Parameter für Unterprojekt-Scopes 2026-10-09 15:46:33 +02:00
.dockerignore Add MicroK8s deployment manifests for node1 (mongomind-http, Keycloak+Postgres) 2026-08-10 04:54:01 +02:00
.gitignore memory_pending: Scope-Label voranstellen; .backups/ ignorieren 2026-09-14 22:41:41 +02:00
AGENTS.md memory_forget: optionaler project-Parameter für Unterprojekt-Scopes 2026-10-09 15:46:33 +02:00
CLAUDE.md Surface MongoDB unreachability instead of failing silently in hooks 2026-08-09 20:18:47 +02:00
COMMERCIAL-LICENSE.de.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00
COMMERCIAL-LICENSE.es.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00
COMMERCIAL-LICENSE.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00
CONTRIBUTING.de.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00
CONTRIBUTING.es.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00
CONTRIBUTING.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00
Dockerfile Add MicroK8s deployment manifests for node1 (mongomind-http, Keycloak+Postgres) 2026-08-10 04:54:01 +02:00
LICENSE Harden shared memory workflows and migrations 2026-07-12 00:33:15 +02:00
pyproject.toml Add mongomind-sync for cross-device memory transfer 2026-07-21 13:29:56 +02:00
README.de.md Registry-Flag include_global und read-only read_children-Scopes 2026-10-08 22:36:24 +02:00
README.es.md Registry-Flag include_global und read-only read_children-Scopes 2026-10-08 22:36:24 +02:00
README.md Registry-Flag include_global und read-only read_children-Scopes 2026-10-08 22:36:24 +02:00
SECURITY.de.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00
SECURITY.es.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00
SECURITY.md Add multilingual project documentation 2026-08-15 04:57:54 +02:00

English | Deutsch | Español

MongoMind

MongoMind is a resource-efficient, project-based memory system for coding agents. It provides the same MCP toolkit locally via stdio and remotely via Streamable HTTP. Active knowledge is curated; automatically captured session events are initially placed in a pending layer.

The runtime requires Python 3.10 or newer, pymongo, and PyJWT[crypto]. It does not launch an LLM, an embedding model, a graph runtime, or a background worker. Compression, redaction, ranking, and rollups are mechanical and limited.

Operating Modes

Mode Transport and Project Binding Authentication Use Case
Local Standard Dedicated stdio process per MCP client; project from Git top-level/cwd or MONGOMIND_PROJECT_ID Local process boundary and MongoDB access Recommended for single-machine operation
Remote POST /mcp/<slug>; slug is mapped to a fixed project ID via a server-side ACL OAuth/OIDC, external discovery/JWKS, exact resource audience and scopes HTTPS/multi-machine operation

Remote identity comes exclusively from the verified token and the server-side project registry. The old headers X-MongoMind-Project and X-MongoMind-Client are invalid and will be rejected. The HTTP transport will not even start without a complete OAuth 2.1 configuration (MONGOMIND_OAUTH_ISSUER).

Installation

git clone <REPOSITORY-URL> mongomind-mcp
cd mongomind-mcp
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -e .

This makes mongomind-mcp, mongomind-http, mongomind-admin, mongomind-hook-start, and mongomind-hook-capture available in .venv/bin/.

MongoDB User

The runtime user requires read and write permissions on the database mongomind in the target system, but no user management permissions. init and migrate additionally require index/schema permissions; for this purpose, a separate administration account should only be used during the maintenance window.

Example in mongosh as an existing MongoDB administrator. The runtime role is intentionally not allowed to create indexes or physically delete records; init also creates counters and locks before the first runtime startup:

use mongomind
db.createRole({
  role: "mongomindRuntime",
  privileges: [
    {
      resource: {db: "mongomind", collection: "observations"},
      actions: ["find", "insert", "update"]
    },
    {
      resource: {db: "mongomind", collection: "counters"},
      actions: ["find", "insert", "update"]
    },
    {
      resource: {db: "mongomind", collection: "locks"},
      actions: ["find", "insert", "update", "remove"]
    }
  ],
  roles: []
})
db.createUser({
  user: "mongomind-runtime",
  pwd: "LONG-RANDOM-RUNTIME-PASSWORD",
  roles: [{role: "mongomindRuntime", db: "mongomind"}]
})
db.createUser({
  user: "mongomind-admin",
  pwd: "DIFFERENT-LONG-RANDOM-ADMIN-PASSWORD",
  roles: [
    {role: "readWrite", db: "mongomind"},
    {role: "dbAdmin", db: "mongomind"}
  ]
})
install -d -m 700 ~/.env
install -m 600 /dev/null ~/.env/.mongomind_env

Contents of ~/.env/.mongomind_env:

MONGODB_MONGOMIND_URI="mongodb://mongomind-runtime:PASSWORD@localhost:27017/mongomind?authSource=mongomind"
MONGODB_MONGOMIND_ADMIN_URI="mongodb://mongomind-admin:ADMIN-PASSWORD@localhost:27017/mongomind?authSource=mongomind"

mongomind/store.py automatically reads this file and rejects insecure file permissions, symlinks, foreign owners, or sizes exceeding 64 KiB. Runtime paths use only MONGODB_MONGOMIND_URI; admin database commands prefer MONGODB_MONGOMIND_ADMIN_URI and only fall back to the runtime URI if it is missing. URIs and passwords do not belong in the repo or in hook files.

Initialize and Migrate the Database

New, empty database:

.venv/bin/mongomind-admin init
.venv/bin/mongomind-admin check

Before migrating existing data, follow this sequence: dry run → secure backup → migration → check. The runtime itself does not perform any migration or index changes.

Before the write migration run, terminate all MongoMind HTTP/MCP processes and pause the hooks. Do not restart the runtime until migrate and the subsequent check are healthy; during normalization, uniqueness indexes are checked and rebuilt.

.venv/bin/mongomind-admin migrate --dry-run

set -a
. ~/.env/.mongomind_env
set +a
umask 077
backup_dir="$(mktemp -d "$HOME/mongomind-backup.XXXXXX")"
backup_uri="${MONGODB_MONGOMIND_ADMIN_URI:-$MONGODB_MONGOMIND_URI}"
mongodump --uri="$backup_uri" \
  --archive="$backup_dir/mongomind.archive.gz" --gzip
unset backup_uri
chmod 700 "$backup_dir"
chmod 600 "$backup_dir/mongomind.archive.gz"

.venv/bin/mongomind-admin migrate
.venv/bin/mongomind-admin check

For these four commands, MONGODB_MONGOMIND_ADMIN_URI should point to the separate administration account; the running runtime retains its restricted URI. migrate --dry-run does not write. check pings the database, checks migration invariants, and compares each named index exactly, including key order, unique and partialFilterExpression. If there is drift, the check is invalid; running init/migrate restores the canonical definitions.

Local stdio operation

Claude Code:

claude mcp add mongomind --scope user \
  --env MONGOMIND_CLIENT=claude -- "$PWD/.venv/bin/mongomind-mcp"

Codex:

codex mcp add mongomind \
  --env MONGOMIND_CLIENT=codex -- "$PWD/.venv/bin/mongomind-mcp"

Other MCP clients run the same stdio command. MONGOMIND_PROJECT_ID can intentionally merge multiple worktrees under a stable, local project ID. MONGOMIND_READONLY=1 denies write tools and also prevents reinforcement.

Remote Operation with OAuth/OIDC

MongoMind is a resource server, not an identity provider. The external provider must provide OIDC discovery, JWKS, asymmetrically signed JWT access tokens, and the required scopes. For the slug mixxx, the resource and the expected single aud are exactly:

https://memory.example/mcp/mixxx

Multiple audiences or a different spelling will be rejected. The project and principal are bound on the server side from <slug>, sub, and client_id.

Project Registry v1

/etc/mongomind/projects.json:

{
  "version": 1,
  "projects": {
    "mixxx": {
      "project_id": "repo:mixxx",
      "allowed_principals": [
        {"sub": "user-123", "client_id": "codex-client"},
        {"sub": "hooks-mixxx", "client_id": "mongomind-hooks"}
      ],
      "read_children": ["mixxx-worktree"]
    },
    "mixxx-worktree": {
      "project_id": "repo:mixxx/worktree",
      "allowed_principals": []
    }
  }
}
sudo chown mongomind:mongomind /etc/mongomind/projects.json
sudo chmod 600 /etc/mongomind/projects.json

The file must be regular, symlink-free, owned by the server process, and have the exact mode 0600. Slugs, project IDs, principals, count, and file size are limited; unknown fields and duplicate JSON keys are rejected using fail-closed. read_children is optional and also grants the project read access to transitive subprojects; the relationships must point to registered slugs and must not contain cycles. Reading children is an explicit registry permission, not a filesystem search. The optional include_global: false hides the curated global entries for that slug (see docs/configuration.md).

Start the server

Behind a TLS-terminating reverse proxy:

MONGOMIND_PUBLIC_BASE_URL=https://memory.example \
MONGOMIND_OAUTH_ISSUER=https://id.example/realms/agents \
MONGOMIND_PROJECTS_FILE=/etc/mongomind/projects.json \
MONGOMIND_HTTP_HOST=0.0.0.0 MONGOMIND_HTTP_PORT=8642 \
MONGOMIND_HTTP_BEHIND_PROXY=1 \
  .venv/bin/mongomind-http

Alternatively, MongoMind terminates TLS itself if MONGOMIND_TLS_CERT and MONGOMIND_TLS_KEY are set together. The proxy must set request and header limits at least as strictly, enforce connection timeouts, and must not make the unencrypted backend port publicly accessible.

Public, project-specific protected resource metadata:

GET https://memory.example/.well-known/oauth-protected-resource/mcp/mixxx

The metadata refers to the configured issuer and resource. Discovery and JWKS are loaded only via HTTPS, without redirects, with size limits, and with caching.

Scopes

Scope Permission
mongomind:read Index, Search, Detail Retrieval, Pending, and Statistics
mongomind:write Save, Forget, Consolidate, and Rollup; also allows Reinforcement with memory_get
mongomind:transfer Server-side file export and import
mongomind:hooks:read POST /hooks/<slug>/start
mongomind:hooks:write POST /hooks/<slug>/events
mongomind:global:write Additional gate for memory_save(scope="global"); MONGOMIND_ALLOW_GLOBAL_WRITE=1 must also apply on the server side; always refused for registry slugs with include_global: false

Remote Clients

Codex registers the resource and then initiates interactive provider authorization:

codex mcp add mongomind-mixxx \
  --url https://memory.example/mcp/mixxx \
  --oauth-client-id codex-client \
  --oauth-resource https://memory.example/mcp/mixxx
codex mcp login mongomind-mixxx \
  --scopes mongomind:read,mongomind:write,mongomind:transfer

Claude Code:

claude mcp add --transport http --scope user \
  --client-id claude-client mongomind-mixxx \
  https://memory.example/mcp/mixxx

The OAuth provider must register these client IDs, allow redirect URIs as specified by the respective client, and issue JWTs with the exact resource audience. User authorization takes place at the provider; MongoMind does not accept passwords, authorization codes, or static remote headers.

Hooks

Templates are available at hooks/hooks.json (Claude Code) and hooks/codex.json (Codex). Using the admin tools, you can generate templates for the current installation and then review them in read-only mode:

.venv/bin/mongomind-admin hooks render --client claude --transport local \
  > /tmp/mongomind-claude-hooks.json
.venv/bin/mongomind-admin hooks check --file /tmp/mongomind-claude-hooks.json

The output is intentionally not automatically merged into an existing client configuration; copy the field hooks from it into the respective client configuration. The committed files are examples for this checkout, while hooks render uses the interpreter and remote environment of the current installation.

Local Hooks

Without MONGOMIND_HOOK_URL, the hook processes access MongoDB directly. SessionStart reads the active index; UserPromptSubmit, PostToolUse, Stop, and SessionEnd update one pending entry per project, client, and session. The templates must point to the scripts or the installed entry points of the virtual environment being used. When the pending threshold is reached, SessionStart returns, in addition to the model context, a visible systemMessage for Claude Code and Codex with the instruction to check memory_pending and consolidate relevant entries. Active curated entries from nested subprojects appear in the index; pending sessions remain limited to the specific project.

A git push is an exception to the otherwise strict “Pending” recording (see memory.md, section “Exception: git push”): PostToolUse immediately creates an additional active auto-captured/git-push note and returns—synchronously to the same still open session—a curation prompt, rather than waiting until the next SessionStart to remind the user. If curation does not occur, the auto-note remains active as a safety net.

This is not currently a foolproof guarantee with Codex: The Codex template still uses exec_command|functions.exec_command, while Codex Unified Exec is matched under Bash according to the current Hook documentation. On the local Codex CLI (0.147.0), PostToolUse errors with invalid JSON and exit code 1 were also observed. A terminal push outside of Codex is not captured by this hook. The open issue is documented in the Codex Review.

Remote Hooks

Remote hooks use OAuth client_credentials; user tokens are not reused.

install -d -m 700 ~/.config/mongomind
install -m 600 /dev/null ~/.config/mongomind/hook-client.secret
printf '%s\n' 'PROVIDER-CLIENT-SECRET' > ~/.config/mongomind/hook-client.secret
chmod 600 ~/.config/mongomind/hook-client.secret

export MONGOMIND_HOOK_URL=https://memory.example/hooks/mixxx
export MONGOMIND_OAUTH_RESOURCE=https://memory.example/mcp/mixxx
export MONGOMIND_OAUTH_CLIENT_ID=mongomind-hooks
export MONGOMIND_OAUTH_CLIENT_SECRET_FILE=$HOME/.config/mongomind/hook-client.secret
export MONGOMIND_OAUTH_TOKEN_CACHE_FILE=$HOME/.config/mongomind/hook-token.json
export MONGOMIND_OAUTH_SCOPES='mongomind:hooks:read mongomind:hooks:write'

.venv/bin/mongomind-admin hooks render --client codex --transport remote \
  > /tmp/mongomind-codex-remote-hooks.json
.venv/bin/mongomind-admin hooks check --file /tmp/mongomind-codex-remote-hooks.json

The hook and resource URLs must have the same HTTPS origin and slug. The client determines the token endpoint via Protected-Resource and Authorization-Server metadata, does not follow any redirects, and stores the token atomically in a file with 0600. The secret and cache must be separate files. The secret itself is never written to rendered hook commands.

Hook inputs are limited to 1 MiB. Only a normalized and redacted payload containing the event, a stable SHA-256-event_id, session/turn ID, limited prompt/assistant text, tool name, and at most 20 modified paths. Raw tool_input, cwd, and secrets do not leave the client. Repeated event_ids are idempotent. Hook entry points are intentionally fail-open: In the event of configuration, OAuth, network, or database errors, they write {} and terminate with status 0 so that the coding agent can continue working. stderr with status 0 ends up only in the debug log of the respective host CLI—it does not appear in the transcript and is invisible to both the user and the model. For the one error where this is relevant—MongoDB is unreachable—session_start.py therefore specifically sets a systemMessage instead of relying on stderr (see docs/configuration.md).

All hook variables, limits, and CA/timeout settings are listed in docs/configuration.md.

Cross-Device Sync

memory_import always recalculates the target scope from the calling context—locally, this is the device-dependent Git top-level path; remotely, it is the device-independent slug project_id. To ensure that the same repo ends up on multiple devices within the same mongomind-web project, mongomind-sync push bundles the export, scp, and the import to the correct /mcp/<slug> endpoint:

.venv/bin/mongomind-sync push --dry-run                        # export locally only
MONGOMIND_SYNC_BASE_URL=https://memory.example \
  .venv/bin/mongomind-sync push                                 # export -> scp -> import

The target slug is resolved from .mongomind.json in the repo or ~/.mongomind/project-map.json (key: normalized git remote get-url origin); it is never guessed. Details, all options, and the OAuth variables used can be found in docs/configuration.md.

MCP Tools

Tool Behavior
memory_save Save redacted, compressed, deduplicated active knowledge
memory_index Prioritized and type-diversified index of the current project and its child projects
memory_search Full-text search within the read scope, with automatic synonym expansion, filters, and hybrid ranking
memory_get Content and provenance for up to 10 IDs; child-project results are shown, while reinforcement remains scoped to the exact project. Optional project targets an already server-authorized child project explicitly, including its pending entries
memory_pending Check automatically recorded pending sessions. Optional project targets an already server-authorized child project instead of the current one
memory_consolidate Transfer pending sources atomically to an active memory. Optional project curates an already server-authorized child project; the result then records which scope it was curated from
memory_forget Archive exact project IDs
memory_stats Active, pending, archive, and expiration counters
memory_rollup Consolidate a limited batch of old pending sessions
memory_export Export data as a file to the server process’s file system
memory_import Import a file from the server process’s file system

memory_index, memory_search, and memory_get mark hits with Projekt=. Locally, this is a path relative to the selected workspace root; remotely, it is the registry slug. This origin is read-only; saving, forgetting, and consolidating remain specific to the exact project.

Remote import/export does not transfer files via MCP. The paths are always located on the server side under ~/.mongomind/exports/; therefore, a remote client does not receive a direct download or upload. This is listed as an open UX enhancement in the Roadmap.

The distinction between MongoMind as a project-specific memory layer and a direct, generic MongoDB MCP is documented in docs/mongomind-vs-mongodb-mcp.md.

Security Boundaries

  • MCP request and entire response: maximum of 1 MiB each; tool text maximum of 768 KiB; JSON depth 64; no duplicate keys, non-finite numbers, or JSON-RPC batches.
  • HTTP: Request line 8 KiB, total headers 32 KiB and 50 fields, MCP body 1 MiB, hook body 64 KiB, 16 concurrent connections (configurable from 1 to 128), queue 32, request timeout 5 s.
  • HTTP rates: globally 1200 requests/minute and per peer/principal 240/minute; MCP tools additionally 120 calls/minute and 30 write calls/minute per rate key.
  • memory_get: maximum of 10 IDs; general ID lists 100; title 300 characters; content 64 KiB; 20 tags; search query 500 characters.
  • Export: maximum of 500 records and 40 MiB, fixed export folder with 0700/0600 and path traversal protection. Import undergoes the same field validation, redaction, compression, and deduplication as memory_save.
  • Secrets and <private> blocks are redacted before storage or hook transmission. However, memories remain untrusted data and must be verified against the repository.

Administration and Diagnostics

.venv/bin/mongomind-admin auth check --offline
.venv/bin/mongomind-admin auth check
.venv/bin/mongomind-admin interop render --help
.venv/bin/mongomind-admin hooks render --help
.venv/bin/mongomind-admin hooks check --help

The offline auth check verifies the configuration and registry without provider access; the online check additionally loads the OIDC discovery and validates the issuer as well as jwks_uri. The JWKS itself is loaded to a limited extent during the first token check. The complete variable reference is available at docs/configuration.md, the staging interoperability verification at docs/interop.md, the architecture at docs/architecture.md and the memory model in docs/memory.md, the roadmap in docs/roadmap.md, and the security review in docs/feedback-codex.md.

Tests

.venv/bin/python -m unittest discover -s tests -v

E2E exclusively against a disposable database:

MONGOMIND_TEST_URI=mongodb://127.0.0.1:27717/mongomind_test \
  .venv/bin/python -m unittest tests.test_store_e2e -v

Compression benchmark:

.venv/bin/python -m evals.bench

License

MongoMind is free for personal, educational, scientific, charitable, and other non-commercial purposes. Commercial use requires a separate agreement.