Skip to main content
Glama
README.md
<p align="center">
  <img src="src/www/images/_raydeStar.png" alt="WikiMCP" width="120" />
</p>

<h1 align="center">WikiMCP</h1>

<p align="center">
  MCP server for a Wiki.js project. Provides full-text search, page retrieval, and optional page creation via the Model Context Protocol.
</p>

## What this repo gives you

- **A Wiki.js stack** (Wiki.js + Postgres) you can run locally with Docker.
- **An MCP server** (Node/TypeScript) that exposes Wiki tools over **stdio** (spawned by a client like LM Studio / Cursor / Claude Desktop).
- **Receipts-first tooling**: `wiki.quote` returns exact line ranges so answers can cite sources.

---

## Architecture in one picture

```text
┌──────────────┐        ┌───────────────────────┐
│ MCP Client   │        │ Wiki.js (UI)          │
│ (LM Studio / │        │ + Postgres            │
│ Cursor / …)  │        └──────────┬────────────┘
└──────┬───────┘                   │
       │ spawns (stdio)            │
       ▼                           │ reads/imports
┌───────────────────────┐          │ markdown
│ WikiMCP (this repo)   │◄─────────┘
│ - tools: search/get/  │
│   quote/list/(create) │
└───────────────────────┘
```

**Important:** Docker is for **Wiki.js + Postgres**. The MCP server is typically spawned directly by your MCP client (no Docker required for the MCP server unless you want it).

---

## Quick Start (sample data)

```powershell
git clone https://github.com/raydeStar/WikiMCP WikiMCP
cd WikiMCP
.\bootstrap-local.ps1 -OpenUi
```

- Wiki.js opens at: `http://localhost:3030`
- The stack includes sample content in `./wiki-content`

---

## Setup paths (choose your adventure)

### 1) Local with sample data (default)

```powershell
.\bootstrap-local.ps1 -OpenUi
```

Uses `./wiki-content` (characters, locations, chapters, etc.).

### 2) Local with empty wiki

```powershell
.\bootstrap-local.ps1 -ContentMode Empty -OpenUi
```

Creates `./wiki-content-empty` with just the `en/` locale folder (sample data stays untouched).

### 3) Local with custom content path

```powershell
.\bootstrap-local.ps1 -ContentMode Path -ContentPath "D:\my-wiki" -OpenUi
```

Points to any folder on your machine.

### 4) Reset everything (wipe DB, keep content)

```powershell
.\bootstrap-local.ps1 -Reset -OpenUi
```

Removes Docker volumes and rebuilds from scratch. Your content folder survives.

---

## Wiki.js first-run setup

After containers start:

1. Open `http://localhost:3030`
2. Complete the Wiki.js setup wizard (create admin account)
3. Go to **Administration → Storage → Local File System** (or Git)
4. Set the path to: `file:///wiki-storage`
5. Click **Apply** and **Import Everything**

Your markdown files will appear in the wiki.

---

## Connect an LLM / MCP client (the fun part)

WikiMCP communicates via **stdio** (stdin/stdout). Your MCP client spawns the server directly.

### 1) Build the MCP server

```powershell
npm install
npm run build
```

This produces `dist/index.js`.

### 2) Configure your MCP client

#### Cursor / Claude Desktop (example)

Add to your MCP config (example file: `mcp-config.example.json`):

```json
{
  "mcpServers": {
    "novel-wiki": {
      "command": "node",
      "args": ["dist/index.js"],
      "cwd": "C:/Users/YourName/WikiMCP",
      "env": {
        "WIKI_REPO_PATH": "C:/Users/YourName/WikiMCP/wiki-content",
        "WIKI_WRITE_ENABLED": "false",
        "MCP_AUTH_USERNAME": "",
        "MCP_AUTH_PASSWORD": ""
      }
    }
  }
}
```

Adjust paths for your system.

#### LM Studio (concept)

LM Studio can act as an MCP host as well. Add a server entry that spawns:

- `node dist/index.js` …and pass `WIKI_REPO_PATH` to point at your content directory.

---

## MCP vs REST/Swagger (1-minute version)

If you’re used to normal APIs, MCP can feel weird at first. Here’s the simple mapping:

- **REST/Swagger:** You design lots of URLs like `GET /pages/{id}` and document them in OpenAPI.
- **MCP:** You expose a **tool list** (functions) like `wiki.search`, `wiki.get_page`, `wiki.quote` with JSON schemas.

In other words:

- REST is **resource-oriented** (endpoints)
- MCP is **capability-oriented** (tools)

A typical REST call:

- `GET /api/wiki/pages/Tim`

A typical MCP call (conceptually):

- `call tool wiki.get_page({ path: "/characters/white-bunny" })`

The MCP client/host (LM Studio, Cursor, etc.) is the thing that:

1. discovers the tool list
2. decides when to call a tool
3. feeds tool results back into the model

---

## MCP Authentication (optional) (optional)

If `MCP_AUTH_USERNAME` and `MCP_AUTH_PASSWORD` are both set, every tool call must include:

```json
{
  "auth": {
    "username": "your-user",
    "password": "your-pass"
  },
  "query": "The Knights who say Ni"
}
```

Bootstrap helpers:

```powershell
.\bootstrap-local.ps1 -AuthFromDb
```

or:

```powershell
.\bootstrap-local.ps1 -McpAuthUsername "admin" -McpAuthPassword "secret"
```

---

## Write operations

`wiki.create_page` is **disabled by default**.

Enable it by either:

1. `.env`:

- set `WIKI_WRITE_ENABLED=true`
- ensure your wiki content mount is not read-only

or

2. bootstrap flag:

```powershell
.\bootstrap-local.ps1 -WriteEnabled
```

---

## Available MCP tools

| Tool                     | Description                                                      |
| ------------------------ | ---------------------------------------------------------------- |
| `wiki.search`            | Full-text search with optional filters (type, tags, path prefix) |
| `wiki.get_page`          | Retrieve full page content by path                               |
| `wiki.quote`             | Extract specific lines from a page (citations/receipts)          |
| `wiki.list`              | List pages, optionally filtered by type or tag                   |
| `wiki.reindex`           | Rebuild the search index                                         |
| `wiki.get_context_bundle`| Get everything about a topic: main page, related pages, summaries, citations |
| `wiki.create_page`       | Create a new page (requires `WIKI_WRITE_ENABLED=true`)           |

### wiki.get_context_bundle (the power tool)

This is the bridge between librarian and editor. Instead of orchestrating multiple calls, ask:

```json
{ "topic": "Kazalt", "maxPages": 5 }
```

Returns:

- **mainPage**: Full content of the best-match page
- **relatedPages**: Summaries of linked and related pages
- **citations**: Version info for every page (receipts)
- **totalPagesFound**: How many matches exist

The model can now say *"give me everything about X"* and get a ready-to-use context bundle.

---

## Environment variables

| Variable             | Description                          | Default                   |
| -------------------- | ------------------------------------ | ------------------------- |
| `WIKI_DB_NAME`       | Postgres database name               | `wikijs`                  |
| `WIKI_DB_USER`       | Postgres username                    | `wikijs`                  |
| `WIKI_DB_PASSWORD`   | Postgres password                    | *(required)*              |
| `WIKI_CONTENT_DIR`   | Content folder path (Docker/Wiki.js) | `./wiki-content`          |
| `WIKI_WRITE_ENABLED` | Enable `wiki.create_page`            | `false`                   |
| `MCP_AUTH_USERNAME`  | MCP auth username                    | *(empty)*                 |
| `MCP_AUTH_PASSWORD`  | MCP auth password                    | *(empty)*                 |
| `WIKI_REPO_PATH`     | Content path used by MCP server      | `/wiki`                   |
| `DB_PATH`            | SQLite index path                    | `/app/data/wiki-index.db` |

---

## Project structure

```text
WikiMCP/
├── src/
│   ├── index.ts        # MCP server entry point
│   ├── indexer.ts      # SQLite FTS indexer
│   └── config.ts       # Environment config
├── wiki-content/       # Sample markdown content
├── docker-compose.yml  # Local dev stack (Wiki.js + Postgres)
├── docker-compose.prod.yml  # Production overrides
├── bootstrap-local.ps1 # PowerShell setup script
├── Dockerfile          # Optional container for MCP server
└── .env.example        # Environment template
```

---

## Troubleshooting

### “password authentication failed”

Old Postgres volume credentials. Reset:

```powershell
.\bootstrap-local.ps1 -Reset
```

### “detected dubious ownership in repository”

Git safety check. The compose file configures `safe.directory`. Restart:

```powershell
docker compose restart wiki-js
```

### MCP server not connecting

- Ensure `npm run build` succeeded
- Ensure absolute paths in the MCP client config
- Ensure `WIKI_REPO_PATH` points to real content

---

## How this differs from a normal REST API (quick intuition)

WikiMCP is **not** a traditional HTTP API meant for humans or frontends.

- A REST API exposes *endpoints* (URLs) and HTTP verbs.
- An MCP server exposes *tools* (named capabilities with JSON schemas).

In practice:

- Your MCP client (LM Studio, Cursor, Claude Desktop) **spawns this server**.
- The server advertises its tools (e.g. `wiki.search`, `wiki.quote`).
- The LLM decides *which tool to call* and with what arguments.
- WikiMCP enforces validation, permissions, and returns structured results.

Think of it as **"controllers for an AI client"** rather than endpoints for a web app.

If you understand that one sentence, you understand MCP well enough to build useful things.

---

## When *not* to use WikiMCP

WikiMCP is intentionally simple. You probably *should not* use it if:

- You only want a normal REST API over your wiki
- You don’t need citations or exact quotes
- You don’t plan to use an LLM with tool-calling

WikiMCP shines when:

- You want an LLM to *prove where it got information*
- You’re experimenting with agents, RAG, or MCP
- You want a clean learning project that scales into something real

---

## License

This project is licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**.

WikiMCP intentionally mirrors the license of **Wiki.js**, which is also AGPL-3.0. This ensures:

- Clear legal alignment with the upstream project
- Transparency for anyone running modified versions as a service
- A shared expectation that improvements remain open

If you are unfamiliar with AGPL, the practical takeaway is simple:

> If you modify this project and make it available to users over a network, you must provide the source code of your modified version.

For personal use, learning, tinkering, and local deployments, AGPL imposes no additional burden.

See the `LICENSE` file for full terms.

---