diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb58dee --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +data diff --git a/README.md b/README.md index 86e4edd..1a98867 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -mnemory +# mnemory +Self-hosted MCP memory server for LLMs — [fpytloun/mnemory](https://github.com/fpytloun/mnemory). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c5444a5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,89 @@ +--- +services: + mnemory: + image: genunix/mnemory:${MNEMORY_VERSION} + restart: unless-stopped + depends_on: + qdrant: + condition: service_healthy + environment: + - DATA_DIR=/data + - MCP_HOST=0.0.0.0 + - MCP_PORT=8050 + - MGMT_HOST=127.0.0.1 + - MGMT_PORT=9090 + - MCP_API_KEY=${MCP_API_KEY} + - SERVER_BASE_URL=${SERVER_BASE_URL} + - INSTRUCTION_MODE=${INSTRUCTION_MODE} + - ENABLE_METRICS=${ENABLE_METRICS} + - ENABLE_DELETE_ALL=${ENABLE_DELETE_ALL} + - LOG_LEVEL=${LOG_LEVEL} + - DEFAULT_TIMEZONE=${TIMEZONE} + - LLM_API_KEY=${LLM_API_KEY} + - LLM_BASE_URL=${LLM_BASE_URL} + - LLM_MODEL=${LLM_MODEL} + - EMBED_API_KEY=${EMBED_API_KEY} + - EMBED_BASE_URL=${EMBED_BASE_URL} + - EMBED_MODEL=${EMBED_MODEL} + - EMBED_DIMS=${EMBED_DIMS} + - QDRANT_HOST=qdrant + - QDRANT_PORT=6333 + - QDRANT_API_KEY=${QDRANT_API_KEY} + - QDRANT_COLLECTION=${QDRANT_COLLECTION} + - ARTIFACT_BACKEND=filesystem + - ARTIFACT_PATH=/data/artifacts + - SESSION_BACKEND=sqlite + - SESSION_PATH=/data/sessions.db + - FSCK_AUTO_INTERVAL=${FSCK_AUTO_INTERVAL} + healthcheck: + test: ["CMD", "httpx", "http://127.0.0.1:9090/health"] + interval: 30s + timeout: 5s + start_period: 20s + retries: 3 + labels: + ### Section Træfik + - traefik.enable=${TRAEFIK_ENABLED} + - traefik.docker.network=${TRAEFIK_NETWORK} + ## HTTP + - traefik.http.routers.http-${TRAEFIK_ROUTER}.entrypoints=http + # redirect to HTTPS only + - traefik.http.routers.http-${TRAEFIK_ROUTER}.middlewares=${TRAEFIK_HTTP_MIDDLEWARES} + - traefik.http.routers.http-${TRAEFIK_ROUTER}.rule=${TRAEFIK_MATCHRULE} + ## HTTPS + - traefik.http.routers.https-${TRAEFIK_ROUTER}.entrypoints=https + # configure the exposed service + - traefik.http.routers.https-${TRAEFIK_ROUTER}.middlewares=${TRAEFIK_HTTPS_MIDDLEWARES} + - traefik.http.routers.https-${TRAEFIK_ROUTER}.rule=${TRAEFIK_MATCHRULE} + # enable TLS and its certificate provider + - traefik.http.routers.https-${TRAEFIK_ROUTER}.tls=${TRAEFIK_TLSENABLED} + - traefik.http.routers.https-${TRAEFIK_ROUTER}.tls.certresolver=${TRAEFIK_CERTRESOLVER} + # specify a service so a custom port can be used + - traefik.http.services.${TRAEFIK_SERVICE}.loadbalancer.server.port=${TRAEFIK_SERVICE_PORT} + networks: + - internal + - traefik + volumes: + - ${MNEMORY_DATA}:/data + + qdrant: + image: qdrant/qdrant:${QDRANT_VERSION} + restart: unless-stopped + environment: + - QDRANT__SERVICE__API_KEY=${QDRANT_API_KEY} + healthcheck: + test: ["CMD", "bash", "-c", ":> /dev/tcp/127.0.0.1/6333"] + interval: 10s + timeout: 3s + start_period: 10s + retries: 5 + networks: + - internal + volumes: + - ${QDRANT_DATA}:/qdrant/storage + +networks: + internal: + traefik: + external: true + name: ${TRAEFIK_NETWORK} diff --git a/env.example b/env.example new file mode 100644 index 0000000..fe58506 --- /dev/null +++ b/env.example @@ -0,0 +1,40 @@ +# Træfik +TRAEFIK_ENABLED=true +TRAEFIK_NETWORK=traefik +TRAEFIK_ROUTER=mnemory_example_com +TRAEFIK_SERVICE=mnemory_example_com +TRAEFIK_SERVICE_PORT=8050 +TRAEFIK_MATCHRULE=Host(`mnemory.example.com`) +TRAEFIK_TLSENABLED=true +TRAEFIK_CERTRESOLVER=letsencrypt +TRAEFIK_HTTP_MIDDLEWARES=http-to-https +TRAEFIK_HTTPS_MIDDLEWARES=hsts + +# Mnemory +MNEMORY_VERSION=latest +MNEMORY_DATA=./data/mnemory +SERVER_BASE_URL=https://mnemory.example.com +MCP_API_KEY=changeme +INSTRUCTION_MODE=proactive +ENABLE_METRICS=true +ENABLE_DELETE_ALL=false +LOG_LEVEL=INFO +FSCK_AUTO_INTERVAL=24 +TIMEZONE=Europe/London + +# LLM (OpenAI-compatible — default xAI) +LLM_API_KEY=xai-changeme +LLM_BASE_URL=https://api.x.ai/v1 +LLM_MODEL=grok-4.5 + +# Embeddings (separate provider — xAI has no standalone embedding model) +EMBED_API_KEY=sk-changeme +EMBED_BASE_URL=https://api.openai.com/v1 +EMBED_MODEL=text-embedding-3-small +EMBED_DIMS=1536 + +# Qdrant +QDRANT_VERSION=v1.18.3 +QDRANT_DATA=./data/qdrant +QDRANT_API_KEY=changeme +QDRANT_COLLECTION=mnemory