Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ WORKDIR /app
# node:24-alpine ships a `node` user at UID 1000 — matches obsidian-sync's
# PUID so both containers can read/write the shared /vault volume.
RUN apk add --no-cache tini libstdc++
ENV NODE_ENV=production PORT=8000 HOST=0.0.0.0
ENV NODE_ENV=production PORT=8000 HOST=0.0.0.0 VAULT_PATH=/vault INDEX_DB_PATH=/data/index.db
# OCI ownership marker for the MCP Registry — must match `name` in
# server.json. mcp-publisher reads this label off the image manifest.
LABEL io.modelcontextprotocol.server.name="io.github.aliasunder/vault-cortex"
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist/src ./dist/src
COPY package.json ./
Expand Down
5 changes: 5 additions & 0 deletions deploy/local/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,10 @@ VAULT_PATH=
# Log verbosity: debug | info | warn | error (default: info).
# LOG_LEVEL=info

# Directory for persistent log files inside the container.
# Unset by default — logs go to stdout only. Set a path to also write
# date-stamped log files there (the /data volume persists them).
# LOG_DIR=/data/logs

# Days to retain persistent log files before cleanup (default: 30).
# LOG_RETENTION_DAYS=30
8 changes: 6 additions & 2 deletions deploy/local/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ services:
PUBLIC_URL: ${PUBLIC_URL:-http://localhost:8000}
MEMORY_DIR: ${MEMORY_DIR:-About Me}
LOG_LEVEL: ${LOG_LEVEL:-info}
LOG_DIR: /data/logs
LOG_DIR: ${LOG_DIR:-}
LOG_RETENTION_DAYS: ${LOG_RETENTION_DAYS:-30}
TZ: ${TZ:-UTC}
# Uncomment to override smart defaults (see Configuration in the main README):
# Optional overrides. When unset, the server applies smart defaults
# (<MEMORY_DIR> below is the resolved MEMORY_DIR value, default "About Me"):
# PROTECTED_PATHS default: "<MEMORY_DIR>, Daily Notes" (blocked from vault_delete_note)
# ORPHAN_EXCLUDE_FOLDERS default: "Daily Notes, Templates, <MEMORY_DIR>" (excluded from vault_find_orphans)
# SERVICE_DOCUMENTATION_URL default: https://github.com/aliasunder/vault-cortex
# PROTECTED_PATHS: ${PROTECTED_PATHS:-}
# ORPHAN_EXCLUDE_FOLDERS: ${ORPHAN_EXCLUDE_FOLDERS:-}
# SERVICE_DOCUMENTATION_URL: ${SERVICE_DOCUMENTATION_URL:-}
Expand Down
4 changes: 4 additions & 0 deletions deploy/remote/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ VAULT_NAME=
# Log verbosity: debug | info | warn | error (default: info).
# LOG_LEVEL=info

# Directory for persistent log files inside the container (default: /data/logs).
# Set to empty to disable file logging (logs still go to stdout either way).
# LOG_DIR=/data/logs

# Days to retain persistent log files before cleanup (default: 30).
# LOG_RETENTION_DAYS=30

Expand Down
9 changes: 7 additions & 2 deletions deploy/remote/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ services:
# root. Docker named volumes inherit this root ownership, so the obsidian
# user (UID 1000) can't write sync state. This init container chowns the
# volume before obsidian-sync starts.
# Remove when upstream fixes: github.com/Belphemur/obsidian-headless-sync-docker
init-config-perms:
image: alpine:latest
command: sh -c "chown -R ${PUID:-1000}:${PGID:-1000} /config"
Expand Down Expand Up @@ -69,10 +70,14 @@ services:
PUBLIC_URL: "${PUBLIC_URL:?Set PUBLIC_URL to your server's public URL}"
MEMORY_DIR: ${MEMORY_DIR:-About Me}
LOG_LEVEL: ${LOG_LEVEL:-info}
LOG_DIR: /data/logs
LOG_DIR: ${LOG_DIR:-/data/logs}
LOG_RETENTION_DAYS: ${LOG_RETENTION_DAYS:-30}
TZ: ${TZ:-UTC}
# Uncomment to override smart defaults (see Configuration in the main README):
# Optional overrides. When unset, the server applies smart defaults
# (<MEMORY_DIR> below is the resolved MEMORY_DIR value, default "About Me"):
# PROTECTED_PATHS default: "<MEMORY_DIR>, Daily Notes" (blocked from vault_delete_note)
# ORPHAN_EXCLUDE_FOLDERS default: "Daily Notes, Templates, <MEMORY_DIR>" (excluded from vault_find_orphans)
# SERVICE_DOCUMENTATION_URL default: https://github.com/aliasunder/vault-cortex
# PROTECTED_PATHS: ${PROTECTED_PATHS:-}
# ORPHAN_EXCLUDE_FOLDERS: ${ORPHAN_EXCLUDE_FOLDERS:-}
# SERVICE_DOCUMENTATION_URL: ${SERVICE_DOCUMENTATION_URL:-}
Expand Down
5 changes: 5 additions & 0 deletions docker-compose.local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ services:
LOG_LEVEL: debug
MEMORY_DIR: ${MEMORY_DIR:-About Me}
TZ: ${TZ:-UTC}
# Left empty = the server applies smart defaults
# (<MEMORY_DIR> below is the resolved MEMORY_DIR value, default "About Me"):
# PROTECTED_PATHS default: "<MEMORY_DIR>, Daily Notes"
# ORPHAN_EXCLUDE_FOLDERS default: "Daily Notes, Templates, <MEMORY_DIR>"
# SERVICE_DOCUMENTATION_URL default: https://github.com/aliasunder/vault-cortex
PROTECTED_PATHS: ${PROTECTED_PATHS:-}
ORPHAN_EXCLUDE_FOLDERS: ${ORPHAN_EXCLUDE_FOLDERS:-}
SERVICE_DOCUMENTATION_URL: ${SERVICE_DOCUMENTATION_URL:-}
Expand Down
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ services:
LOG_RETENTION_DAYS: ${LOG_RETENTION_DAYS:-30}
TZ: ${TZ:-UTC}
MEMORY_DIR: ${MEMORY_DIR:-About Me}
# Left empty = the server applies smart defaults
# (<MEMORY_DIR> below is the resolved MEMORY_DIR value, default "About Me"):
# PROTECTED_PATHS default: "<MEMORY_DIR>, Daily Notes"
# ORPHAN_EXCLUDE_FOLDERS default: "Daily Notes, Templates, <MEMORY_DIR>"
# SERVICE_DOCUMENTATION_URL default: https://github.com/aliasunder/vault-cortex
PROTECTED_PATHS: ${PROTECTED_PATHS:-}
ORPHAN_EXCLUDE_FOLDERS: ${ORPHAN_EXCLUDE_FOLDERS:-}
SERVICE_DOCUMENTATION_URL: ${SERVICE_DOCUMENTATION_URL:-}
Expand Down
112 changes: 90 additions & 22 deletions server.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,127 @@
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.aliasunder/vault-cortex",
"title": "vault-cortex",
"description": "Remote MCP server for Obsidian vaults — search, memory, link graph, 23 tools, OAuth-protected.",
"description": "MCP server for Obsidian vaults — search, memory, link graph, 23 tools, OAuth-protected.",
"version": "0.15.3",
"websiteUrl": "https://github.com/aliasunder/vault-cortex",
"repository": {
"url": "https://github.com/aliasunder/vault-cortex",
"source": "github",
"id": "aliasunder/vault-cortex"
"id": "1226067541"
},
"packages": [
{
"registryType": "oci",
"identifier": "ghcr.io/aliasunder/vault-cortex",
"identifier": "ghcr.io/aliasunder/vault-mcp",
"version": "0.15.3",
"runtimeHint": "docker",
"runtimeArguments": [
{
"type": "named",
"name": "-p",
"description": "Publish the container's port 8000 on the host.",
"value": "{PORT}:8000",
"isRequired": true,
"variables": {
"PORT": {
"description": "Host port to expose vault-mcp on.",
"default": "8000",
"format": "number"
}
}
},
{
"type": "named",
"name": "-v",
"description": "Bind-mount your Obsidian vault into the container at /vault.",
"value": "{VAULT_PATH}:/vault:rw",
"isRequired": true,
"variables": {
"VAULT_PATH": {
"description": "Absolute path to your Obsidian vault on the host machine.",
"isRequired": true,
"format": "filepath"
}
}
},
{
"type": "named",
"name": "-v",
"description": "Named volume for persistent state under /data — search index, OAuth token DB, and any log files. Keeps OAuth sessions alive across container restarts.",
"value": "vault-cortex-data:/data"
}
],
"transport": {
"type": "streamable-http",
"url": "http://localhost:8000/mcp"
"url": "http://localhost:{PORT}/mcp",
"headers": [
{
"name": "Authorization",
"description": "Bearer token used by the MCP client. Must match the MCP_AUTH_TOKEN env var passed to the container.",
"value": "Bearer {MCP_AUTH_TOKEN}",
"isRequired": true,
"isSecret": true,
"variables": {
"MCP_AUTH_TOKEN": {
"description": "Bearer token for MCP client authentication. Generate with: openssl rand -hex 32",
"isRequired": true,
"isSecret": true
}
}
}
]
},
"environmentVariables": [
{
"name": "MCP_AUTH_TOKEN",
"description": "Bearer token for MCP client authentication. Generate with: openssl rand -hex 32",
"description": "Bearer token for MCP client authentication. Must match the Authorization header sent by clients. Generate with: openssl rand -hex 32",
"isRequired": true,
"isSecret": true
},
{
"name": "VAULT_PATH",
"description": "Absolute path to your Obsidian vault (mounted into the container)",
"isRequired": true,
"format": "filepath"
},
{
"name": "PUBLIC_URL",
"description": "Public URL for OAuth discovery metadata. Required for remote deployments with OAuth.",
"isRequired": false
"description": "Public URL clients use to reach this server. Used as the OAuth issuer URL in discovery metadata. Override when exposing the server outside localhost or on a non-default port.",
"default": "http://localhost:8000"
},
{
"name": "MEMORY_DIR",
"description": "Vault folder for structured memory files",
"default": "About Me",
"isRequired": false
"description": "Vault folder for structured memory files (About Me-style notes).",
"default": "About Me"
},
{
"name": "TZ",
"description": "IANA timezone for timestamps and daily note resolution",
"default": "UTC",
"isRequired": false
"description": "IANA timezone for timestamps and daily note resolution.",
"default": "UTC"
},
{
"name": "LOG_LEVEL",
"description": "Logging verbosity",
"description": "Logging verbosity.",
"default": "info",
"choices": ["debug", "info", "warn", "error"],
"isRequired": false
"choices": ["debug", "info", "warn", "error"]
},
{
"name": "LOG_DIR",
"description": "Directory for persistent log files. Unset by default — logs go to stdout only. Set to /data/logs to also write date-stamped .log files to the persistent volume.",
"format": "filepath"
},
{
"name": "LOG_RETENTION_DAYS",
"description": "Days to retain persistent log files before cleanup.",
"default": "30",
"format": "number"
},
{
"name": "PROTECTED_PATHS",
"description": "Comma-separated vault folder names blocked from vault_delete_note. Default: MEMORY_DIR and \"Daily Notes\"."
},
{
"name": "ORPHAN_EXCLUDE_FOLDERS",
"description": "Comma-separated vault folder names excluded from vault_find_orphans. Default: \"Daily Notes\", \"Templates\", MEMORY_DIR."
},
{
"name": "SERVICE_DOCUMENTATION_URL",
"description": "Override the OAuth service documentation URL exposed via discovery metadata.",
"default": "https://github.com/aliasunder/vault-cortex"
}
]
}
Expand Down