Architecture

Last modified by Vincent Massol on 2026/09/04 19:19

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 routingDefaultMCPResource applies 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 the XWikiContext.
  • Lifecycle and middlewareXWikiMCPServerManager keeps one SDK server per wiki, built lazily and cached, registers only that wiki's enabled MCPTool components on it, and routes every call through executeWrapped(), 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_wikis is reach-gated, plus list_collections and search_collections contributed 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 SecureQuery and ContextualAuthorizationManager.
  • 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

  1. HTTP request arrives at DefaultMCPResource (/rest/wikis/{wiki}/aiLLM/mcp).
  2. Enable gate: disabled wiki returns 404 before anything else.
  3. Authentication has already happened (filter chain). Guest + OIDC → 401.
  4. Resource sets the target wiki on the XWikiContext and calls XWikiMCPServerManager.handleRequest().
  5. Manager resolves the wiki's cached SDK server (built lazily, one per wiki).
  6. SDK parses the JSON-RPC message and dispatches tools/call to the registered handler.
  7. Handler is the middleware (executeWrapped), which invokes the tool's execute() synchronously on the request thread.
  8. 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

  • XWikiMCPServerManager owns a ConcurrentHashMap of SDK servers, one per wiki.
  • buildServer(wikiId): reads config, enumerates MCPTool components, 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: MCPConfigChangeEventListener watches saves of AI.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.

Related

Get Connected