docmost-mcp
by NeerdOnerT
README.md
# docmost-mcp
An MCP server that gives AI agents read/write access to a self-hosted
[Docmost](https://docmost.com) wiki through its regular REST API.
## Why this exists
Docmost ships its own MCP endpoint, but it is gated behind a paid licence — the
Settings UI shows *"Available with a paid license"* for API management, and
`/api/mcp` returns `404` on the Community Edition. Minting API keys is gated the
same way.
The ordinary REST API, however, is fully open in the Community Edition. This
server is a thin wrapper over it: same operations, session authentication
instead of an API key.
## Requirements
- Python 3.11+
- A Docmost instance you can reach over HTTP(S)
- A dedicated Docmost user account for the agent
## Install
```bash
git clone https://github.com/<you>/docmost-mcp.git
cd docmost-mcp
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
```
## Configure
Copy the example config and fill it in:
```bash
cp config.example.json config.json
chmod 600 config.json
```
```json
{
"url": "https://docmost.example.com",
"api_key": "",
"email": "agent@example.com",
"password": "..."
}
```
Two authentication modes are supported:
| Mode | When to use |
|---|---|
| `api_key` | If you hold a Docmost Enterprise licence. Sent as a Bearer token. |
| `email` + `password` | Community Edition. The server logs in and re-authenticates automatically when the session expires. |
If `api_key` is set it takes precedence; otherwise the credentials are used.
The config path can be overridden with the `DOCMOST_MCP_CONFIG` environment
variable.
### Create a dedicated account
Do not use the workspace owner's credentials. Invite a separate user
(Settings → Members → Invite) and grant it access only to the spaces the agent
needs. Space access in Docmost is usually inherited from the default *Everyone*
group, so check what that group can reach before assuming the agent is
restricted.
Gmail-style plus-addressing (`you+agent@gmail.com`) works if you would rather
not create a second mailbox.
## Verify
`selftest.py` exercises the whole chain — login, read, write, read back, delete:
```bash
./venv/bin/python selftest.py
```
## Connecting an agent
The server speaks MCP over **stdio**.
### Claude Code
```bash
claude mcp add docmost -- /path/to/docmost-mcp/venv/bin/python /path/to/docmost-mcp/server.py
```
Or add it to `~/.claude.json` by hand:
```json
{
"mcpServers": {
"docmost": {
"type": "stdio",
"command": "/path/to/docmost-mcp/venv/bin/python",
"args": ["/path/to/docmost-mcp/server.py"],
"env": {}
}
}
}
```
Restart Claude Code afterwards — the configuration is read at startup.
### Claude Desktop
Add the same block to `claude_desktop_config.json`:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
### Cursor
Add it to `.cursor/mcp.json` in the project, or to `~/.cursor/mcp.json`
globally, using the same `mcpServers` shape.
### Any other MCP client
Launch `server.py` with the virtualenv's Python and speak JSON-RPC over stdin
and stdout. A minimal handshake:
```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
```
A convenience wrapper keeps the command short:
```sh
#!/bin/sh
exec /path/to/docmost-mcp/venv/bin/python /path/to/docmost-mcp/server.py "$@"
```
## Tools
| Tool | Arguments | Does |
|---|---|---|
| `list_spaces` | `limit` | Lists workspace spaces |
| `search` | `query`, `space_id?`, `limit` | Full-text search across pages |
| `get_page` | `page_id` | Fetches a page by id or slugId |
| `recent_pages` | `space_id?`, `limit` | Recently changed pages |
| `create_page` | `space_id`, `title`, `content?`, `parent_page_id?`, `fmt` | Creates a page |
| `update_page` | `page_id`, `title?`, `content?`, `fmt` | Updates title and/or body |
| `move_page` | `page_id`, `parent_page_id?` | Reparents a page |
| `delete_page` | `page_id`, `permanently` | Trashes (or permanently deletes) a page |
`fmt` is `markdown` (default), `html` or `json`.
## Notes on the Docmost API
Things worth knowing if you extend this server:
- Every endpoint is `POST`, including reads.
- `/pages/create` and `/pages/update` **require** a `format` field
(`json` | `markdown` | `html`). Omitting it returns `400`.
- Responses wrap the payload in `{"data": ...}`; the client unwraps it.
- `/api/api-keys` answers `200` with an empty list on the Community Edition —
listing is open, only key *creation* is licence-gated.
- Endpoint paths and payload shapes were taken from the Docmost client source
(`apps/client/src/features/*/services/*.ts`), not guessed.
## Security
- `config.json` holds a plaintext password. Keep it at mode `600` and out of
version control — it is in `.gitignore`.
- Give the agent account the narrowest space access that still lets it work.
- The account's actions appear in Docmost under its own name, so page history
stays attributable.
## Compatibility
Built against Docmost 0.95.0 and Python MCP SDK 2.0. Note that SDK 2.0 renamed
`FastMCP` to `MCPServer` and moved it to `mcp.server`; the pre-2.0 import path
`mcp.server.fastmcp` will not work.
## Licence
MIT — see [LICENSE](LICENSE).
This project is not affiliated with Docmost.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues