Architecture
Last modified by gabrielc on 2026/07/13 16:51
Content
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)
├── application-ai-llm-mcp-server/ endpoint, manager, config reader,
│ access doors, 6 bundled tools,
│ tool support (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
HTTP (JSON-RPC over POST)
│
┌─────────────────────────────▼───────────────────────────────┐
│ DefaultMCPResource identity & routing layer │
│ /rest/wikis/{wiki}/aiLLM/mcp │
│ - per-wiki enable gate (disabled wiki → 404) │
│ - OAuth/OIDC discovery (RFC 9728) │
│ - rejects unauthenticated callers (when OIDC present) │
│ - sets the target wiki on the XWikiContext │
└─────────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────────▼───────────────────────────────┐
│ XWikiMCPServerManager lifecycle & middleware layer │
│ - one SDK server per wiki, built lazily, cached │
│ - registers only the wiki's enabled MCPTool components │
│ - executeWrapped(): per-call middleware (audit, │
│ exception normalization) │
└─────────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────────▼───────────────────────────────┐
│ MCPTool components capability layer │
│ man · query_documents · get_document · edit_document │
│ · write_document · list_wikis (reach-gated) │
│ (index module contributes list_collections / │
│ search_collections when installed) │
└─────────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────────▼───────────────────────────────┐
│ Access doors shared authorization layer │
│ MCPDocumentAccess · MCPWikiReach · MCPSpaceFilter │
│ · MCPDocumentSearch │
│ - reach gate → rights check → space filter, in that order │
│ - always as the authenticated user, via XWiki's normal │
│ 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.
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.