xwiki-mcp
# xwiki-mcp
A [Model Context Protocol](https://modelcontextprotocol.io) server for
[XWiki](https://www.xwiki.org). It gives an MCP-capable assistant read-only
access to the spaces, pages and attachments that one XWiki account can see.
## Why this exists
XWiki has announced an MCP server of its own, but at the time this was written
it had not been released. Until it is, there is no supported way to point an
assistant at an XWiki instance, which also leaves the knowledge module of every
[openDesk](https://www.opendesk.eu) deployment out of reach.
This server uses the documented
[XWiki REST API](https://www.xwiki.org/xwiki/bin/view/Documentation/UserGuide/Features/XWikiRESTfulAPI/),
which every instance exposes under `/rest`.
## Scope and safety
Every tool in this server is read-only. There is no code path that creates,
edits or deletes a page, and no tool that writes to disk or makes a request to
any host other than the configured instance.
The server authenticates as one XWiki account and therefore sees exactly what
that account sees. XWiki's own page and space rights remain the access
boundary; this server does not widen them.
Responses are size-capped before they reach the assistant. A single response
body is read up to a limit and then aborted, and long page content is truncated
with an explicit `[truncated]` marker rather than silently cut.
## Requirements
- Node.js 20 or newer
- An XWiki instance reachable from the machine running the server
- An XWiki account whose password works against `/rest`
### A note on single sign-on
XWiki instances behind an SSO-only setup often have HTTP Basic authentication
disabled on `/rest`. When that is the case, this server cannot authenticate,
and it says so explicitly rather than failing vaguely: an unauthenticated REST
call returns the login page with status 200, which the server reports as
`unauthorized`.
Before setting anything up, check from a shell:
```
curl -u 'username:password' 'https://wiki.example.org/xwiki/rest/wikis?media=json'
```
JSON means this server will work. HTML means Basic authentication is not
available and an administrator would have to enable it.
## Installation
```
git clone https://github.com/Nraitschew/xwiki-mcp.git
cd xwiki-mcp
npm install
npm run build
```
The build writes an executable entry point to `dist/index.js`.
## Configuration
The server is configured through environment variables. The host application
that starts the server passes them in.
| Variable | Required | Default | Meaning |
| --- | --- | --- | --- |
| `XWIKI_URL` | yes | | Instance URL, for example `https://wiki.example.org/xwiki`. The path prefix matters: most installations serve XWiki under `/xwiki`. `https` is added when the scheme is missing. |
| `XWIKI_USERNAME` | yes | | XWiki login name. |
| `XWIKI_PASSWORD` | yes | | The account's password. |
| `XWIKI_WIKI` | no | `xwiki` | Wiki name in the REST path. Only relevant on a multi-wiki farm; `list_wikis` reports the available names. |
| `XWIKI_TIMEOUT_MS` | no | `15000` | Per-request timeout in milliseconds. |
| `XWIKI_MAX_RESPONSE_BYTES` | no | `4194304` | Hard cap on a single response body. |
| `XWIKI_MAX_TEXT_CHARS` | no | `50000` | Cap on page content handed to the assistant. |
A missing or malformed variable makes the server exit with a message on stderr
that names the variable, rather than starting and failing on the first tool
call.
## Connecting a client
### Claude Desktop
Edit the MCP configuration file:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"xwiki": {
"command": "node",
"args": ["/absolute/path/to/xwiki-mcp/dist/index.js"],
"env": {
"XWIKI_URL": "https://wiki.example.org/xwiki",
"XWIKI_USERNAME": "your-login",
"XWIKI_PASSWORD": "your-password"
}
}
}
}
```
Restart Claude Desktop afterwards.
### Claude Code
```
claude mcp add xwiki \
--env XWIKI_URL=https://wiki.example.org/xwiki \
--env XWIKI_USERNAME=your-login \
--env XWIKI_PASSWORD=your-password \
-- node /absolute/path/to/xwiki-mcp/dist/index.js
```
### Any other MCP client
The server speaks MCP over stdio. Start it with `node dist/index.js` and the
three required environment variables set; any client that can spawn a stdio
server will work.
## Tools
| Tool | Purpose |
| --- | --- |
| `search_pages` | Full-text search across page names, titles and content. Returns the references to read next. |
| `get_page` | One page's content, with its version and syntax. |
| `list_spaces` | The spaces of the configured wiki, with the references to browse them. |
| `list_pages_in_space` | The pages directly inside one space. Nested spaces are not expanded. |
| `list_page_attachments` | The files attached to a page: name, size, MIME type. Contents are not downloaded. |
| `list_wikis` | The wikis this account can see, and which one is configured. Only relevant on a multi-wiki farm. |
Tool results are JSON.
## Page references
XWiki addresses a page as `Space.PageName`, and a nested space as
`A.B.PageName`. Two details are easy to get wrong, and this server handles both:
- A literal dot inside a name is escaped as `\.` in a reference. Splitting on
every dot would break exactly the pages whose names contain one, such as
release notes or dates. The parser here resolves the escapes.
- A reference may be fully qualified as `wiki:Space.Page`. The wiki part is a
separate REST path segment, not a dot-separated one.
A bare page name with no space is rejected rather than guessed at, because
guessing a space would silently read a different page. Always pass a reference
that `search_pages`, `list_spaces` or `list_pages_in_space` returned.
## Errors
A failing tool call returns a result marked as an error whose text starts with
a stable machine code:
| Code | Meaning |
| --- | --- |
| `unauthorized` | The credentials were rejected, or the instance does not allow Basic authentication on `/rest`. |
| `forbidden` | The account is authenticated but not permitted to read that page or space. |
| `not_found` | No such page, space or wiki. |
| `rate_limited` | The instance is rate limiting this client. |
| `unreachable` | The instance did not answer, or the request timed out. |
| `invalid_reference` | The page reference names no space. |
| `invalid_response` | The response was not the expected document. |
| `http_error` | Any other non-success status, with the status code in the message. |
## Testing against your instance
```
npx @modelcontextprotocol/inspector node dist/index.js
```
The MCP Inspector lists the tools and lets you call them by hand, which is the
fastest way to confirm the URL, credentials and wiki name are right.
## Development
```
npm install
npm run typecheck
npm test
npm run build
```
The unit tests cover the configuration parsing and the reference grammar, which
is the part most likely to break silently. They make no network requests, so
they run anywhere.
## Limitations
- Read-only by design. Creating or editing pages is not implemented.
- Attachment contents are listed but not downloaded.
- `get_page` returns the page source in its stored syntax (usually
`xwiki/2.1`), not rendered HTML or plain text.
- Objects, classes and comments attached to a page are not exposed.
- Search pages once with the requested limit rather than paging through a
large result set.
## Related
- [opendesk-mcp](https://github.com/Nraitschew/opendesk-mcp) connects a whole
openDesk instance, including this server's XWiki tools.
- [openproject-mcp](https://github.com/Nraitschew/openproject-mcp) does the
same for OpenProject.
## License
Apache License 2.0. See [LICENSE](LICENSE).
This project is not affiliated with or endorsed by the XWiki project or XWiki
SAS. "XWiki" is a trademark of its respective owner and is used here only to
describe what this software connects to.
TDQS
Scored across 6 tools
Each tool targets a distinct resource/action: full-text search, single page retrieval, space listing, in-space page listing, attachment listing, and wiki listing. Although list_spaces and list_wikis sound similar, their descriptions clearly separate spaces within a wiki from wiki instances on a farm. No two tools appear interchangeable.
Tool names follow a consistent verb_noun pattern: search_pages, get_page, list_spaces, list_pages_in_space, list_page_attachments, and list_wikis. All use lowercase snake_case and list_ for enumeration operations. Minor singular/plural variation is natural and does not create confusion.
Six tools is well-scoped for a wiki browsing/reading server. Each tool has a clear role in navigation or retrieval, with no redundancy. The count is not excessive for the feature set.
The server covers the core read/browse cycle: discover wikis, navigate spaces, search/list pages, fetch page content, and see attachments. The only notable gaps are that attachment contents cannot be fetched and there are no page lifecycle operations, but the exposed surface appears intentionally read-oriented. No critical dead end blocks typical wiki research.