wiki-viewer-mcp
v0.2.0
Published
MCP filesystem adapter for wiki-viewer agent API
Maintainers
Readme
wiki-viewer-mcp
MCP filesystem adapter for wiki-viewer.
Maps standard MCP filesystem tools onto the wiki-viewer agent HTTP API so Claude Code, Cursor, and Codex get native-feeling file tools against a remote wiki-viewer instance.
First-time setup (register)
Before connecting an agent, register it with your wiki-viewer instance. The human operator approves the request in the wiki-viewer AI Panel.
Using the built-in CLI (recommended):
# Once published to npm:
npx wiki-viewer-mcp register \
--url https://notes.example.com \
--id ai:myagent \
--name "My Agent" \
--scope-paths "**/*" \
--ops read,mutate,delete \
--timeout 300
# Or from a local build (after cd packages/wiki-viewer-mcp && npm run build):
node ./dist/index.js register \
--url http://localhost:3000 \
--id ai:myagent \
--name "My Agent"The CLI will:
- POST the registration to wiki-viewer and print the registration ID.
- Print
⏳ Waiting for approval. Open the wiki-viewer AI Panel and approve agent "ai:myagent". - Poll every 3 s until the human approves (or timeout).
- On approval, print your
WIKI_VIEWER_TOKENandWIKI_VIEWER_AGENT_ID, then print a ready-to-pastemcp.jsonsnippet.
✅ Approved!
Agent ID : ai:myagent
Token : wv_tok_…
Paste this into your mcp.json:
{
"servers": {
"wiki-viewer": {
"command": "npx",
"args": ["wiki-viewer-mcp"],
"env": {
"WIKI_VIEWER_URL": "https://notes.example.com",
"WIKI_VIEWER_TOKEN": "wv_tok_…",
"WIKI_VIEWER_AGENT_ID": "ai:myagent"
}
}
}
}CLI options:
| Flag | Required | Default | Description |
| --------------- | -------- | ------------- | --------------------------------------------------------- |
| --url | yes | — | Base URL of wiki-viewer, e.g. https://notes.example.com |
| --id | yes | — | Agent ID, must match ai:[a-z][a-z0-9-]{0,30} |
| --name | yes | — | Human-readable display name |
| --scope-paths | no | **/* | Comma-separated path globs the agent can access |
| --ops | no | read,mutate | Comma-separated: read, mutate, delete |
| --timeout | no | 300 | Seconds to wait for approval before giving up |
Installation
# Once published to npm:
npx wiki-viewer-mcp
# or install globally
npm i -g wiki-viewer-mcp
# From a local build:
cd packages/wiki-viewer-mcp
npm run build
node dist/index.js # start MCP serverConfiguration
Set three environment variables before starting the MCP server
(the register command prints them for you after approval):
| Var | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| WIKI_VIEWER_URL | Base URL of your wiki-viewer instance, e.g. https://notes.example.com |
| WIKI_VIEWER_TOKEN | Bearer token obtained via wiki-viewer-mcp register |
| WIKI_VIEWER_AGENT_ID | Your agent ID (e.g. ai:myagent), sent as X-Agent-Id on every request |
| WIKI_VIEWER_WORKSPACE | Optional. Workspace id, sent as X-Workspace on every request. Targets one root directory when the instance serves several. Omit for single-workspace instances (the server uses its default). |
Usage in Claude Code / Cursor / Codex
Add to your mcp.json (or equivalent):
{
"servers": {
"wiki-viewer": {
"command": "npx",
"args": ["wiki-viewer-mcp"],
"env": {
"WIKI_VIEWER_URL": "https://notes.example.com",
"WIKI_VIEWER_TOKEN": "<your-token>",
"WIKI_VIEWER_AGENT_ID": "<your-agent-id>"
}
}
}
}Available tools
| Tool | Maps to | Description |
| ---------------- | ---------------------------------- | ----------------------------------------------- |
| read_file | GET /api/agent/fs/file/<path> | Read file bytes; captures sha256 + collab state |
| write_file | PUT /api/agent/fs/file/<path> | Atomic whole-file write with If-Match |
| edit_file | read → str-replace → PUT | Client-side exact-string replacement |
| list_directory | GET /api/agent/fs/ls/<path> | Scope-filtered directory listing |
| search | POST /api/agent/fs/search | Server-side grep or glob |
| move_file | POST /api/agent/fs/move | Rename/move; sidecar handled by server |
| delete_file | DELETE /api/agent/fs/file/<path> | Delete; requires delete scope |
Working mode vs Collaborating mode (important)
wiki-viewer has two tiers for .md files:
- Tier 1 (raw fs) — fast, all file types, light audit. Use for code, config, non-prose, or whole-file rewrites.
- Tier 2 (collab) — block-ops + proof-spans, review/accept/revert by humans. Use for prose that a human is co-editing.
The shim enforces this automatically in three layers:
Layer 1 — discoverable (headers)
Every read_file response includes:
X-Collab-State: active | tracked | untracked | not-markdown
X-Collab-Revision: <n>
X-Collab-Snapshot: /api/agent/files/<path>.md| State | Meaning | You should |
| -------------- | ------------------------------------------------------------ | -------------------------------------- |
| active | Human has the doc open OR there are pending review artifacts | Use Tier-2 block-ops |
| tracked | Sidecar exists, no active review | Prefer Tier-2 for prose/semantic edits |
| untracked | Plain .md, no collaboration history | Raw ok |
| not-markdown | Not a .md file | Raw only |
Layer 2 — client-side guard
If the shim's last-known X-Collab-State for a .md is active, write_file and edit_file are blocked before any HTTP request is made. The tool returns a clear error with the Tier-2 snapshot URL.
Layer 3 — server-side enforcement (409)
Even if the cache is stale, the server re-checks collab state atomically inside the write mutex. A raw PUT to an active .md is rejected with 409 COLLAB_ACTIVE and the Tier-2 snapshot URL. The shim surfaces this as a clear error message.
Rule
Before editing a
.md, runread_fileand checkX-Collab-State.
Ifactive, use wiki-viewer block-ops (Tier 2).
For everything else, use raw fs tools.
If-Match concurrency
The shim caches the sha256 from every read_file response (ETag header). write_file, edit_file, and delete_file automatically send this as If-Match. If the file changed since your read, you get a 412 error with instructions to re-read.
edit_file always reads fresh before writing, so it's naturally atomic per-op.
Use force: true to bypass If-Match (audited by the server).
Scope
Your token's scope.paths (set during registration) governs what paths you can touch. Paths outside scope, and internal paths (.proof/, .locks/, the app db), are rejected by the server. Scope supports **, *, ? glob patterns.
The delete op is a separate scope permission from mutate — an agent can be granted "edit but never delete."
Development
cd packages/wiki-viewer-mcp
pnpm install
pnpm test # runs unit tests with tsx --test
pnpm build # compiles to dist/Tests use a mock fetch — no real wiki-viewer instance needed.
