Skip to main content

docmost-mcp-oss

CI License: MIT Python 3.10+

An MCP server built with FastMCP that exposes the REST API of Docmost as tools for AI assistants (Claude Desktop, Claude Code, Cursor, VS Code…).

Managed with uv.

📄 Full API research: docs/DOCMOST-API.md. Verified against a real Docmost instance (not just the documentation).

Why a custom MCP?

Docmost ships with an official MCP, but it requires a Business/Enterprise license and is enabled from Settings → AI settings → MCP. This project uses the internal API (the same one the web UI consumes), which is also available in the self-hosted OSS edition.

About the name: the -oss suffix distinguishes this package from the unrelated docmost-mcp already on PyPI. They are different projects by different authors, and they would collide if installed side by side (both used to ship the same import package). This one targets self-hosted Docmost and can edit page bodies; install it as docmost-mcp-oss.

Exposed tools (20)

Category Tools
Pages search_pages, get_page, create_page, update_page, update_page_content, delete_page, restore_page, move_page, list_recent_pages, list_child_pages, get_page_breadcrumbs, get_page_history
Spaces list_spaces, get_space, create_space
Comments get_comments, create_comment, update_comment
User get_current_user, list_workspace_members

Two tools stand out:

  • get_page returns metadata and content in Markdown (it combines /pages/info with /pages/export, because the former does not return the body).
  • update_page_content replaces the body of an existing page. The REST API can't do this: it writes directly to the Yjs document over the collaboration WebSocket. Requires the yjs extra and takes ~13 s (Docmost persists with a 10 s debounce).

Editing the body of an existing page

Docmost's REST API ignores the content field in /pages/create and /pages/update (they respond 200 but save nothing): the body lives in the Yjs collaboration server.

That's why there are two distinct paths:

Operation How
Read content get_page
Create pagewith content create_page (uses /pages/import)
Replace the body of an existing page update_page_content (Yjs WebSocket)
Rename update_page
Delete / restore / move

update_page_content opens the wss://<host>/collab WebSocket, syncs the document, replaces the content and waits for it to persist. Markdown is converted using Docmost's own converter, so it supports the full schema (tables, lists, code, quotes, images…).

uv sync --extra yjs     # enables update_page_content

Technical details of the protocol: docs/YJS-EDITING.md.

Installation

uv creates the virtual environment and installs the dependencies (pinned in uv.lock):

uv sync

No need to activate the environment: use uv run ….

Configuration

cp .env.example .env   # then edit the values
DOCMOST_URL=https://docmost.example.com

# Option A — API Key
DOCMOST_API_KEY=dm_xxx

# Option B — login (works on OSS)
DOCMOST_EMAIL=tu@email.com
DOCMOST_PASSWORD=tu_password

Verify the connection:

uv run docmost-mcp-oss --check
# -> OK: authenticated as tu@email.com (https://docmost.example.com)

Usage

uv run docmost-mcp-oss

HTTP (for remote access)

uv run docmost-mcp-oss --http --port 8000
# MCP endpoint: http://127.0.0.1:8000/mcp

Connecting to MCP clients

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "docmost": {
      "command": "uv",
      "args": ["--directory", "/ruta/a/docmost-mcp-oss", "run", "docmost-mcp-oss"],
      "env": {
        "DOCMOST_URL": "https://docmost.example.com",
        "DOCMOST_EMAIL": "tu@email.com",
        "DOCMOST_PASSWORD": "tu_password"
      }
    }
  }
}

Claude Code

claude mcp add docmost -- uv --directory /ruta/a/docmost-mcp-oss run docmost-mcp-oss

Cursor (.cursor/mcp.json)

Same as Claude Desktop, inside the mcpServers key.

Tests

Command What it validates Needs instance
uv run python tests/test_client.py Client against a mocked Docmost (12 cases) No
uv run python tests/test_tools.py MCP tool registry No
uv run python tests/smoke_live.py Read-only against a real instance Yes
uv run python tests/smoke_mcp_live.py Tools through the MCP layer Yes
uv run --extra yjs python tests/smoke_yjs_live.py Body editing via Yjs (7 checks) Yes
uv run ruff check . Lint No

The live tests read credentials from .docmost-creds.json (ignored by git):

{
  "url": "https://docmost.example.com",
  "email": "you@example.com",
  "password": "your-password"
}

--write adds a create → update → get → delete cycle over a test page (use --write keep to keep it).

Implementation notes

Things that are not obvious and that the client already handles:

  • All endpoints are POST and respond with {data, success, status}; the client unwraps data.
  • Content does not come from /pages/info: it is fetched via /pages/export (markdown|html), which responds with the raw file, no wrapper.
  • Only /pages/import persists content over REST; /pages/create and /pages/update ignore content. To edit the body of an already-created page you must write to the Yjs document (see above).
  • Authentication: both real variants are supported — the authToken cookie (httpOnly) and data.tokens.accessToken forwarded as Bearer.
  • /search requires query and spaceId; if you don't provide a space, it fans out across all accessible spaces and merges by rank.
  • /pages/sidebar-pages requires spaceId; if you only provide a page, its space is resolved first.
  • Lexical search (PostgreSQL FTS): stopwords ("a", "de", "the") return 0 results.
  • Heterogeneous response shapes: some builds return {items, meta} and others raw lists; the client normalizes both.
  • Permissions: the MCP acts as the authenticated user; it can never do more than the user can.

Structure

docmost-mcp-oss/
├── docmost_mcp_oss/
│   ├── __init__.py
│   ├── client.py       # async HTTP client for the Docmost REST API
│   ├── collab.py       # Yjs WebSocket: read/write page bodies
│   └── server.py       # FastMCP server + tools
├── docs/
│   ├── DOCMOST-API.md  # API research (OSS + real instance)
│   └── YJS-EDITING.md  # collaboration WebSocket protocol
├── tests/
│   ├── test_client.py      # mocked, no network
│   ├── test_tools.py       # MCP tool registry, no network
│   ├── smoke_live.py       # real instance, read-only
│   ├── smoke_mcp_live.py   # MCP layer against a real instance
│   └── smoke_yjs_live.py   # body editing via Yjs
├── .github/workflows/ci.yml  # lint, tests and packaging
├── CONTRIBUTING.md
├── LICENSE                   # MIT
├── pyproject.toml            # metadata, dependencies and ruff config
├── uv.lock                   # reproducible resolution (it is versioned)
└── .env.example

License

MIT © 2026 Abel Santillan Rodriguez

Release files for docmost-mcp-oss 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for docmost-mcp-oss 0.1.0
File Size Uploaded
docmost_mcp_oss-0.1.0.tar.gz 159.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for docmost-mcp-oss 0.1.0
File Interpreter ABI Platform
docmost_mcp_oss-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 181.2 kB

Release files / docmost_mcp_oss-0.1.0.tar.gz

Download URL docmost_mcp_oss-0.1.0.tar.gz
Size 159.8 kB
Tags Source
SHA-256 checksum
How to use checksums
ad5cbbc85d9f4bb134b69feb7a01be1cbbc2a79fb261ad28df17dad279d4ab99
BLAKE2b-256 checksum
How to use checksums
6aad0ff40df687691a3ffff83a0a902320965647921864f076def9ba54a7c055
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / docmost_mcp_oss-0.1.0-py3-none-any.whl

Download URL docmost_mcp_oss-0.1.0-py3-none-any.whl
Size 21.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ba5f07c2e3aadd5aa1cb8d0b9c9157c982db76ef4edb5a223c98d72cfa31cf0
BLAKE2b-256 checksum
How to use checksums
1a23db837d8d4d44dc9a9ce42efbd99621a4d7942bc902198b72a5ffc0216bab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page