Wiki.js Plugin: Technical
Technical details of the Wiki.js plugin: structure, startup flow, GraphQL client, SQLite schema for history and verified markers, validation, shrink guard and known quirks.
Wiki.js Plugin: Technical
This documentation always describes the latest published version.
Structure
wikijs-plugin/
├── .claude-plugin/ plugin.json and marketplace.json
├── .mcp.json Registration of the MCP server wikijs-mcp
├── bin/ run-server (POSIX) and run-server.cmd (Windows)
├── servers/wikijs-mcp-server/
│ ├── run.py Entry point
│ ├── server.py Tool registration
│ └── tools/ client, pages, validation, config, db, history
└── skills/ docs-wiki, source-check, translation-check, setup
The plugin has no hooks. The MCP server runs over the standard stdio transport and uses mcp[cli] (2.x), httpx and python-dotenv.
Architecture
graph TD
A["Claude Code"] --> B["MCP server wikijs-mcp"]
B --> C["Validation"]
C --> D["WikiJsClient (httpx)"]
D --> E["Wiki.js GraphQL API"]
B --> F["History (SQLite)"]
G["Skills"] --> B
| Component | Responsibility |
|---|---|
server.py |
Registers the ten tools with annotations, builds the client only on the first call |
tools/pages.py |
Business logic: validation, resolving path to ID, shrink guard, history |
tools/client.py |
GraphQL client with bearer token, 30 second time limit, truncation of large content |
tools/validation.py |
Input limits |
tools/config.py |
Loading credentials |
tools/db.py, tools/history.py |
SQLite schema, history and verified markers |
Startup flow
sequenceDiagram
participant C as Claude Code
participant R as bin/run-server
participant S as run.py
participant W as Wiki.js
C->>R: Start server
R->>S: Python from ~/.wikijs-plugin/venv
S->>S: Check credentials, abort if missing
C->>S: Tool call
S->>S: Create client on first call
S->>W: GraphQL request
W-->>S: Response
S-->>C: Result
The wrapper bin/run-server starts the Python interpreter from ~/.wikijs-plugin/venv/, on Windows bin/run-server.cmd does that. run.py checks the credentials before startup and exits with an error message if they are missing.
GraphQL access
| Tool | Wiki.js operation |
|---|---|
wikijs_list_pages |
pages.list, filter and slice locally |
wikijs_get_page |
pages.single (by ID) or pages.singleByPath |
wikijs_search_pages |
pages.search, locale filter locally |
wikijs_create_page |
pages.create |
wikijs_update_page |
pages.update, loads the page first and the page list when tags are missing |
wikijs_delete_page |
pages.delete |
wikijs_move_page |
pages.move |
Wiki.js errors (succeeded: false) become tool errors carrying the message from Wiki.js.
Local database
File: ~/.wikijs-plugin/wikijs-plugin.db (SQLite, WAL mode). The schema is created on the first real access.
Table page_history:
| Column | Content |
|---|---|
id |
Running number |
page_path |
Page path |
locale |
Language |
changed_at |
Timestamp (UTC) |
source_repo |
Source project |
source_ref |
Commit or tag |
summary |
Short note |
verified |
1 only for entries from wikijs_mark_verified, otherwise 0 |
page_updated_at |
updatedAt of the page at the time of the check |
An index on (page_path, locale, changed_at) speeds up the queries. The schema state is kept in PRAGMA user_version, older files are migrated on access.
- Written at:
wikijs_create_pageandwikijs_update_pagelog an entry when at least one ofsourceRepo,sourceRef,summaryis set. The ref only means that the page was written at that state. - Verified at: Only
wikijs_mark_verifiedsetsverified = 1.wikijs_get_verified_refsreturns the newest such entry per page and locale. Later unverified writes do not hide it. - Per machine: The file is local, there is no synchronisation. On another machine the same pages count as unverified.
- Fault tolerance: If logging fails (for example a locked database), the already written Wiki.js page stays valid and the message goes to stderr. When opening a locked database it retries up to five times. If the file sits on a network or cloud-sync path, the time limit is 30 instead of 5 seconds.
- Path key: History and markers hang on the path, not on the page ID. After
wikijs_move_pagethey stay with the old path.
Known quirks
| Quirk | Effect |
|---|---|
isPublished is not taken over from the page on updates |
Without isPublished: true a published page becomes a draft |
| Truncated content for pages over 100,000 characters | An update without content (or with the text as read) writes the truncated version back |
| The truncation notice names path access as a way out | Path access truncates as well |
wikijs_list_pages and updates without tags load all pages |
Noticeably slow on large wikis |
| Description up to 500 characters allowed | In practice the Wiki.js database limits to 255 |
| Path validation excludes dots and non-ASCII | Such pages can only be addressed by id |
More on error symptoms: Troubleshooting. On handling tokens and data: Privacy and security.