Docmost (self-hosted)

Registre officiel Autres

Self-hosted remote MCP server for Docmost CE: members read and edit the wiki as themselves

Installation

Ajoutez ceci à la configuration MCP de votre client (Claude Desktop : claude_desktop_config.json ; Cursor : .cursor/mcp.json ; VS Code et les autres utilisent la même forme « mcpServers »).

OCI package ghcr.io/bbik52/docmost-mcp-remote:1.2.3
Claude Code
claude mcp add docmost-self-hosted -e 'PUBLIC_URL=http://localhost:8000' -e 'DOCMOST_URL=<DOCMOST_URL>' -e 'DATABASE_URL=<your database_url>' -e 'SECRET_KEY=<your secret_key>' -- docker run -i --rm ghcr.io/bbik52/docmost-mcp-remote:1.2.3
Configuration JSON (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "docmost-self-hosted": {
            "command": "docker",
            "args": [
                "run",
                "-i",
                "--rm",
                "ghcr.io/bbik52/docmost-mcp-remote:1.2.3"
            ],
            "env": {
                "PUBLIC_URL": "http://localhost:8000",
                "DOCMOST_URL": "<DOCMOST_URL>",
                "DATABASE_URL": "<your database_url>",
                "SECRET_KEY": "<your secret_key>"
            }
        }
    }
}

Variables d'environnement

  • PUBLIC_URL obligatoire Public URL of this server: http://localhost:8000 locally, or the https URL of your reverse proxy
  • DOCMOST_URL obligatoire Base URL of your Docmost, Community Edition 0.80.1 or newer
  • DATABASE_URL obligatoire secret Postgres URL for the server's own data, e.g. postgresql://user:password@host/db
  • SECRET_KEY obligatoire secret Random value of at least 32 characters; encrypts stored Docmost sessions
PYPI package docmost-mcp-remote
Claude Code
claude mcp add docmost-self-hosted -e 'PUBLIC_URL=http://localhost:8000' -e 'DOCMOST_URL=<DOCMOST_URL>' -e 'DATABASE_URL=<your database_url>' -e 'SECRET_KEY=<your secret_key>' -- uvx docmost-mcp-remote==1.2.3
Configuration JSON (Claude Desktop, Cursor, VS Code)
{
    "mcpServers": {
        "docmost-self-hosted": {
            "command": "uvx",
            "args": [
                "docmost-mcp-remote==1.2.3"
            ],
            "env": {
                "PUBLIC_URL": "http://localhost:8000",
                "DOCMOST_URL": "<DOCMOST_URL>",
                "DATABASE_URL": "<your database_url>",
                "SECRET_KEY": "<your secret_key>"
            }
        }
    }
}

Variables d'environnement

  • PUBLIC_URL obligatoire Public URL of this server: http://localhost:8000 locally, or the https URL of your reverse proxy
  • DOCMOST_URL obligatoire Base URL of your Docmost, Community Edition 0.80.1 or newer
  • DATABASE_URL obligatoire secret Postgres URL for the server's own data, e.g. postgresql://user:password@host/db
  • SECRET_KEY obligatoire secret Random value of at least 32 characters; encrypts stored Docmost sessions

Documentation

Tirée du README du projet sur GitHub, actualisée chaque semaine. Les liens ouvrent GitHub.

Sommaire
  1. docmost-mcp-remote
  2. How it works
  3. Supported Docmost versions
  4. Tools
  5. Security model
  6. Quick start
  7. Reverse proxy
  8. Connecting a client
  9. Administration
  10. Upgrading
  11. Configuration
  12. Development
  13. License

docmost-mcp-remote

English · Русский

A self-hosted remote MCP server for Docmost Community Edition. Run it next to your Docmost, put it behind your domain, and let AI clients such as Claude, Claude Code, Cursor or VS Code read and edit the wiki on behalf of each member, with that member's own Docmost account and rights.

  • One server, one Docmost, many members. Each member signs in with their own Docmost account in the browser. Everything their AI client does is done as them in Docmost.
  • Authorization is mandatory. OAuth 2.1 for remote connectors and personal bearer tokens for scripts. There is no unauthenticated mode.
  • Safe by default. read is the only scope granted without asking. Writing and moving to Trash need explicit scopes. Nothing is deleted permanently, and the server keeps an encrypted snapshot of a page body before every change.
  • Self-hosted. One container plus Postgres, with a ready compose.yaml.

Quick start · Connecting a client · Tools · Security model · Configuration · Upgrading

How it works

flowchart LR
    member(["Member"]) -. "signs in once with<br/>their Docmost account" .-> server
    client["AI client<br/>Claude, Cursor, VS Code"] -- "MCP over https<br/>OAuth 2.1 or personal token" --> server["docmost-mcp-remote"]
    server -- "Docmost API,<br/>as that member" --> docmost["Docmost CE"]
    server --- db[("Postgres<br/>sessions, snapshots,<br/>audit log")]

The first time a client connects, the member signs in with their Docmost email and password and picks what the client may do. They can see and revoke every connected app and token on their account page.

Choosing what a client may do Connected apps and personal tokens

Supported Docmost versions

Docmost Community Edition 0.70.0 or newer. Older versions are refused at sign-in. CI runs the integration tests against Docmost 0.70.3, 0.96.0 and 0.97.0; newer releases work in most cases and log a warning until they are added to the tested range. Docmost users who sign in with SSO only (an Enterprise feature) cannot use this server: it signs in with email and password.

Tools

ToolScopeWhat it does
whoamireadThe Docmost account, scopes and Docmost version of this connection
list_spacesreadSpaces you can access, with your role
list_pagesreadPage tree of a space, one level at a time
recent_pagesreadRecently updated pages
get_pagereadOne page as Markdown, by id, slug id or Docmost URL
searchreadFull-text search with snippets
list_commentsreadComments and replies on a page
list_trashreadPages in the Trash of a space
list_snapshotsreadSnapshots this server saved before your changes to a page
create_pagewriteNew page with a Markdown body, optionally under a parent
update_pagewriteAppend, prepend or replace a page body with Markdown
rename_pagewriteChange a page title
move_pagewriteMove a page within its space, to the start, the end or after a sibling
add_commentwriteComment on a page or reply to a comment
restore_snapshotwritePut a page body back to a snapshot
trash_pagedeleteMove a page to the Trash
restore_pagedeleteRestore a page from the Trash

Page bodies, comments and snippets are returned inside a <docmost-untrusted-content> envelope so the model treats them as data.

Before every body change the server saves the current body as a snapshot in its own database, encrypted, for SNAPSHOT_RETENTION_DAYS; if the snapshot cannot be saved, nothing is written. After the change it reads the page back and reports an error if Docmost did not apply it (this happens when Docmost runs with COLLAB_DISABLE_REDIS). Snapshots can hold content of pages that were later deleted in Docmost until they expire.

Security model

Members sign in with their own Docmost account; everything a client does is done as that member, with their Docmost rights. The server keeps the Docmost session token encrypted with a key derived from SECRET_KEY and does not store passwords unless RELOGIN_MODE=stored_password. Personal tokens are stored as hashes and shown once. The sign-in page has CSRF protection and per-IP and per-email rate limits.

The server is its own OAuth 2.1 authorization server, following the MCP authorization spec: dynamic client registration (limited per IP, redirect URIs must be https, loopback http or a native app scheme), authorization code with PKCE (S256 only), exact redirect URI match, tokens bound to this server's /mcp resource, one-hour access tokens and 30-day refresh tokens that rotate on every use. A reused refresh token or a replayed code revokes the whole grant. OAuth grants and personal tokens are listed and revoked on the same account page.

Page content is treated as untrusted data and labelled as such for the model. Prompt injection in a page can still make a client act within the scopes the member granted, so grant write and delete only to clients you trust. Tool calls are limited per member and recorded in an audit log. See the threat model, SECURITY.md for how to report a vulnerability and the design.

Quick start

You need Docker with Compose, a Docmost reachable from the server, and a host name with https for the server itself, for example mcp.example.com.

  1. Download the compose file and the settings template:
     mkdir docmost-mcp && cd docmost-mcp
     curl -fsSLO https://raw.githubusercontent.com/bbik52/docmost-mcp-remote/master/compose.yaml
     curl -fsSL -o .env https://raw.githubusercontent.com/bbik52/docmost-mcp-remote/master/.env.example
  2. Edit .env: set PUBLIC_URL (the https URL of this server), DOCMOST_URL, a long random POSTGRES_PASSWORD and SECRET_KEY (openssl rand -hex 32 gives a good value for both). Consider ALLOWED_EMAILS to limit who can sign in.
  3. Start it and check that it is up:
     docker compose up -d
     curl http://127.0.0.1:8000/healthz
  4. Put a reverse proxy with https in front of 127.0.0.1:8000 (see below) and open PUBLIC_URL/login in a browser to check that you can sign in with your Docmost account.
  5. Connect a client (see Connecting a client).

The server applies its database migrations at startup. Back up the Postgres volume like you back up Docmost: it holds the encrypted sessions, the snapshots and the audit log. Losing SECRET_KEY signs every member out and makes the snapshots unreadable.

The compose.yaml

# docmost-mcp-remote: the server and its Postgres.
# Copy .env.example to .env and fill in the required values first, then put a
# reverse proxy with https in front of port 8000.

services:
  server:
    # "1" follows 1.x releases; set IMAGE_TAG to a full version such as 1.0.0 to pin one.
    image: ghcr.io/bbik52/docmost-mcp-remote:${IMAGE_TAG:-1}
    restart: unless-stopped
    environment:
      PUBLIC_URL: ${PUBLIC_URL:?set PUBLIC_URL to the public https URL of this server}
      DOCMOST_URL: ${DOCMOST_URL:?set DOCMOST_URL to the base URL of your Docmost}
      DOCMOST_ALLOW_INSECURE_HTTP: ${DOCMOST_ALLOW_INSECURE_HTTP:-false}
      DATABASE_URL: postgresql://docmost_mcp:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/docmost_mcp
      SECRET_KEY: ${SECRET_KEY:?set SECRET_KEY to a random value of at least 32 characters}
      SECRET_KEY_PREVIOUS: ${SECRET_KEY_PREVIOUS:-}
      ALLOWED_EMAILS: ${ALLOWED_EMAILS:-}
      ALLOWED_SPACES: ${ALLOWED_SPACES:-}
      RELOGIN_MODE: ${RELOGIN_MODE:-ask}
      SNAPSHOT_RETENTION_DAYS: ${SNAPSHOT_RETENTION_DAYS:-30}
      AUDIT_RETENTION_DAYS: ${AUDIT_RETENTION_DAYS:-90}
      TOOL_CALLS_PER_MINUTE: ${TOOL_CALLS_PER_MINUTE:-60}
      MAX_PAGE_CHARS: ${MAX_PAGE_CHARS:-60000}
      # The port is published on 127.0.0.1 only, so every client is a local proxy.
      FORWARDED_ALLOW_IPS: ${FORWARDED_ALLOW_IPS:-*}
      LOG_LEVEL: ${LOG_LEVEL:-info}
    ports:
      - "127.0.0.1:8000:8000"
    depends_on:
      postgres:
        condition: service_healthy
    read_only: true
    tmpfs:
      - /tmp
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true

  postgres:
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: docmost_mcp
      POSTGRES_DB: docmost_mcp
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U docmost_mcp -d docmost_mcp"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres-data:

The server is also on PyPI (pip install docmost-mcp-remote or uvx docmost-mcp-remote) for setups without containers; it needs Postgres and the same settings as environment variables.

Reverse proxy

The server listens on plain http and expects a reverse proxy that terminates https. Serve it at the root of its own host name; a sub-path is not supported. The proxy must not buffer responses, because MCP streams them.

Caddy (gets certificates by itself):

mcp.example.com {
    reverse_proxy 127.0.0.1:8000
}

nginx

server {
    listen 443 ssl;
    server_name mcp.example.com;
    ssl_certificate     /etc/letsencrypt/live/mcp.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mcp.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
        proxy_read_timeout 1h;
    }
}

The server uses X-Forwarded-For for its per-IP rate limits. The compose file publishes the port on 127.0.0.1 only and trusts the header from every client; if you publish the port elsewhere, set FORWARDED_ALLOW_IPS to the proxy's address.

Connecting a client

The MCP endpoint is PUBLIC_URL/mcp, for example https://mcp.example.com/mcp. Clients that support MCP authorization open a browser window: sign in with your Docmost email and password and choose what the client may do. read is always granted; tick write or delete only for clients you trust.

Claude.ai and Claude Desktop: Settings, Connectors, Add custom connector, then enter the endpoint URL. The server must be reachable from the internet over https for Claude.ai.

Claude Code:

claude mcp add --transport http docmost https://mcp.example.com/mcp

Then run /mcp in Claude Code to sign in.

Cursor (~/.cursor/mcp.json):

{
  "mcpServers": {
    "docmost": { "url": "https://mcp.example.com/mcp" }
  }
}

VS Code (.vscode/mcp.json):

{
  "servers": {
    "docmost": { "type": "http", "url": "https://mcp.example.com/mcp" }
  }
}

With a personal token (scripts and clients without OAuth):

  1. Open PUBLIC_URL/login and sign in with your Docmost email and password.
  2. On the account page, create a personal token with the scopes you need.
  3. Configure the client with the endpoint and the header Authorization: Bearer <token>:
     claude mcp add --transport http docmost https://mcp.example.com/mcp \
       --header "Authorization: Bearer dmr_..."

Connected apps and tokens are listed and revoked on the account page, PUBLIC_URL/account.

Administration

The admin command runs where the server runs, with the same environment:

docker compose exec server docmost-mcp-remote admin members
docker compose exec server docmost-mcp-remote admin migrate
docker compose exec server docmost-mcp-remote admin grants anna@example.com
docker compose exec server docmost-mcp-remote admin revoke-grant <grant id>
docker compose exec server docmost-mcp-remote admin revoke-member anna@example.com
docker compose exec server docmost-mcp-remote admin disable-member anna@example.com
docker compose exec server docmost-mcp-remote admin audit --email anna@example.com

revoke-member revokes every grant of the member and drops their stored Docmost session; disable-member blocks them until enable-member. Every tool call is recorded in the audit log with the tool, the page or space id and the outcome, never with content or arguments.

To rotate SECRET_KEY: set the old value as SECRET_KEY_PREVIOUS and a new SECRET_KEY, restart, run admin rotate-key, then remove SECRET_KEY_PREVIOUS and restart again.

Upgrading

  1. Read the changelog for "Upgrade notes".
  2. Back up the database:
     docker compose exec -T postgres pg_dump -U docmost_mcp -Fc docmost_mcp > docmost-mcp-$(date +%F).dump
  3. Pull the new image and restart:
     docker compose pull && docker compose up -d

The server upgrades its database schema at startup, in one transaction and one process at a time, so a failed upgrade leaves the old schema in place. docker compose exec server docmost-mcp-remote admin migrate shows the schema revision.

The image tag 1 follows 1.x releases; set IMAGE_TAG in .env to pin a version. Going back to an older version after its schema was upgraded is not supported: an older server refuses to start on a newer schema. To roll back, restore the backup with the old image:

docker compose stop server
docker compose exec -T postgres pg_restore -U docmost_mcp -d docmost_mcp --clean --if-exists < docmost-mcp-2026-01-31.dump
IMAGE_TAG=1.0.0 docker compose up -d

Configuration

VariableRequiredDefaultMeaning
PUBLIC_URLyesPublic https URL of this server
DOCMOST_URLyesBase URL of your Docmost
DOCMOST_ALLOW_INSECURE_HTTPnofalseAllow an http:// DOCMOST_URL on a trusted private network
DATABASE_URLyesPostgres URL (postgresql://user:password@host/db)
SECRET_KEYyesAt least 32 characters; encrypts stored Docmost sessions and signs cookies
SECRET_KEY_PREVIOUSnoThe old key during a rotation
ALLOWED_EMAILSnoemptyComma-separated emails allowed to sign in; empty allows every Docmost user
ALLOWED_SPACESnoemptyComma-separated space slugs or ids members may use through this server; empty allows all
MAX_PAGE_CHARSno60000Longest page body returned; longer bodies are truncated
SNAPSHOT_RETENTION_DAYSno30Days a snapshot of a page body is kept
AUDIT_RETENTION_DAYSno90Days an audit log entry is kept
TOOL_CALLS_PER_MINUTEno60Tool calls one member may make per minute, over all their clients
RELOGIN_MODEnoaskask: members sign in again when their Docmost session expires; stored_password: the password is kept encrypted and used to sign in again
DOCMOST_TIMEOUT_SECONDSno15Timeout for one request to Docmost
DOCMOST_MAX_RESPONSE_BYTESno5242880Largest Docmost response the server reads
FORWARDED_ALLOW_IPSno127.0.0.1Proxies trusted for X-Forwarded-For (* in the compose file)
HOST / PORTno0.0.0.0 / 8000Listen address
LOG_LEVELnoinfodebug, info, warning or error
IMAGE_TAGno1Image tag used by compose.yaml

Development

uv sync
uv run ruff check . && uv run ruff format --check .
uv run mypy
DATABASE_TEST_URL=postgresql://test:test@localhost:5433/test uv run pytest

Tests that need Postgres are skipped without DATABASE_TEST_URL; for example docker run -d -p 5433:5432 -e POSTGRES_USER=test -e POSTGRES_PASSWORD=test postgres:17-alpine.

Integration tests run against a real Docmost:

DOCMOST_VERSION=0.97.0 docker compose -f tests/integration/compose.yaml up -d
DOCMOST_TEST_URL=http://localhost:3000 uv run pytest tests/integration

To run the compose stack with a local build:

docker build -t ghcr.io/bbik52/docmost-mcp-remote:dev .
IMAGE_TAG=dev docker compose up -d

See CONTRIBUTING.md and the roadmap.

License

Apache License 2.0. The license does not cover the project name: forks are welcome under another name. This project is an independent implementation and is not affiliated with Docmost. It was inspired by docmost-mcp-oss.

Questions fréquentes

Qu'est-ce que Docmost (self-hosted) ?

Self-hosted remote MCP server for Docmost CE: members read and edit the wiki as themselves

Comment installer Docmost (self-hosted) ?

Il s'exécute sur votre machine. Dans Claude Code : claude mcp add docmost-self-hosted -e 'PUBLIC_URL=http://localhost:8000' -e 'DOCMOST_URL=<DOCMOST_URL>' -e 'DATABASE_URL=<your database_url>' -e 'SECRET_KEY=<your secret_key>' -- docker run -i --rm ghcr.io/bbik52/docmost-mcp-remote:1.2.3. Pour les autres clients, collez la configuration JSON de cette page dans leurs réglages MCP.

Faut-il une clé API pour Docmost (self-hosted) ?

Oui. Il attend PUBLIC_URL, DOCMOST_URL, DATABASE_URL, SECRET_KEY, à renseigner dans sa configuration.

Docmost (self-hosted) est-il open source ?

Oui. Son code est sur GitHub sous licence Apache-2.0.

Qui maintient Docmost (self-hosted) ?

Il est publié par bbik52. AI.tn le référence sans le maintenir ni le recommander.

Issu du registre MCP officiel. Être listé n'est pas une recommandation : vérifiez le code et les permissions d'un serveur avant de lui donner accès à vos données.