Architecture
Explanation
The MCP server is four thin layers riding existing XWiki infrastructure, plus an extension point for custom tools.
Module layout
application-ai-llm-mcp/
├── application-ai-llm-mcp-api/ MCPTool @Role (the extension point),
│ MCPToolSupport, the public access doors
├── application-ai-llm-mcp-server/ endpoint, manager, config reader,
│ access-door implementations, space
│ filter, 18 bundled tools, the shared
│ tool seams (internal)
└── application-ai-llm-mcp-ui/ admin UI + config pages (XAR)The server module has no dependency on the index/RAG stack. It is installable standalone. Bundled tools query XWiki's built-in Solr index.
Four-layer architecture
A tool call crosses four layers, each with one job. Every one of them is parameterized by the same per-wiki configuration document, and a save of that document is what makes a running server pick the change up.
What each layer is responsible for:
- Identity and routing —
DefaultMCPResourceapplies the per-wiki enable gate (a disabled wiki returns 404 before anything else), advertises the OAuth/OIDC discovery metadata (RFC 9728), rejects unauthenticated callers when an OIDC provider is present, and sets the target wiki on theXWikiContext. - Lifecycle and middleware —
XWikiMCPServerManagerkeeps one SDK server per wiki, built lazily and cached, registers only that wiki's enabledMCPToolcomponents on it, and routes every call throughexecuteWrapped(), which audits it and normalizes the exceptions it throws. - The capabilities — the tools themselves: 18 bundled ones in four categories (Help, Search and Navigation, Structured Data, Authoring), of which
list_wikisis reach-gated, pluslist_collectionsandsearch_collectionscontributed by the index module when it is installed. The full list is on MCP Tool API. - Shared authorization — the access doors, which every tool goes through instead of resolving a reference itself: the reach gate, then the rights check, then the space filter, in that order, always as the authenticated user and through XWiki's own rights model.
Design principles
Every hard problem is delegated to something XWiki already has:
- Authentication rides the existing filter chain (OIDC bridge).
- Authorization rides
SecureQueryandContextualAuthorizationManager. - Save attribution rides
com.xpn.xwiki.api.Document. - Extensibility rides the component manager.
- Configuration rides a per-wiki wiki document plus an event listener.
Request lifecycle
- HTTP request arrives at
DefaultMCPResource(/rest/wikis/{wiki}/aiLLM/mcp). - Enable gate: disabled wiki returns 404 before anything else.
- Authentication has already happened (filter chain). Guest + OIDC → 401.
- Resource sets the target wiki on the XWikiContext and calls
XWikiMCPServerManager.handleRequest(). - Manager resolves the wiki's cached SDK server (built lazily, one per wiki).
- SDK parses the JSON-RPC message and dispatches
tools/callto the registered handler. - Handler is the middleware (
executeWrapped), which invokes the tool'sexecute()synchronously on the request thread. - Result serialized back as HTTP response.
Threading
Tool handlers run inline on the HTTP request thread, where XWiki's thread-locals (current user, wiki) natively live. The SDK builder sets immediateExecution(true) to prevent offloading to Reactor worker threads.
Server lifecycle
XWikiMCPServerManagerowns aConcurrentHashMapof SDK servers, one per wiki.buildServer(wikiId): reads config, enumeratesMCPToolcomponents, filters by enabled tool ids, registers each on a fresh transport.- Registration is fault-isolated per tool: a throwing tool is skipped with a WARN.
- Invalidation is event-driven:
MCPConfigChangeEventListenerwatches saves ofAI.MCP.Code.MCPServerConfig. Main wiki saves invalidate all servers (cross-wiki reach may have changed); other wiki saves invalidate only that wiki.
Shared tool seams
Mechanics that several tools must implement identically live in exactly one place each, so the tools cannot drift apart on them: MCPSourceText in the api module (line-ending normalization, line numbering, the output budget), and in the server module's internal tool package MCPContentWindow (the range-read window grammar), MCPTranslationSupport (exact-match locale resolution), MCPWriteSupport (write rights, the [AI] version comment, the base_version conflict messages), MCPTextGuards (neutralizing echoed wiki-authored text), and MCPAttachmentSupport, MCPHistorySupport and MCPLinksSupport.
Farm administration
The main wiki's MCP admin section is scripted through MCPFarmScriptService ($services.mcp), which reads and applies the per-wiki enable and cross-wiki reach flags across the farm.
MCP SDK
Version 2.0.0 of io.modelcontextprotocol.sdk:mcp-core. The version is owned by the mcp-bom import in the root POM. Two SDK defaults are overridden:
immediateExecution(true)— tools run on the request thread, not Reactor workers.validateToolInputs(false)— the MCPToolSupport declarative parameter layer is the designed validation gate.